aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/00-INDEX6
-rw-r--r--Documentation/DMA-API.txt3
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/deviceiobook.tmpl2
-rw-r--r--Documentation/DocBook/kernel-api.tmpl18
-rw-r--r--Documentation/DocBook/kernel-hacking.tmpl4
-rw-r--r--Documentation/DocBook/mcabook.tmpl2
-rw-r--r--Documentation/DocBook/mtdnand.tmpl5
-rw-r--r--Documentation/DocBook/s390-drivers.tmpl149
-rw-r--r--Documentation/MSI-HOWTO.txt69
-rw-r--r--Documentation/feature-removal-schedule.txt14
-rw-r--r--Documentation/filesystems/00-INDEX4
-rw-r--r--Documentation/filesystems/locks.txt (renamed from Documentation/locks.txt)10
-rw-r--r--Documentation/filesystems/mandatory-locking.txt (renamed from Documentation/mandatory.txt)21
-rw-r--r--Documentation/filesystems/ntfs.txt4
-rw-r--r--Documentation/hwmon/coretemp2
-rw-r--r--Documentation/hwmon/dme173733
-rw-r--r--Documentation/hwmon/f71805f7
-rw-r--r--Documentation/hwmon/it873
-rw-r--r--Documentation/hwmon/lm7810
-rw-r--r--Documentation/hwmon/lm93126
-rw-r--r--Documentation/hwmon/sysfs-interface131
-rw-r--r--Documentation/hwmon/w83791d96
-rw-r--r--Documentation/i2c/busses/i2c-i8013
-rw-r--r--Documentation/i2c/chips/pcf85748
-rw-r--r--Documentation/i2c/dev-interface11
-rw-r--r--Documentation/i2c/i2c-stub18
-rw-r--r--Documentation/ja_JP/HOWTO84
-rw-r--r--Documentation/kernel-parameters.txt37
-rw-r--r--Documentation/kobject.txt22
-rw-r--r--Documentation/networking/bonding.txt33
-rw-r--r--Documentation/networking/proc_net_tcp.txt5
-rw-r--r--Documentation/s390/00-INDEX26
-rw-r--r--Documentation/s390/CommonIO51
-rw-r--r--Documentation/s390/cds.txt8
-rw-r--r--Documentation/sched-design-CFS.txt67
-rw-r--r--Documentation/scsi/00-INDEX34
-rw-r--r--Documentation/scsi/ChangeLog.arcmsr17
-rw-r--r--Documentation/scsi/aacraid.txt8
-rw-r--r--Documentation/scsi/advansys.txt243
-rw-r--r--Documentation/sparc/sbus_drivers.txt4
-rw-r--r--Documentation/usb/authorization.txt92
-rw-r--r--Documentation/usb/power-management.txt517
-rw-r--r--Documentation/usb/usb-serial.txt11
-rw-r--r--Documentation/usb/usbmon.txt9
-rw-r--r--MAINTAINERS46
-rw-r--r--arch/arm/mach-imx/cpufreq.c1
-rw-r--r--arch/arm/mach-omap1/board-h2.c45
-rw-r--r--arch/arm/mach-omap1/board-h3.c39
-rw-r--r--arch/arm/mach-omap1/board-osk.c64
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1110.c1
-rw-r--r--arch/arm/plat-omap/cpu-omap.c1
-rw-r--r--arch/blackfin/mach-bf533/cpu.c2
-rw-r--r--arch/blackfin/mach-bf537/boards/generic_board.c2
-rw-r--r--arch/blackfin/mach-bf537/boards/pnav10.c2
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c2
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c6
-rw-r--r--arch/i386/Kconfig26
-rw-r--r--arch/ia64/Kconfig10
-rw-r--r--arch/ia64/configs/sn2_defconfig443
-rw-r--r--arch/ia64/hp/common/Makefile1
-rw-r--r--arch/ia64/hp/common/aml_nfw.c236
-rw-r--r--arch/ia64/hp/sim/simscsi.c9
-rw-r--r--arch/ia64/kernel/cpufreq/acpi-cpufreq.c2
-rw-r--r--arch/ia64/kernel/crash.c13
-rw-r--r--arch/ia64/kernel/machine_kexec.c6
-rw-r--r--arch/ia64/kernel/mca.c88
-rw-r--r--arch/ia64/kernel/mca_drv.h2
-rw-r--r--arch/ia64/kernel/palinfo.c6
-rw-r--r--arch/ia64/kernel/perfmon.c7
-rw-r--r--arch/ia64/kernel/salinfo.c4
-rw-r--r--arch/ia64/kernel/topology.c12
-rw-r--r--arch/ia64/sn/kernel/tiocx.c3
-rw-r--r--arch/m68k/atari/atakeyb.c104
-rw-r--r--arch/mips/au1000/common/prom.c61
-rw-r--r--arch/mips/au1000/common/setup.c5
-rw-r--r--arch/mips/au1000/db1x00/init.c10
-rw-r--r--arch/mips/au1000/mtx-1/init.c6
-rw-r--r--arch/mips/au1000/pb1000/init.c10
-rw-r--r--arch/mips/au1000/pb1100/init.c10
-rw-r--r--arch/mips/au1000/pb1200/board_setup.c6
-rw-r--r--arch/mips/au1000/pb1200/init.c10
-rw-r--r--arch/mips/au1000/pb1500/init.c10
-rw-r--r--arch/mips/au1000/pb1550/init.c10
-rw-r--r--arch/mips/au1000/xxs1500/init.c10
-rw-r--r--arch/mips/kernel/smp.c6
-rw-r--r--arch/mips/mm/tlbex.c96
-rw-r--r--arch/powerpc/kernel/of_device.c37
-rw-r--r--arch/powerpc/kernel/vio.c16
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c14
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c11
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c2
-rw-r--r--arch/powerpc/platforms/pasemi/cpufreq.c2
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c1
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c1
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c10
-rw-r--r--arch/powerpc/sysdev/axonram.c4
-rw-r--r--arch/powerpc/sysdev/dcr.c4
-rw-r--r--arch/powerpc/sysdev/mpic.c4
-rw-r--r--arch/s390/appldata/appldata_base.c59
-rw-r--r--arch/s390/kernel/audit.c7
-rw-r--r--arch/s390/kernel/audit.h15
-rw-r--r--arch/s390/kernel/compat_audit.c1
-rw-r--r--arch/s390/kernel/cpcmd.c100
-rw-r--r--arch/s390/kernel/dis.c5
-rw-r--r--arch/s390/kernel/entry.S12
-rw-r--r--arch/s390/kernel/entry64.S9
-rw-r--r--arch/s390/kernel/ipl.c4
-rw-r--r--arch/s390/kernel/vmlinux.lds.S234
-rw-r--r--arch/s390/mm/fault.c2
-rw-r--r--arch/sh/Kconfig53
-rw-r--r--arch/sh/Kconfig.debug6
-rw-r--r--arch/sh/Makefile4
-rw-r--r--arch/sh/boards/hp6xx/hp6xx_apm.c9
-rw-r--r--arch/sh/boards/hp6xx/setup.c35
-rw-r--r--arch/sh/boards/magicpanelr2/Kconfig13
-rw-r--r--arch/sh/boards/magicpanelr2/Makefile5
-rw-r--r--arch/sh/boards/magicpanelr2/setup.c394
-rw-r--r--arch/sh/boards/mpc1211/setup.c2
-rw-r--r--arch/sh/boards/renesas/r7780rp/Makefile5
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7780mp.c61
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7780rp.c6
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7785rp.c46
-rw-r--r--arch/sh/boards/renesas/r7780rp/setup.c70
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/Kconfig19
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/irq.c179
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/setup.c95
-rw-r--r--arch/sh/boards/renesas/x3proto/Makefile1
-rw-r--r--arch/sh/boards/renesas/x3proto/ilsel.c151
-rw-r--r--arch/sh/boards/renesas/x3proto/setup.c136
-rw-r--r--arch/sh/boards/se/7206/io.c31
-rw-r--r--arch/sh/boards/se/7206/setup.c19
-rw-r--r--arch/sh/boards/se/7343/irq.c7
-rw-r--r--arch/sh/boards/se/7343/setup.c2
-rw-r--r--arch/sh/boards/se/770x/setup.c10
-rw-r--r--arch/sh/boards/se/7722/setup.c9
-rw-r--r--arch/sh/boards/se/7751/setup.c11
-rw-r--r--arch/sh/boards/se/7780/irq.c28
-rw-r--r--arch/sh/boards/se/7780/setup.c7
-rw-r--r--arch/sh/boards/sh03/setup.c28
-rw-r--r--arch/sh/boards/shmin/setup.c26
-rw-r--r--arch/sh/boards/snapgear/setup.c30
-rw-r--r--arch/sh/boards/titan/setup.c30
-rw-r--r--arch/sh/cchips/Kconfig13
-rw-r--r--arch/sh/cchips/hd6446x/hd64461.c13
-rw-r--r--arch/sh/cchips/hd6446x/hd64465/setup.c7
-rw-r--r--arch/sh/cchips/voyagergx/irq.c188
-rw-r--r--arch/sh/configs/dreamcast_defconfig155
-rw-r--r--arch/sh/configs/hp6xx_defconfig559
-rw-r--r--arch/sh/configs/magicpanelr2_defconfig925
-rw-r--r--arch/sh/configs/rts7751r2d1_defconfig (renamed from arch/sh/configs/rts7751r2d_defconfig)472
-rw-r--r--arch/sh/configs/rts7751r2dplus_defconfig1167
-rw-r--r--arch/sh/configs/se7206_defconfig223
-rw-r--r--arch/sh/configs/shx3_defconfig456
-rw-r--r--arch/sh/drivers/dma/Kconfig1
-rw-r--r--arch/sh/drivers/dma/dma-sh.c13
-rw-r--r--arch/sh/drivers/heartbeat.c70
-rw-r--r--arch/sh/drivers/pci/ops-rts7751r2d.c8
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c13
-rw-r--r--arch/sh/kernel/cpu/clock.c2
-rw-r--r--arch/sh/kernel/cpu/init.c27
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile4
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c562
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c86
-rw-r--r--arch/sh/kernel/cpu/sh2/probe.c19
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c93
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c18
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c217
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c48
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c172
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7708.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c145
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh770x.c224
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c200
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7720.c210
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c178
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c54
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c253
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile6
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7343.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c38
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7770.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c91
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c304
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c234
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c120
-rw-r--r--arch/sh/kernel/cpufreq.c4
-rw-r--r--arch/sh/kernel/early_printk.c49
-rw-r--r--arch/sh/kernel/entry-common.S2
-rw-r--r--arch/sh/kernel/head.S18
-rw-r--r--arch/sh/kernel/kgdb_stub.c53
-rw-r--r--arch/sh/kernel/process.c8
-rw-r--r--arch/sh/kernel/setup.c15
-rw-r--r--arch/sh/kernel/sh_ksyms.c18
-rw-r--r--arch/sh/kernel/signal.c10
-rw-r--r--arch/sh/kernel/smp.c307
-rw-r--r--arch/sh/kernel/syscalls.S18
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c3
-rw-r--r--arch/sh/kernel/traps.c5
-rw-r--r--arch/sh/kernel/vmlinux.lds.S10
-rw-r--r--arch/sh/mm/Kconfig67
-rw-r--r--arch/sh/mm/Makefile23
-rw-r--r--arch/sh/mm/cache-sh4.c81
-rw-r--r--arch/sh/mm/copy_page.S169
-rw-r--r--arch/sh/mm/fault-nommu.c64
-rw-r--r--arch/sh/mm/pmb.c2
-rw-r--r--arch/sh/mm/tlb-sh4.c55
-rw-r--r--arch/sh64/Kconfig51
-rw-r--r--arch/sh64/Kconfig.debug13
-rw-r--r--arch/sh64/Makefile6
-rw-r--r--arch/sh64/configs/cayman_defconfig258
-rw-r--r--arch/sh64/configs/harp_defconfig756
-rw-r--r--arch/sh64/configs/sim_defconfig566
-rw-r--r--arch/sh64/kernel/Makefile2
-rw-r--r--arch/sh64/kernel/alphanum.c1
-rw-r--r--arch/sh64/kernel/sh_ksyms.c32
-rw-r--r--arch/sh64/kernel/time.c14
-rw-r--r--arch/sh64/kernel/vmlinux.lds.S60
-rw-r--r--arch/sh64/lib/c-checksum.c3
-rw-r--r--arch/sh64/lib/io.c29
-rw-r--r--arch/sh64/lib/iomap.c10
-rw-r--r--arch/sh64/mach-cayman/setup.c10
-rw-r--r--arch/sh64/mach-harp/Makefile13
-rw-r--r--arch/sh64/mach-harp/setup.c25
-rw-r--r--arch/sh64/mach-romram/Makefile14
-rw-r--r--arch/sh64/mach-romram/setup.c141
-rw-r--r--arch/sh64/mach-sim/Makefile13
-rw-r--r--arch/sh64/mach-sim/setup.c53
-rw-r--r--arch/sh64/mm/Makefile4
-rw-r--r--arch/sh64/mm/consistent.c (renamed from arch/sh64/kernel/pci-dma.c)4
-rw-r--r--arch/sh64/mm/init.c4
-rw-r--r--arch/sh64/mm/ioremap.c7
-rw-r--r--arch/sparc/Kconfig.debug4
-rw-r--r--arch/sparc/kernel/irq.c12
-rw-r--r--arch/sparc/kernel/of_device.c5
-rw-r--r--arch/sparc/kernel/time.c4
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S165
-rw-r--r--arch/sparc64/defconfig38
-rw-r--r--arch/sparc64/kernel/Makefile1
-rw-r--r--arch/sparc64/kernel/auxio.c4
-rw-r--r--arch/sparc64/kernel/entry.S14
-rw-r--r--arch/sparc64/kernel/irq.c610
-rw-r--r--arch/sparc64/kernel/of_device.c5
-rw-r--r--arch/sparc64/kernel/pci.c60
-rw-r--r--arch/sparc64/kernel/pci_fire.c279
-rw-r--r--arch/sparc64/kernel/pci_impl.h32
-rw-r--r--arch/sparc64/kernel/pci_msi.c433
-rw-r--r--arch/sparc64/kernel/pci_psycho.c6
-rw-r--r--arch/sparc64/kernel/pci_schizo.c3
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c405
-rw-r--r--arch/sparc64/kernel/power.c4
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S22
-rw-r--r--arch/sparc64/kernel/sys_sparc.c15
-rw-r--r--arch/sparc64/kernel/time.c4
-rw-r--r--arch/sparc64/kernel/traps.c4
-rw-r--r--arch/sparc64/kernel/us2e_cpufreq.c1
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S211
-rw-r--r--arch/sparc64/lib/xor.S12
-rw-r--r--arch/sparc64/mm/init.c2
-rw-r--r--arch/um/Makefile6
-rw-r--r--arch/um/Makefile-i3868
-rw-r--r--arch/um/Makefile-x86_643
-rw-r--r--arch/um/scripts/Makefile.rules2
-rw-r--r--arch/um/sys-i386/Makefile6
-rw-r--r--arch/um/sys-x86_64/Makefile4
-rw-r--r--arch/x86/kernel/Makefile_326
-rw-r--r--arch/x86/kernel/Makefile_644
-rw-r--r--arch/x86/kernel/alternative.c1
-rw-r--r--arch/x86/kernel/apic_64.c372
-rw-r--r--arch/x86/kernel/bugs_64.c2
-rw-r--r--arch/x86/kernel/cpu/bugs.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/e_powersaver.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/elanfreq.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/gx-suspmod.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longhaul.c5
-rw-r--r--arch/x86/kernel/cpu/cpufreq/p4-clockmod.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k6.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k7.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c13
-rw-r--r--arch/x86/kernel/cpu/cpufreq/sc520_freq.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/speedstep-ich.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/speedstep-smi.c1
-rw-r--r--arch/x86/kernel/cpuid.c2
-rw-r--r--arch/x86/kernel/crash_dump_32.c2
-rw-r--r--arch/x86/kernel/crash_dump_64.c2
-rw-r--r--arch/x86/kernel/entry_32.S4
-rw-r--r--arch/x86/kernel/entry_64.S23
-rw-r--r--arch/x86/kernel/geode_32.c4
-rw-r--r--arch/x86/kernel/head64.c2
-rw-r--r--arch/x86/kernel/hpet.c (renamed from arch/x86/kernel/hpet_32.c)250
-rw-r--r--arch/x86/kernel/hpet_64.c493
-rw-r--r--arch/x86/kernel/i387_32.c2
-rw-r--r--arch/x86/kernel/i387_64.c2
-rw-r--r--arch/x86/kernel/i8237.c2
-rw-r--r--arch/x86/kernel/i8253.c (renamed from arch/x86/kernel/i8253_32.c)6
-rw-r--r--arch/x86/kernel/i8259_32.c1
-rw-r--r--arch/x86/kernel/i8259_64.c46
-rw-r--r--arch/x86/kernel/ioport_32.c2
-rw-r--r--arch/x86/kernel/ioport_64.c2
-rw-r--r--arch/x86/kernel/irq_32.c2
-rw-r--r--arch/x86/kernel/irq_64.c2
-rw-r--r--arch/x86/kernel/kprobes_32.c8
-rw-r--r--arch/x86/kernel/kprobes_64.c8
-rw-r--r--arch/x86/kernel/ldt_32.c2
-rw-r--r--arch/x86/kernel/ldt_64.c2
-rw-r--r--arch/x86/kernel/machine_kexec_32.c2
-rw-r--r--arch/x86/kernel/machine_kexec_64.c2
-rw-r--r--arch/x86/kernel/mca_32.c1
-rw-r--r--arch/x86/kernel/mfgpt_32.c362
-rw-r--r--arch/x86/kernel/msr.c2
-rw-r--r--arch/x86/kernel/nmi_32.c5
-rw-r--r--arch/x86/kernel/nmi_64.c4
-rw-r--r--arch/x86/kernel/pci-dma_32.c3
-rw-r--r--arch/x86/kernel/pci-dma_64.c1
-rw-r--r--arch/x86/kernel/process_32.c2
-rw-r--r--arch/x86/kernel/process_64.c6
-rw-r--r--arch/x86/kernel/ptrace_32.c1
-rw-r--r--arch/x86/kernel/ptrace_64.c1
-rw-r--r--arch/x86/kernel/quirks.c205
-rw-r--r--arch/x86/kernel/reboot_32.c4
-rw-r--r--arch/x86/kernel/reboot_fixups_32.c8
-rw-r--r--arch/x86/kernel/scx200_32.c12
-rw-r--r--arch/x86/kernel/setup_32.c2
-rw-r--r--arch/x86/kernel/setup_64.c39
-rw-r--r--arch/x86/kernel/signal_32.c2
-rw-r--r--arch/x86/kernel/signal_64.c2
-rw-r--r--arch/x86/kernel/smpboot_64.c11
-rw-r--r--arch/x86/kernel/stacktrace.c2
-rw-r--r--arch/x86/kernel/summit_32.c2
-rw-r--r--arch/x86/kernel/sys_i386_32.c2
-rw-r--r--arch/x86/kernel/sys_x86_64.c4
-rw-r--r--arch/x86/kernel/sysenter_32.c2
-rw-r--r--arch/x86/kernel/time_32.c5
-rw-r--r--arch/x86/kernel/time_64.c179
-rw-r--r--arch/x86/kernel/topology.c2
-rw-r--r--arch/x86/kernel/traps_32.c2
-rw-r--r--arch/x86/kernel/traps_64.c2
-rw-r--r--arch/x86/kernel/tsc_32.c6
-rw-r--r--arch/x86/kernel/tsc_64.c93
-rw-r--r--arch/x86/kernel/tsc_sync.c2
-rw-r--r--arch/x86/kernel/vm86_32.c2
-rw-r--r--arch/x86/kernel/vsyscall_64.c2
-rw-r--r--arch/x86/lib/copy_user_nocache_64.S1
-rw-r--r--arch/x86/lib/thunk_64.S4
-rw-r--r--arch/x86/pci/acpi.c194
-rw-r--r--arch/x86/pci/common.c19
-rw-r--r--arch/x86/pci/fixup.c47
-rw-r--r--arch/x86/pci/i386.c13
-rw-r--r--arch/x86/pci/irq.c39
-rw-r--r--arch/x86/pci/pci.h2
-rw-r--r--arch/x86_64/Kconfig19
-rw-r--r--block/Kconfig5
-rw-r--r--block/Makefile2
-rw-r--r--block/bsg.c5
-rw-r--r--block/elevator.c2
-rw-r--r--block/genhd.c35
-rw-r--r--block/ll_rw_blk.c2
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/processor_idle.c12
-rw-r--r--drivers/acpi/scan.c16
-rw-r--r--drivers/acpi/toshiba_acpi.c2
-rw-r--r--drivers/acpi/video.c4
-rw-r--r--drivers/amba/bus.c9
-rw-r--r--drivers/ata/Kconfig68
-rw-r--r--drivers/ata/Makefile9
-rw-r--r--drivers/ata/ahci.c451
-rw-r--r--drivers/ata/ata_generic.c16
-rw-r--r--drivers/ata/ata_piix.c108
-rw-r--r--drivers/ata/libata-acpi.c165
-rw-r--r--drivers/ata/libata-core.c1336
-rw-r--r--drivers/ata/libata-eh.c922
-rw-r--r--drivers/ata/libata-pmp.c1191
-rw-r--r--drivers/ata/libata-scsi.c497
-rw-r--r--drivers/ata/libata-sff.c69
-rw-r--r--drivers/ata/libata.h41
-rw-r--r--drivers/ata/pata_acpi.c395
-rw-r--r--drivers/ata/pata_ali.c17
-rw-r--r--drivers/ata/pata_amd.c43
-rw-r--r--drivers/ata/pata_artop.c20
-rw-r--r--drivers/ata/pata_at32.c441
-rw-r--r--drivers/ata/pata_atiixp.c15
-rw-r--r--drivers/ata/pata_bf54x.c1627
-rw-r--r--drivers/ata/pata_cmd640.c4
-rw-r--r--drivers/ata/pata_cmd64x.c43
-rw-r--r--drivers/ata/pata_cs5520.c47
-rw-r--r--drivers/ata/pata_cs5530.c4
-rw-r--r--drivers/ata/pata_cs5535.c4
-rw-r--r--drivers/ata/pata_cs5536.c344
-rw-r--r--drivers/ata/pata_cypress.c4
-rw-r--r--drivers/ata/pata_efar.c11
-rw-r--r--drivers/ata/pata_hpt366.c4
-rw-r--r--drivers/ata/pata_hpt37x.c28
-rw-r--r--drivers/ata/pata_hpt3x2n.c11
-rw-r--r--drivers/ata/pata_hpt3x3.c10
-rw-r--r--drivers/ata/pata_icside.c39
-rw-r--r--drivers/ata/pata_isapnp.c8
-rw-r--r--drivers/ata/pata_it8213.c11
-rw-r--r--drivers/ata/pata_it821x.c17
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c24
-rw-r--r--drivers/ata/pata_jmicron.c24
-rw-r--r--drivers/ata/pata_legacy.c27
-rw-r--r--drivers/ata/pata_marvell.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c10
-rw-r--r--drivers/ata/pata_mpiix.c25
-rw-r--r--drivers/ata/pata_netcell.c5
-rw-r--r--drivers/ata/pata_ns87410.c11
-rw-r--r--drivers/ata/pata_ns87415.c467
-rw-r--r--drivers/ata/pata_oldpiix.c11
-rw-r--r--drivers/ata/pata_opti.c11
-rw-r--r--drivers/ata/pata_optidma.c26
-rw-r--r--drivers/ata/pata_pcmcia.c18
-rw-r--r--drivers/ata/pata_pdc2027x.c114
-rw-r--r--drivers/ata/pata_pdc202xx_old.c23
-rw-r--r--drivers/ata/pata_platform.c16
-rw-r--r--drivers/ata/pata_qdi.c15
-rw-r--r--drivers/ata/pata_radisys.c4
-rw-r--r--drivers/ata/pata_rz1000.c13
-rw-r--r--drivers/ata/pata_sc1200.c4
-rw-r--r--drivers/ata/pata_scc.c66
-rw-r--r--drivers/ata/pata_serverworks.c8
-rw-r--r--drivers/ata/pata_sil680.c72
-rw-r--r--drivers/ata/pata_sis.c33
-rw-r--r--drivers/ata/pata_sl82c105.c11
-rw-r--r--drivers/ata/pata_triflex.c11
-rw-r--r--drivers/ata/pata_via.c16
-rw-r--r--drivers/ata/pata_winbond.c13
-rw-r--r--drivers/ata/pdc_adma.c103
-rw-r--r--drivers/ata/sata_inic162x.c34
-rw-r--r--drivers/ata/sata_mv.c68
-rw-r--r--drivers/ata/sata_nv.c904
-rw-r--r--drivers/ata/sata_promise.c27
-rw-r--r--drivers/ata/sata_qstor.c17
-rw-r--r--drivers/ata/sata_sil.c53
-rw-r--r--drivers/ata/sata_sil24.c341
-rw-r--r--drivers/ata/sata_sis.c2
-rw-r--r--drivers/ata/sata_svw.c14
-rw-r--r--drivers/ata/sata_sx4.c25
-rw-r--r--drivers/ata/sata_uli.c16
-rw-r--r--drivers/ata/sata_via.c37
-rw-r--r--drivers/ata/sata_vsc.c16
-rw-r--r--drivers/atm/ambassador.h2
-rw-r--r--drivers/atm/firestream.c2
-rw-r--r--drivers/atm/horizon.h2
-rw-r--r--drivers/base/Kconfig8
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c116
-rw-r--r--drivers/base/class.c60
-rw-r--r--drivers/base/core.c108
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/memory.c3
-rw-r--r--drivers/base/platform.c26
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/main.c344
-rw-r--r--drivers/base/power/power.h38
-rw-r--r--drivers/base/power/resume.c149
-rw-r--r--drivers/base/power/suspend.c210
-rw-r--r--drivers/base/sys.c73
-rw-r--r--drivers/block/Kconfig3
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/char/agp/agp.h7
-rw-r--r--drivers/char/agp/ali-agp.c27
-rw-r--r--drivers/char/agp/amd-k7-agp.c9
-rw-r--r--drivers/char/agp/backend.c12
-rw-r--r--drivers/char/agp/generic.c19
-rw-r--r--drivers/char/agp/i460-agp.c4
-rw-r--r--drivers/char/agp/intel-agp.c6
-rw-r--r--drivers/char/drm/drm.h20
-rw-r--r--drivers/char/drm/drmP.h237
-rw-r--r--drivers/char/drm/drm_agpsupport.c130
-rw-r--r--drivers/char/drm/drm_auth.c48
-rw-r--r--drivers/char/drm/drm_bufs.c203
-rw-r--r--drivers/char/drm/drm_context.c177
-rw-r--r--drivers/char/drm/drm_dma.c11
-rw-r--r--drivers/char/drm/drm_drawable.c67
-rw-r--r--drivers/char/drm/drm_drv.c186
-rw-r--r--drivers/char/drm/drm_fops.c34
-rw-r--r--drivers/char/drm/drm_ioc32.c2
-rw-r--r--drivers/char/drm/drm_ioctl.c196
-rw-r--r--drivers/char/drm/drm_irq.c98
-rw-r--r--drivers/char/drm/drm_lock.c75
-rw-r--r--drivers/char/drm/drm_os_linux.h10
-rw-r--r--drivers/char/drm/drm_pciids.h2
-rw-r--r--drivers/char/drm/drm_scatter.c48
-rw-r--r--drivers/char/drm/drm_vm.c4
-rw-r--r--drivers/char/drm/i810_dma.c312
-rw-r--r--drivers/char/drm/i810_drm.h5
-rw-r--r--drivers/char/drm/i810_drv.h9
-rw-r--r--drivers/char/drm/i830_dma.c210
-rw-r--r--drivers/char/drm/i830_drv.h15
-rw-r--r--drivers/char/drm/i830_irq.c30
-rw-r--r--drivers/char/drm/i915_dma.c214
-rw-r--r--drivers/char/drm/i915_drv.h36
-rw-r--r--drivers/char/drm/i915_irq.c128
-rw-r--r--drivers/char/drm/i915_mem.c125
-rw-r--r--drivers/char/drm/mga_dma.c140
-rw-r--r--drivers/char/drm/mga_drv.h21
-rw-r--r--drivers/char/drm/mga_state.c197
-rw-r--r--drivers/char/drm/mga_warp.c8
-rw-r--r--drivers/char/drm/r128_cce.c138
-rw-r--r--drivers/char/drm/r128_drm.h18
-rw-r--r--drivers/char/drm/r128_drv.h23
-rw-r--r--drivers/char/drm/r128_state.c351
-rw-r--r--drivers/char/drm/r300_cmdbuf.c68
-rw-r--r--drivers/char/drm/radeon_cp.c146
-rw-r--r--drivers/char/drm/radeon_drv.h43
-rw-r--r--drivers/char/drm/radeon_irq.c34
-rw-r--r--drivers/char/drm/radeon_mem.c108
-rw-r--r--drivers/char/drm/radeon_state.c683
-rw-r--r--drivers/char/drm/savage_bci.c145
-rw-r--r--drivers/char/drm/savage_drv.h9
-rw-r--r--drivers/char/drm/savage_state.c200
-rw-r--r--drivers/char/drm/sis_drv.c2
-rw-r--r--drivers/char/drm/sis_drv.h5
-rw-r--r--drivers/char/drm/sis_mm.c112
-rw-r--r--drivers/char/drm/via_dma.c144
-rw-r--r--drivers/char/drm/via_dmablit.c54
-rw-r--r--drivers/char/drm/via_drv.h22
-rw-r--r--drivers/char/drm/via_irq.c47
-rw-r--r--drivers/char/drm/via_map.c14
-rw-r--r--drivers/char/drm/via_mm.c83
-rw-r--r--drivers/char/drm/via_verifier.c8
-rw-r--r--drivers/char/drm/via_video.c20
-rw-r--r--drivers/char/dsp56k.c6
-rw-r--r--drivers/char/ec3104_keyb.c457
-rw-r--r--drivers/char/ip2/ip2main.c12
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c6
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c18
-rw-r--r--drivers/char/istallion.c8
-rw-r--r--drivers/char/lp.c5
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c5
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c5
-rw-r--r--drivers/char/pty.c9
-rw-r--r--drivers/char/raw.c5
-rw-r--r--drivers/char/rio/host.h2
-rw-r--r--drivers/char/riscom8.h2
-rw-r--r--drivers/char/snsc.c3
-rw-r--r--drivers/char/stallion.c7
-rw-r--r--drivers/char/sx.h4
-rw-r--r--drivers/char/synclink_gt.c8
-rw-r--r--drivers/char/tipar.c6
-rw-r--r--drivers/char/viotape.c10
-rw-r--r--drivers/char/watchdog/mpc5200_wdt.c2
-rw-r--r--drivers/cpufreq/Kconfig27
-rw-r--r--drivers/cpufreq/cpufreq.c36
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c19
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c22
-rw-r--r--drivers/cpufreq/cpufreq_stats.c18
-rw-r--r--drivers/edac/edac_mc_sysfs.c3
-rw-r--r--drivers/eisa/eisa-bus.c13
-rw-r--r--drivers/fc4/fc.c41
-rw-r--r--drivers/fc4/fcp_impl.h2
-rw-r--r--drivers/firewire/fw-cdev.c5
-rw-r--r--drivers/firewire/fw-device.c11
-rw-r--r--drivers/firmware/dmi-id.c62
-rw-r--r--drivers/firmware/edd.c4
-rw-r--r--drivers/firmware/efivars.c4
-rw-r--r--drivers/hid/Kconfig19
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-core.c16
-rw-r--r--drivers/hid/hid-debug.c40
-rw-r--r--drivers/hid/hid-input.c94
-rw-r--r--drivers/hid/hidraw.c407
-rw-r--r--drivers/hid/usbhid/Kconfig11
-rw-r--r--drivers/hid/usbhid/hid-core.c54
-rw-r--r--drivers/hid/usbhid/hid-ff.c5
-rw-r--r--drivers/hid/usbhid/hid-plff.c24
-rw-r--r--drivers/hid/usbhid/hid-quirks.c33
-rw-r--r--drivers/hid/usbhid/hid-tmff.c161
-rw-r--r--drivers/hid/usbhid/hiddev.c12
-rw-r--r--drivers/hwmon/Kconfig82
-rw-r--r--drivers/hwmon/Makefile5
-rw-r--r--drivers/hwmon/abituguru.c10
-rw-r--r--drivers/hwmon/abituguru3.c10
-rw-r--r--drivers/hwmon/ad7418.c12
-rw-r--r--drivers/hwmon/adm1021.c373
-rw-r--r--drivers/hwmon/adm1025.c12
-rw-r--r--drivers/hwmon/adm1026.c12
-rw-r--r--drivers/hwmon/adm1029.c10
-rw-r--r--drivers/hwmon/adm1031.c10
-rw-r--r--drivers/hwmon/adm9240.c10
-rw-r--r--drivers/hwmon/adt7470.c1050
-rw-r--r--drivers/hwmon/ams/ams-input.c76
-rw-r--r--drivers/hwmon/ams/ams.h5
-rw-r--r--drivers/hwmon/applesmc.c93
-rw-r--r--drivers/hwmon/asb100.c16
-rw-r--r--drivers/hwmon/atxp1.c10
-rw-r--r--drivers/hwmon/coretemp.c19
-rw-r--r--drivers/hwmon/dme1737.c954
-rw-r--r--drivers/hwmon/ds1621.c12
-rw-r--r--drivers/hwmon/f71805f.c15
-rw-r--r--drivers/hwmon/f71882fg.c950
-rw-r--r--drivers/hwmon/f75375s.c691
-rw-r--r--drivers/hwmon/fscher.c10
-rw-r--r--drivers/hwmon/fschmd.c778
-rw-r--r--drivers/hwmon/fscpos.c10
-rw-r--r--drivers/hwmon/gl518sm.c10
-rw-r--r--drivers/hwmon/gl520sm.c10
-rw-r--r--drivers/hwmon/hdaps.c55
-rw-r--r--drivers/hwmon/hwmon.c27
-rw-r--r--drivers/hwmon/ibmpex.c607
-rw-r--r--drivers/hwmon/it87.c66
-rw-r--r--drivers/hwmon/k8temp.c10
-rw-r--r--drivers/hwmon/lm63.c10
-rw-r--r--drivers/hwmon/lm70.c27
-rw-r--r--drivers/hwmon/lm75.c12
-rw-r--r--drivers/hwmon/lm75.h2
-rw-r--r--drivers/hwmon/lm77.c12
-rw-r--r--drivers/hwmon/lm78.c48
-rw-r--r--drivers/hwmon/lm80.c10
-rw-r--r--drivers/hwmon/lm83.c10
-rw-r--r--drivers/hwmon/lm85.c704
-rw-r--r--drivers/hwmon/lm87.c83
-rw-r--r--drivers/hwmon/lm90.c39
-rw-r--r--drivers/hwmon/lm92.c10
-rw-r--r--drivers/hwmon/lm93.c28
-rw-r--r--drivers/hwmon/max1619.c10
-rw-r--r--drivers/hwmon/max6650.c10
-rw-r--r--drivers/hwmon/pc87360.c12
-rw-r--r--drivers/hwmon/pc87427.c10
-rw-r--r--drivers/hwmon/sis5595.c21
-rw-r--r--drivers/hwmon/smsc47b397.c10
-rw-r--r--drivers/hwmon/smsc47m1.c14
-rw-r--r--drivers/hwmon/smsc47m192.c12
-rw-r--r--drivers/hwmon/thmc50.c68
-rw-r--r--drivers/hwmon/via686a.c10
-rw-r--r--drivers/hwmon/vt1211.c10
-rw-r--r--drivers/hwmon/vt8231.c12
-rw-r--r--drivers/hwmon/w83627ehf.c16
-rw-r--r--drivers/hwmon/w83627hf.c812
-rw-r--r--drivers/hwmon/w83781d.c206
-rw-r--r--drivers/hwmon/w83791d.c134
-rw-r--r--drivers/hwmon/w83792d.c59
-rw-r--r--drivers/hwmon/w83793.c10
-rw-r--r--drivers/hwmon/w83l785ts.c10
-rw-r--r--drivers/i2c/busses/Kconfig23
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-au1550.c11
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c16
-rw-r--r--drivers/i2c/busses/i2c-davinci.c586
-rw-r--r--drivers/i2c/busses/i2c-i801.c5
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c9
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c8
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c83
-rw-r--r--drivers/i2c/busses/i2c-stub.c79
-rw-r--r--drivers/i2c/chips/pcf8574.c14
-rw-r--r--drivers/i2c/chips/tps65010.c299
-rw-r--r--drivers/i2c/i2c-core.c58
-rw-r--r--drivers/i2c/i2c-dev.c20
-rw-r--r--drivers/ide/Kconfig16
-rw-r--r--drivers/ide/arm/icside.c45
-rw-r--r--drivers/ide/cris/ide-cris.c8
-rw-r--r--drivers/ide/ide-acpi.c1
-rw-r--r--drivers/ide/ide-dma.c28
-rw-r--r--drivers/ide/ide-io.c10
-rw-r--r--drivers/ide/ide-iops.c133
-rw-r--r--drivers/ide/ide-lib.c78
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide.c19
-rw-r--r--drivers/ide/legacy/ide_platform.c2
-rw-r--r--drivers/ide/mips/au1xxx-ide.c28
-rw-r--r--drivers/ide/pci/aec62xx.c12
-rw-r--r--drivers/ide/pci/alim15x3.c58
-rw-r--r--drivers/ide/pci/amd74xx.c26
-rw-r--r--drivers/ide/pci/atiixp.c33
-rw-r--r--drivers/ide/pci/cmd64x.c9
-rw-r--r--drivers/ide/pci/cs5520.c32
-rw-r--r--drivers/ide/pci/cs5530.c50
-rw-r--r--drivers/ide/pci/cs5535.c38
-rw-r--r--drivers/ide/pci/hpt34x.c9
-rw-r--r--drivers/ide/pci/hpt366.c18
-rw-r--r--drivers/ide/pci/it8213.c34
-rw-r--r--drivers/ide/pci/it821x.c90
-rw-r--r--drivers/ide/pci/jmicron.c15
-rw-r--r--drivers/ide/pci/pdc202xx_new.c24
-rw-r--r--drivers/ide/pci/pdc202xx_old.c9
-rw-r--r--drivers/ide/pci/piix.c46
-rw-r--r--drivers/ide/pci/sc1200.c54
-rw-r--r--drivers/ide/pci/scc_pata.c28
-rw-r--r--drivers/ide/pci/serverworks.c14
-rw-r--r--drivers/ide/pci/sgiioc4.c24
-rw-r--r--drivers/ide/pci/siimage.c29
-rw-r--r--drivers/ide/pci/sis5513.c16
-rw-r--r--drivers/ide/pci/sl82c105.c23
-rw-r--r--drivers/ide/pci/slc90e66.c18
-rw-r--r--drivers/ide/pci/tc86c001.c9
-rw-r--r--drivers/ide/pci/triflex.c10
-rw-r--r--drivers/ide/pci/via82cxxx.c29
-rw-r--r--drivers/ide/ppc/pmac.c323
-rw-r--r--drivers/ieee1394/nodemgr.c17
-rw-r--r--drivers/infiniband/core/sysfs.c9
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c29
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c3
-rw-r--r--drivers/infiniband/ulp/srp/Kconfig1
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c28
-rw-r--r--drivers/input/Kconfig22
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/evdev.c708
-rw-r--r--drivers/input/input-polldev.c7
-rw-r--r--drivers/input/input.c722
-rw-r--r--drivers/input/joydev.c743
-rw-r--r--drivers/input/joystick/xpad.c55
-rw-r--r--drivers/input/keyboard/Kconfig40
-rw-r--r--drivers/input/keyboard/Makefile5
-rw-r--r--drivers/input/keyboard/atakbd.c160
-rw-r--r--drivers/input/keyboard/bf54x-keys.c382
-rw-r--r--drivers/input/keyboard/gpio_keys.c81
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c277
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c185
-rw-r--r--drivers/input/keyboard/maple_keyb.c252
-rw-r--r--drivers/input/keyboard/omap-keypad.c22
-rw-r--r--drivers/input/misc/pcspkr.c3
-rw-r--r--drivers/input/mouse/alps.c2
-rw-r--r--drivers/input/mouse/appletouch.c15
-rw-r--r--drivers/input/mouse/atarimouse.c18
-rw-r--r--drivers/input/mouse/lifebook.c10
-rw-r--r--drivers/input/mouse/psmouse-base.c5
-rw-r--r--drivers/input/mousedev.c740
-rw-r--r--drivers/input/serio/i8042.c4
-rw-r--r--drivers/input/serio/serio.c11
-rw-r--r--drivers/input/touchscreen/Kconfig21
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ads7846.c4
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c182
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c3
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c93
-rw-r--r--drivers/input/tsdev.c533
-rw-r--r--drivers/isdn/hisax/avm_pci.c224
-rw-r--r--drivers/isdn/hisax/bkm_a8.c8
-rw-r--r--drivers/isdn/hisax/diva.c513
-rw-r--r--drivers/isdn/hisax/elsa.c494
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c3
-rw-r--r--drivers/isdn/hisax/hfc_usb.c63
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/hisax/hisax_if.h2
-rw-r--r--drivers/isdn/hisax/nj_s.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c276
-rw-r--r--drivers/isdn/hisax/telespci.c8
-rw-r--r--drivers/isdn/hisax/w6692.c7
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c274
-rw-r--r--drivers/isdn/i4l/isdn_net.c146
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c9
-rw-r--r--drivers/kvm/Kconfig1
-rw-r--r--drivers/kvm/Makefile2
-rw-r--r--drivers/kvm/i8259.c450
-rw-r--r--drivers/kvm/ioapic.c388
-rw-r--r--drivers/kvm/irq.c98
-rw-r--r--drivers/kvm/irq.h165
-rw-r--r--drivers/kvm/kvm.h211
-rw-r--r--drivers/kvm/kvm_main.c1488
-rw-r--r--drivers/kvm/kvm_svm.h3
-rw-r--r--drivers/kvm/lapic.c1064
-rw-r--r--drivers/kvm/mmu.c51
-rw-r--r--drivers/kvm/paging_tmpl.h84
-rw-r--r--drivers/kvm/svm.c1046
-rw-r--r--drivers/kvm/vmx.c1034
-rw-r--r--drivers/kvm/vmx.h73
-rw-r--r--drivers/kvm/x86_emulate.c411
-rw-r--r--drivers/kvm/x86_emulate.h20
-rw-r--r--drivers/macintosh/Kconfig1
-rw-r--r--drivers/macintosh/adbhid.c58
-rw-r--r--drivers/md/dm-emc.c2
-rw-r--r--drivers/md/md.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c5
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c7
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c7
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c10
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c6
-rw-r--r--drivers/media/video/ov511.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c7
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c4
-rw-r--r--drivers/media/video/pwc/pwc-if.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c7
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c6
-rw-r--r--drivers/media/video/videobuf-core.c2
-rw-r--r--drivers/media/video/videobuf-dma-sg.c2
-rw-r--r--drivers/media/video/videobuf-vmalloc.c2
-rw-r--r--drivers/media/video/w9968cf.c11
-rw-r--r--drivers/message/fusion/Kconfig26
-rw-r--r--drivers/message/fusion/lsi/mpi.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt2
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_lan.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_raid.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_sas.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_targ.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_tool.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_type.h2
-rw-r--r--drivers/message/fusion/mptbase.c602
-rw-r--r--drivers/message/fusion/mptbase.h80
-rw-r--r--drivers/message/fusion/mptctl.c364
-rw-r--r--drivers/message/fusion/mptctl.h4
-rw-r--r--drivers/message/fusion/mptfc.c149
-rw-r--r--drivers/message/fusion/mptlan.c32
-rw-r--r--drivers/message/fusion/mptlan.h8
-rw-r--r--drivers/message/fusion/mptsas.c468
-rw-r--r--drivers/message/fusion/mptsas.h158
-rw-r--r--drivers/message/fusion/mptscsih.c643
-rw-r--r--drivers/message/fusion/mptscsih.h4
-rw-r--r--drivers/message/fusion/mptspi.c211
-rw-r--r--drivers/misc/thinkpad_acpi.c18
-rw-r--r--drivers/misc/thinkpad_acpi.h2
-rw-r--r--drivers/misc/tifm_core.c9
-rw-r--r--drivers/mmc/core/bus.c21
-rw-r--r--drivers/mmc/core/host.c2
-rw-r--r--drivers/mmc/core/sdio_bus.c15
-rw-r--r--drivers/mmc/host/mmc_spi.c2
-rw-r--r--drivers/mtd/Kconfig8
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c38
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c2
-rw-r--r--drivers/mtd/chips/jedec_probe.c37
-rw-r--r--drivers/mtd/devices/Kconfig25
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/at91_dataflash26.c485
-rw-r--r--drivers/mtd/devices/docprobe.c4
-rw-r--r--drivers/mtd/devices/m25p80.c271
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c17
-rw-r--r--drivers/mtd/devices/pmc551.c27
-rw-r--r--drivers/mtd/inftlmount.c3
-rw-r--r--drivers/mtd/maps/Kconfig43
-rw-r--r--drivers/mtd/maps/Makefile6
-rw-r--r--drivers/mtd/maps/alchemy-flash.c14
-rw-r--r--drivers/mtd/maps/intel_vr_nor.c298
-rw-r--r--drivers/mtd/maps/lubbock-flash.c168
-rw-r--r--drivers/mtd/maps/mainstone-flash.c180
-rw-r--r--drivers/mtd/maps/nettel.c65
-rw-r--r--drivers/mtd/maps/ocelot.c175
-rw-r--r--drivers/mtd/maps/physmap_of.c1
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c22
-rw-r--r--drivers/mtd/maps/pmcmsp-ramroot.c1
-rw-r--r--drivers/mtd/maps/pq2fads.c88
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c200
-rw-r--r--drivers/mtd/maps/tqm834x.c286
-rw-r--r--drivers/mtd/mtd_blkdevs.c7
-rw-r--r--drivers/mtd/mtdchar.c3
-rw-r--r--drivers/mtd/mtdconcat.c3
-rw-r--r--drivers/mtd/mtdcore.c2
-rw-r--r--drivers/mtd/mtdcore.h11
-rw-r--r--drivers/mtd/mtdoops.c376
-rw-r--r--drivers/mtd/nand/Kconfig31
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/alauda.c742
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c788
-rw-r--r--drivers/mtd/nand/cafe_nand.c53
-rw-r--r--drivers/mtd/nand/diskonchip.c2
-rw-r--r--drivers/mtd/nand/excite_nandflash.c1
-rw-r--r--drivers/mtd/nand/nand_base.c9
-rw-r--r--drivers/mtd/nand/nand_ids.c1
-rw-r--r--drivers/mtd/nand/nandsim.c8
-rw-r--r--drivers/mtd/nand/ndfc.c8
-rw-r--r--drivers/mtd/nand/s3c2410.c4
-rw-r--r--drivers/mtd/onenand/Kconfig23
-rw-r--r--drivers/mtd/onenand/Makefile3
-rw-r--r--drivers/mtd/onenand/onenand_base.c694
-rw-r--r--drivers/mtd/onenand/onenand_sim.c495
-rw-r--r--drivers/mtd/rfd_ftl.c8
-rw-r--r--drivers/mtd/ubi/build.c28
-rw-r--r--drivers/mtd/ubi/debug.c37
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c131
-rw-r--r--drivers/mtd/ubi/io.c75
-rw-r--r--drivers/mtd/ubi/kapi.c9
-rw-r--r--drivers/mtd/ubi/scan.c62
-rw-r--r--drivers/mtd/ubi/scan.h8
-rw-r--r--drivers/mtd/ubi/ubi.h42
-rw-r--r--drivers/mtd/ubi/vmt.c70
-rw-r--r--drivers/mtd/ubi/vtbl.c8
-rw-r--r--drivers/mtd/ubi/wl.c136
-rw-r--r--drivers/net/Kconfig9
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/atarilance.c2
-rw-r--r--drivers/net/au1000_eth.c28
-rw-r--r--drivers/net/bnx2.c16
-rw-r--r--drivers/net/bonding/bond_main.c207
-rw-r--r--drivers/net/bonding/bond_sysfs.c74
-rw-r--r--drivers/net/bonding/bonding.h10
-rw-r--r--drivers/net/cassini.c2
-rw-r--r--drivers/net/cpmac.c1174
-rw-r--r--drivers/net/gianfar.c14
-rw-r--r--drivers/net/hamradio/6pack.c2
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c5
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.h5
-rw-r--r--drivers/net/ibm_newemac/core.c4
-rw-r--r--drivers/net/ibm_newemac/mal.c9
-rw-r--r--drivers/net/ibm_newemac/mal.h5
-rw-r--r--drivers/net/ibm_newemac/rgmii.c14
-rw-r--r--drivers/net/ibm_newemac/tah.c4
-rw-r--r--drivers/net/ibm_newemac/zmii.c4
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ipg.c34
-rw-r--r--drivers/net/ipg.h12
-rw-r--r--drivers/net/irda/donauboe.c2
-rw-r--r--drivers/net/jazzsonic.c1
-rw-r--r--drivers/net/loopback.c11
-rw-r--r--drivers/net/macmace.c6
-rw-r--r--drivers/net/macvlan.c1
-rw-r--r--drivers/net/mipsnet.c63
-rw-r--r--drivers/net/mipsnet.h83
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/mv643xx_eth.c2
-rw-r--r--drivers/net/mvme147.c1
-rw-r--r--drivers/net/myri10ge/myri10ge.c100
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h90
-rw-r--r--drivers/net/natsemi.c20
-rw-r--r--drivers/net/ne-h8300.c4
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/niu.c19
-rw-r--r--drivers/net/saa9730.c9
-rw-r--r--drivers/net/sky2.c116
-rw-r--r--drivers/net/sky2.h2
-rw-r--r--drivers/net/tc35815.c1
-rw-r--r--drivers/net/tehuti.c3
-rw-r--r--drivers/net/tg3.c43
-rw-r--r--drivers/net/tulip/de4x5.c4
-rw-r--r--drivers/net/tulip/de4x5.h2
-rw-r--r--drivers/net/tulip/tulip_core.c5
-rw-r--r--drivers/net/ucc_geth.c5
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/sdla.c8
-rw-r--r--drivers/net/wireless/b43/phy.c1
-rw-r--r--drivers/net/wireless/b43/pio.h1
-rw-r--r--drivers/net/wireless/b43/sysfs.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h2
-rw-r--r--drivers/net/wireless/ray_cs.h4
-rw-r--r--drivers/net/xen-netfront.c35
-rw-r--r--drivers/pci/hotplug.c28
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c2
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c74
-rw-r--r--drivers/pci/hotplug/ibmphp_hpc.c57
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c62
-rw-r--r--drivers/pci/hotplug/pciehp_core.c24
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c20
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c203
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c24
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c6
-rw-r--r--drivers/pci/msi.c2
-rw-r--r--drivers/pci/pci-driver.c6
-rw-r--r--drivers/pci/pci.c22
-rw-r--r--drivers/pci/pci.h9
-rw-r--r--drivers/pci/pcie/Kconfig9
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c9
-rw-r--r--drivers/pci/probe.c53
-rw-r--r--drivers/pci/proc.c7
-rw-r--r--drivers/pci/quirks.c43
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/pci/setup-irq.c2
-rw-r--r--drivers/pcmcia/cs.c10
-rw-r--r--drivers/pcmcia/ds.c26
-rw-r--r--drivers/pcmcia/i82365.c2
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c2
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c2
-rw-r--r--drivers/pcmcia/tcic.c2
-rw-r--r--drivers/power/power_supply.h3
-rw-r--r--drivers/power/power_supply_sysfs.c17
-rw-r--r--drivers/rtc/rtc-sh.c51
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/con3215.c3
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/sclp.c5
-rw-r--r--drivers/s390/char/tape_3590.c26
-rw-r--r--drivers/s390/char/tty3270.c9
-rw-r--r--drivers/s390/char/tty3270.h16
-rw-r--r--drivers/s390/char/vmwatchdog.c4
-rw-r--r--drivers/s390/char/zcore.c7
-rw-r--r--drivers/s390/cio/ccwgroup.c70
-rw-r--r--drivers/s390/cio/chp.c30
-rw-r--r--drivers/s390/cio/cio.c5
-rw-r--r--drivers/s390/cio/cmf.c232
-rw-r--r--drivers/s390/cio/css.c98
-rw-r--r--drivers/s390/cio/css.h3
-rw-r--r--drivers/s390/cio/device.c105
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c147
-rw-r--r--drivers/s390/cio/device_ops.c241
-rw-r--r--drivers/s390/cio/qdio.c39
-rw-r--r--drivers/s390/crypto/ap_bus.c19
-rw-r--r--drivers/s390/crypto/zcrypt_mono.c4
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c9
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.h45
-rw-r--r--drivers/s390/scsi/zfcp_aux.c13
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c18
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c10
-rw-r--r--drivers/s390/scsi/zfcp_def.h46
-rw-r--r--drivers/s390/scsi/zfcp_erp.c158
-rw-r--r--drivers/s390/scsi/zfcp_ext.h38
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c293
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h30
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c7
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c47
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_unit.c4
-rw-r--r--drivers/scsi/Kconfig48
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR5380.c31
-rw-r--r--drivers/scsi/NCR5380.h7
-rw-r--r--drivers/scsi/NCR53C9x.c2
-rw-r--r--drivers/scsi/NCR_D700.c5
-rw-r--r--drivers/scsi/a4000t.c7
-rw-r--r--drivers/scsi/aacraid/aachba.c8
-rw-r--r--drivers/scsi/aacraid/aacraid.h2
-rw-r--r--drivers/scsi/aacraid/commsup.c5
-rw-r--r--drivers/scsi/advansys.c19980
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/aic7xxx_old.c8
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h12
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c42
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h192
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c73
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c2258
-rw-r--r--drivers/scsi/atari_NCR5380.c27
-rw-r--r--drivers/scsi/bvme6000_scsi.c7
-rw-r--r--drivers/scsi/constants.c16
-rw-r--r--drivers/scsi/dc395x.c110
-rw-r--r--drivers/scsi/dpt_i2o.c29
-rw-r--r--drivers/scsi/dtc.c16
-rw-r--r--drivers/scsi/eata.c44
-rw-r--r--drivers/scsi/eata_pio.c100
-rw-r--r--drivers/scsi/esp_scsi.c10
-rw-r--r--drivers/scsi/fdomain.c5
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/gdth.c2937
-rw-r--r--drivers/scsi/gdth.h42
-rw-r--r--drivers/scsi/gdth_kcompat.h31
-rw-r--r--drivers/scsi/gdth_proc.c133
-rw-r--r--drivers/scsi/gdth_proc.h20
-rw-r--r--drivers/scsi/hosts.c1
-rw-r--r--drivers/scsi/hptiop.c63
-rw-r--r--drivers/scsi/hptiop.h229
-rw-r--r--drivers/scsi/ibmmca.c8
-rw-r--r--drivers/scsi/ibmvscsi/Makefile2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c81
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h32
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c61
-rw-r--r--drivers/scsi/ibmvscsi/iseries_vscsi.c37
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c113
-rw-r--r--drivers/scsi/ide-scsi.c140
-rw-r--r--drivers/scsi/imm.c4
-rw-r--r--drivers/scsi/in2000.c30
-rw-r--r--drivers/scsi/ipr.c19
-rw-r--r--drivers/scsi/ips.c9
-rw-r--r--drivers/scsi/ips.h11
-rw-r--r--drivers/scsi/libsas/sas_ata.c11
-rw-r--r--drivers/scsi/libsrp.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c2
-rw-r--r--drivers/scsi/megaraid.c3
-rw-r--r--drivers/scsi/mvme16x_scsi.c3
-rw-r--r--drivers/scsi/ncr53c8xx.c18
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/osst.c21
-rw-r--r--drivers/scsi/osst.h3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c159
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h8
-rw-r--r--drivers/scsi/pluto.c11
-rw-r--r--drivers/scsi/ps3rom.c24
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c200
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c1846
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h15
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c88
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c62
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c140
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c221
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qlogicfas.c2
-rw-r--r--drivers/scsi/qlogicpti.c171
-rw-r--r--drivers/scsi/qlogicpti.h3
-rw-r--r--drivers/scsi/scsi.c26
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_error.c162
-rw-r--r--drivers/scsi/scsi_lib.c123
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_scan.c48
-rw-r--r--drivers/scsi/scsi_sysfs.c189
-rw-r--r--drivers/scsi/scsi_tgt_if.c42
-rw-r--r--drivers/scsi/scsi_tgt_lib.c85
-rw-r--r--drivers/scsi/scsi_tgt_priv.h22
-rw-r--r--drivers/scsi/scsi_transport_fc.c35
-rw-r--r--drivers/scsi/scsi_transport_fc_internal.h26
-rw-r--r--drivers/scsi/scsi_transport_srp.c381
-rw-r--r--drivers/scsi/scsi_transport_srp_internal.h25
-rw-r--r--drivers/scsi/sd.c76
-rw-r--r--drivers/scsi/sg.c255
-rw-r--r--drivers/scsi/sr.c80
-rw-r--r--drivers/scsi/sun3_NCR5380.c22
-rw-r--r--drivers/scsi/tmscsim.c18
-rw-r--r--drivers/scsi/u14-34f.c44
-rw-r--r--drivers/scsi/wd33c93.c32
-rw-r--r--drivers/scsi/zorro7xx.c8
-rw-r--r--drivers/serial/mpc52xx_uart.c8
-rw-r--r--drivers/serial/sh-sci.c39
-rw-r--r--drivers/serial/sh-sci.h34
-rw-r--r--drivers/sh/Makefile4
-rw-r--r--drivers/sh/maple/Makefile3
-rw-r--r--drivers/sh/maple/maple.c735
-rw-r--r--drivers/spi/spi.c7
-rw-r--r--drivers/ssb/main.c11
-rw-r--r--drivers/ssb/pcmcia.c1
-rw-r--r--drivers/usb/Makefile22
-rw-r--r--drivers/usb/atm/cxacru.c43
-rw-r--r--drivers/usb/atm/speedtch.c5
-rw-r--r--drivers/usb/atm/ueagle-atm.c1384
-rw-r--r--drivers/usb/atm/xusbatm.c2
-rw-r--r--drivers/usb/class/usblp.c116
-rw-r--r--drivers/usb/core/config.c24
-rw-r--r--drivers/usb/core/devio.c83
-rw-r--r--drivers/usb/core/driver.c119
-rw-r--r--drivers/usb/core/endpoint.c1
-rw-r--r--drivers/usb/core/generic.c26
-rw-r--r--drivers/usb/core/hcd.c718
-rw-r--r--drivers/usb/core/hcd.h46
-rw-r--r--drivers/usb/core/hub.c276
-rw-r--r--drivers/usb/core/message.c78
-rw-r--r--drivers/usb/core/quirks.c81
-rw-r--r--drivers/usb/core/sysfs.c50
-rw-r--r--drivers/usb/core/urb.c106
-rw-r--r--drivers/usb/core/usb.c41
-rw-r--r--drivers/usb/core/usb.h5
-rw-r--r--drivers/usb/gadget/Kconfig26
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c9
-rw-r--r--drivers/usb/gadget/at91_udc.c2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2077
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h352
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c93
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/ether.c155
-rw-r--r--drivers/usb/gadget/file_storage.c249
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c13
-rw-r--r--drivers/usb/gadget/gmidi.c82
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/inode.c46
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/m66592-udc.c2
-rw-r--r--drivers/usb/gadget/net2280.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c12
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c2
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/serial.c174
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c239
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/ehci-au1xxx.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c22
-rw-r--r--drivers/usb/host/ehci-pci.c5
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c6
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c99
-rw-r--r--drivers/usb/host/ehci-sched.c47
-rw-r--r--drivers/usb/host/isp116x-hcd.c61
-rw-r--r--drivers/usb/host/ohci-dbg.c8
-rw-r--r--drivers/usb/host/ohci-hcd.c234
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-pci.c22
-rw-r--r--drivers/usb/host/ohci-ppc-of.c5
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c5
-rw-r--r--drivers/usb/host/ohci-q.c187
-rw-r--r--drivers/usb/host/ohci-ssb.c249
-rw-r--r--drivers/usb/host/ohci.h39
-rw-r--r--drivers/usb/host/r8a66597-hcd.c172
-rw-r--r--drivers/usb/host/sl811-hcd.c74
-rw-r--r--drivers/usb/host/u132-hcd.c370
-rw-r--r--drivers/usb/host/uhci-debug.c4
-rw-r--r--drivers/usb/host/uhci-hcd.h16
-rw-r--r--drivers/usb/host/uhci-q.c70
-rw-r--r--drivers/usb/image/microtek.c32
-rw-r--r--drivers/usb/misc/adutux.c3
-rw-r--r--drivers/usb/misc/berry_charge.c7
-rw-r--r--drivers/usb/misc/ftdi-elan.c8
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c200
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h130
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c60
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c354
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.h1315
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_struct.h144
-rw-r--r--drivers/usb/mon/mon_bin.c42
-rw-r--r--drivers/usb/mon/mon_main.c25
-rw-r--r--drivers/usb/mon/mon_text.c72
-rw-r--r--drivers/usb/mon/usb_mon.h2
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ark3116.c5
-rw-r--r--drivers/usb/serial/bus.c16
-rw-r--r--drivers/usb/serial/ch341.c354
-rw-r--r--drivers/usb/serial/cp2101.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c5
-rw-r--r--drivers/usb/serial/funsoft.c21
-rw-r--r--drivers/usb/serial/ipaq.c3
-rw-r--r--drivers/usb/serial/kl5kusb105.c28
-rw-r--r--drivers/usb/serial/kobil_sct.c144
-rw-r--r--drivers/usb/serial/mct_u232.c28
-rw-r--r--drivers/usb/serial/oti6858.c2
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h1
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c8
-rw-r--r--drivers/usb/serial/usb-serial.c42
-rw-r--r--drivers/usb/serial/visor.c64
-rw-r--r--drivers/usb/storage/initializers.c14
-rw-r--r--drivers/usb/storage/initializers.h3
-rw-r--r--drivers/usb/storage/shuttle_usbat.c3
-rw-r--r--drivers/usb/storage/transport.c46
-rw-r--r--drivers/usb/storage/unusual_devs.h34
-rw-r--r--drivers/usb/storage/usb.c4
-rw-r--r--drivers/usb/usb-skeleton.c1
-rw-r--r--drivers/video/backlight/hp680_bl.c4
-rw-r--r--drivers/video/cg6.c294
-rw-r--r--drivers/video/ffb.c161
-rw-r--r--drivers/video/output.c29
-rw-r--r--drivers/video/pvr2fb.c4
-rw-r--r--drivers/video/xilinxfb.c2
-rw-r--r--drivers/w1/w1.c19
-rw-r--r--fs/9p/vfs_file.c2
-rw-r--r--fs/Kconfig89
-rw-r--r--fs/afs/flock.c3
-rw-r--r--fs/debugfs/file.c36
-rw-r--r--fs/dlm/dlm_internal.h1
-rw-r--r--fs/dlm/lock.c142
-rw-r--r--fs/dlm/lock.h3
-rw-r--r--fs/dlm/lockspace.c3
-rw-r--r--fs/dlm/lowcomms.c23
-rw-r--r--fs/dlm/member.c41
-rw-r--r--fs/dlm/midcomms.c17
-rw-r--r--fs/dlm/rcom.c36
-rw-r--r--fs/dlm/rcom.h5
-rw-r--r--fs/dlm/recoverd.c11
-rw-r--r--fs/dlm/requestqueue.c58
-rw-r--r--fs/dlm/requestqueue.h4
-rw-r--r--fs/gfs2/bmap.c35
-rw-r--r--fs/gfs2/daemon.c24
-rw-r--r--fs/gfs2/daemon.h1
-rw-r--r--fs/gfs2/dir.c3
-rw-r--r--fs/gfs2/eaops.c8
-rw-r--r--fs/gfs2/eaops.h4
-rw-r--r--fs/gfs2/glock.c293
-rw-r--r--fs/gfs2/glock.h5
-rw-r--r--fs/gfs2/glops.c24
-rw-r--r--fs/gfs2/incore.h31
-rw-r--r--fs/gfs2/inode.c78
-rw-r--r--fs/gfs2/inode.h3
-rw-r--r--fs/gfs2/locking/dlm/lock_dlm.h1
-rw-r--r--fs/gfs2/locking/dlm/plock.c11
-rw-r--r--fs/gfs2/locking/dlm/sysfs.c2
-rw-r--r--fs/gfs2/locking/dlm/thread.c20
-rw-r--r--fs/gfs2/locking/nolock/main.c1
-rw-r--r--fs/gfs2/log.c230
-rw-r--r--fs/gfs2/log.h2
-rw-r--r--fs/gfs2/lops.c470
-rw-r--r--fs/gfs2/main.c3
-rw-r--r--fs/gfs2/meta_io.c136
-rw-r--r--fs/gfs2/meta_io.h6
-rw-r--r--fs/gfs2/mount.c5
-rw-r--r--fs/gfs2/ops_address.c146
-rw-r--r--fs/gfs2/ops_export.c2
-rw-r--r--fs/gfs2/ops_file.c17
-rw-r--r--fs/gfs2/ops_fstype.c40
-rw-r--r--fs/gfs2/ops_inode.c38
-rw-r--r--fs/gfs2/ops_super.c14
-rw-r--r--fs/gfs2/quota.c13
-rw-r--r--fs/gfs2/recovery.c2
-rw-r--r--fs/gfs2/rgrp.c39
-rw-r--r--fs/gfs2/super.c2
-rw-r--r--fs/gfs2/sys.c4
-rw-r--r--fs/gfs2/trans.c22
-rw-r--r--fs/gfs2/trans.h2
-rw-r--r--fs/inode.c24
-rw-r--r--fs/jbd/transaction.c9
-rw-r--r--fs/jffs2/Makefile1
-rw-r--r--fs/jffs2/acl.c23
-rw-r--r--fs/jffs2/acl.h4
-rw-r--r--fs/jffs2/background.c4
-rw-r--r--fs/jffs2/build.c10
-rw-r--r--fs/jffs2/compr.c422
-rw-r--r--fs/jffs2/compr.h54
-rw-r--r--fs/jffs2/compr_lzo.c108
-rw-r--r--fs/jffs2/compr_rtime.c2
-rw-r--r--fs/jffs2/compr_rubin.c4
-rw-r--r--fs/jffs2/compr_zlib.c6
-rw-r--r--fs/jffs2/dir.c37
-rw-r--r--fs/jffs2/erase.c57
-rw-r--r--fs/jffs2/fs.c32
-rw-r--r--fs/jffs2/gc.c23
-rw-r--r--fs/jffs2/jffs2_fs_sb.h5
-rw-r--r--fs/jffs2/nodelist.h2
-rw-r--r--fs/jffs2/nodemgmt.c25
-rw-r--r--fs/jffs2/os-linux.h5
-rw-r--r--fs/jffs2/readinode.c8
-rw-r--r--fs/jffs2/scan.c19
-rw-r--r--fs/jffs2/security.c6
-rw-r--r--fs/jffs2/summary.c30
-rw-r--r--fs/jffs2/summary.h6
-rw-r--r--fs/jffs2/wbuf.c81
-rw-r--r--fs/jffs2/write.c13
-rw-r--r--fs/jffs2/xattr.h2
-rw-r--r--fs/jffs2/xattr_user.c4
-rw-r--r--fs/jfs/jfs_dtree.c2
-rw-r--r--fs/jfs/jfs_incore.h2
-rw-r--r--fs/jfs/jfs_logmgr.c3
-rw-r--r--fs/jfs/jfs_logmgr.h2
-rw-r--r--fs/jfs/jfs_metapage.c3
-rw-r--r--fs/lockd/mon.c3
-rw-r--r--fs/lockd/xdr.c8
-rw-r--r--fs/lockd/xdr4.c8
-rw-r--r--fs/locks.c192
-rw-r--r--fs/nfs/Makefile1
-rw-r--r--fs/nfs/client.c49
-rw-r--r--fs/nfs/delegation.c6
-rw-r--r--fs/nfs/dir.c263
-rw-r--r--fs/nfs/direct.c8
-rw-r--r--fs/nfs/file.c108
-rw-r--r--fs/nfs/inode.c273
-rw-r--r--fs/nfs/internal.h50
-rw-r--r--fs/nfs/nfs2xdr.c20
-rw-r--r--fs/nfs/nfs3acl.c2
-rw-r--r--fs/nfs/nfs3proc.c17
-rw-r--r--fs/nfs/nfs3xdr.c25
-rw-r--r--fs/nfs/nfs4proc.c85
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/nfs4xdr.c72
-rw-r--r--fs/nfs/nfsroot.c3
-rw-r--r--fs/nfs/proc.c5
-rw-r--r--fs/nfs/read.c9
-rw-r--r--fs/nfs/super.c393
-rw-r--r--fs/nfs/unlink.c3
-rw-r--r--fs/nfs/write.c199
-rw-r--r--fs/nfsd/nfs3xdr.c59
-rw-r--r--fs/nfsd/nfs4callback.c89
-rw-r--r--fs/nfsd/nfs4idmap.c8
-rw-r--r--fs/nfsd/nfs4proc.c4
-rw-r--r--fs/nfsd/nfs4state.c202
-rw-r--r--fs/nfsd/nfs4xdr.c38
-rw-r--r--fs/nfsd/nfsctl.c7
-rw-r--r--fs/nfsd/nfssvc.c8
-rw-r--r--fs/nfsd/nfsxdr.c4
-rw-r--r--fs/nfsd/vfs.c56
-rw-r--r--fs/ntfs/ChangeLog12
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/aops.c22
-rw-r--r--fs/ntfs/attrib.c8
-rw-r--r--fs/ntfs/file.c36
-rw-r--r--fs/ntfs/inode.c3
-rw-r--r--fs/ntfs/logfile.c143
-rw-r--r--fs/ntfs/runlist.c4
-rw-r--r--fs/ocfs2/alloc.c482
-rw-r--r--fs/ocfs2/alloc.h7
-rw-r--r--fs/ocfs2/aops.c309
-rw-r--r--fs/ocfs2/aops.h6
-rw-r--r--fs/ocfs2/cluster/heartbeat.c3
-rw-r--r--fs/ocfs2/cluster/masklog.c3
-rw-r--r--fs/ocfs2/dir.c1423
-rw-r--r--fs/ocfs2/dir.h48
-rw-r--r--fs/ocfs2/dlmglue.c2
-rw-r--r--fs/ocfs2/dlmglue.h4
-rw-r--r--fs/ocfs2/export.c8
-rw-r--r--fs/ocfs2/extent_map.c6
-rw-r--r--fs/ocfs2/file.c298
-rw-r--r--fs/ocfs2/file.h2
-rw-r--r--fs/ocfs2/inode.c7
-rw-r--r--fs/ocfs2/inode.h1
-rw-r--r--fs/ocfs2/journal.c120
-rw-r--r--fs/ocfs2/journal.h3
-rw-r--r--fs/ocfs2/namei.c552
-rw-r--r--fs/ocfs2/namei.h19
-rw-r--r--fs/ocfs2/ocfs2.h7
-rw-r--r--fs/ocfs2/ocfs2_fs.h64
-rw-r--r--fs/ocfs2/super.c62
-rw-r--r--fs/ocfs2/sysfile.c10
-rw-r--r--fs/partitions/check.c12
-rw-r--r--fs/partitions/sun.c4
-rw-r--r--fs/pipe.c9
-rw-r--r--fs/proc/array.c17
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/proc_misc.c34
-rw-r--r--fs/read_write.c2
-rw-r--r--fs/smbfs/smbiod.c2
-rw-r--r--fs/sysfs/bin.c36
-rw-r--r--fs/sysfs/dir.c754
-rw-r--r--fs/sysfs/file.c248
-rw-r--r--fs/sysfs/group.c2
-rw-r--r--fs/sysfs/inode.c103
-rw-r--r--fs/sysfs/mount.c26
-rw-r--r--fs/sysfs/symlink.c34
-rw-r--r--fs/sysfs/sysfs.h184
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c3
-rw-r--r--include/asm-arm/arch-davinci/i2c.h21
-rw-r--r--include/asm-arm/io.h8
-rw-r--r--include/asm-blackfin/mach-bf548/bf54x_keys.h17
-rw-r--r--include/asm-blackfin/mach-bf548/dma.h1
-rw-r--r--include/asm-blackfin/nand.h47
-rw-r--r--include/asm-frv/system.h5
-rw-r--r--include/asm-generic/libata-portmap.h5
-rw-r--r--include/asm-generic/vmlinux.lds.h3
-rw-r--r--include/asm-ia64/dma-mapping.h1
-rw-r--r--include/asm-ia64/mca.h2
-rw-r--r--include/asm-ia64/sal.h15
-rw-r--r--include/asm-m68k/Kbuild1
-rw-r--r--include/asm-m68k/unistd.h3
-rw-r--r--include/asm-mips/fw/cfe/cfe_api.h2
-rw-r--r--include/asm-mips/mach-au1x00/prom.h13
-rw-r--r--include/asm-powerpc/dcr-mmio.h6
-rw-r--r--include/asm-powerpc/dcr-native.h6
-rw-r--r--include/asm-powerpc/io.h4
-rw-r--r--include/asm-powerpc/of_device.h2
-rw-r--r--include/asm-s390/cache.h2
-rw-r--r--include/asm-s390/ccwdev.h77
-rw-r--r--include/asm-s390/ccwgroup.h32
-rw-r--r--include/asm-s390/cio.h288
-rw-r--r--include/asm-s390/cmb.h73
-rw-r--r--include/asm-s390/page.h3
-rw-r--r--include/asm-s390/pgtable.h13
-rw-r--r--include/asm-s390/s390_ext.h8
-rw-r--r--include/asm-s390/system.h24
-rw-r--r--include/asm-s390/zcrypt.h4
-rw-r--r--include/asm-sh/cacheflush.h33
-rw-r--r--include/asm-sh/cpu-sh3/cache.h4
-rw-r--r--include/asm-sh/cpu-sh3/dma.h13
-rw-r--r--include/asm-sh/cpu-sh3/gpio.h66
-rw-r--r--include/asm-sh/cpu-sh3/mmu_context.h9
-rw-r--r--include/asm-sh/cpu-sh3/timer.h9
-rw-r--r--include/asm-sh/cpu-sh3/ubc.h3
-rw-r--r--include/asm-sh/cpu-sh4/dma.h2
-rw-r--r--include/asm-sh/cpu-sh4/mmu_context.h14
-rw-r--r--include/asm-sh/dma.h5
-rw-r--r--include/asm-sh/dreamcast/maple.h37
-rw-r--r--include/asm-sh/gpio.h19
-rw-r--r--include/asm-sh/hd64461.h1
-rw-r--r--include/asm-sh/heartbeat.h17
-rw-r--r--include/asm-sh/hw_irq.h53
-rw-r--r--include/asm-sh/ilsel.h45
-rw-r--r--include/asm-sh/io.h26
-rw-r--r--include/asm-sh/kgdb.h24
-rw-r--r--include/asm-sh/magicpanelr2.h67
-rw-r--r--include/asm-sh/page.h10
-rw-r--r--include/asm-sh/pgtable.h115
-rw-r--r--include/asm-sh/processor.h11
-rw-r--r--include/asm-sh/r7780rp.h33
-rw-r--r--include/asm-sh/rtc.h6
-rw-r--r--include/asm-sh/rts7751r2d.h65
-rw-r--r--include/asm-sh/sections.h1
-rw-r--r--include/asm-sh/sh03/io.h9
-rw-r--r--include/asm-sh/smp.h34
-rw-r--r--include/asm-sh/snapgear.h12
-rw-r--r--include/asm-sh/spinlock.h181
-rw-r--r--include/asm-sh/spinlock_types.h11
-rw-r--r--include/asm-sh/system.h1
-rw-r--r--include/asm-sh/voyagergx.h39
-rw-r--r--include/asm-sh64/gpio.h8
-rw-r--r--include/asm-sh64/io.h7
-rw-r--r--include/asm-sparc/irqflags.h39
-rw-r--r--include/asm-sparc/system.h22
-rw-r--r--include/asm-sparc64/cpudata.h21
-rw-r--r--include/asm-sparc64/irq.h13
-rw-r--r--include/asm-x86/8253pit.h5
-rw-r--r--include/asm-x86/8253pit_32.h12
-rw-r--r--include/asm-x86/8253pit_64.h10
-rw-r--r--include/asm-x86/apic_64.h8
-rw-r--r--include/asm-x86/cpufeature_64.h2
-rw-r--r--include/asm-x86/geode.h50
-rw-r--r--include/asm-x86/hardirq_32.h1
-rw-r--r--include/asm-x86/hpet.h96
-rw-r--r--include/asm-x86/hpet_32.h90
-rw-r--r--include/asm-x86/hpet_64.h18
-rw-r--r--include/asm-x86/i8253.h20
-rw-r--r--include/asm-x86/i8253_32.h17
-rw-r--r--include/asm-x86/i8253_64.h6
-rw-r--r--include/asm-x86/io_apic_32.h16
-rw-r--r--include/asm-x86/irqflags_32.h13
-rw-r--r--include/asm-x86/irqflags_64.h14
-rw-r--r--include/asm-x86/pci.h90
-rw-r--r--include/asm-x86/pci_32.h58
-rw-r--r--include/asm-x86/pci_64.h56
-rw-r--r--include/asm-x86/pda.h1
-rw-r--r--include/asm-x86/processor-flags.h2
-rw-r--r--include/asm-x86/proto.h7
-rw-r--r--include/asm-x86/system_32.h19
-rw-r--r--include/asm-x86/system_64.h10
-rw-r--r--include/asm-x86/timex.h19
-rw-r--r--include/asm-x86/timex_32.h22
-rw-r--r--include/asm-x86/timex_64.h31
-rw-r--r--include/asm-x86/tsc.h15
-rw-r--r--include/asm-x86/vsyscall.h3
-rw-r--r--include/linux/agpgart.h2
-rw-r--r--include/linux/ata.h116
-rw-r--r--include/linux/blkdev.h14
-rw-r--r--include/linux/blktrace_api.h7
-rw-r--r--include/linux/clockchips.h10
-rw-r--r--include/linux/cpufreq.h39
-rw-r--r--include/linux/debugfs.h27
-rw-r--r--include/linux/device.h17
-rw-r--r--include/linux/fs.h28
-rw-r--r--include/linux/gfs2_ondisk.h30
-rw-r--r--include/linux/gpio_keys.h1
-rw-r--r--include/linux/hdlcdrv.h2
-rw-r--r--include/linux/hid.h27
-rw-r--r--include/linux/hidraw.h86
-rw-r--r--include/linux/hwmon.h4
-rw-r--r--include/linux/i2c-dev.h31
-rw-r--r--include/linux/i2c.h102
-rw-r--r--include/linux/ide.h35
-rw-r--r--include/linux/if_bridge.h2
-rw-r--r--include/linux/inet_lro.h8
-rw-r--r--include/linux/input.h118
-rw-r--r--include/linux/isdn.h1
-rw-r--r--include/linux/jbd.h5
-rw-r--r--include/linux/jffs2.h1
-rw-r--r--include/linux/jiffies.h10
-rw-r--r--include/linux/kernel.h14
-rw-r--r--include/linux/kernel_stat.h1
-rw-r--r--include/linux/keyboard.h4
-rw-r--r--include/linux/kobject.h125
-rw-r--r--include/linux/kvm.h128
-rw-r--r--include/linux/libata.h320
-rw-r--r--include/linux/lockdep.h9
-rw-r--r--include/linux/maple.h80
-rw-r--r--include/linux/mod_devicetable.h5
-rw-r--r--include/linux/mtd/cfi.h9
-rw-r--r--include/linux/mtd/flashchip.h1
-rw-r--r--include/linux/mtd/map.h10
-rw-r--r--include/linux/mtd/mtd.h7
-rw-r--r--include/linux/mtd/nand.h1
-rw-r--r--include/linux/mtd/onenand.h12
-rw-r--r--include/linux/mtd/onenand_regs.h4
-rw-r--r--include/linux/mutex.h9
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--include/linux/netfilter.h26
-rw-r--r--include/linux/netfilter/nf_conntrack_amanda.h2
-rw-r--r--include/linux/netfilter/nf_conntrack_ftp.h2
-rw-r--r--include/linux/netfilter/nf_conntrack_h323.h18
-rw-r--r--include/linux/netfilter/nf_conntrack_irc.h2
-rw-r--r--include/linux/netfilter/nf_conntrack_pptp.h4
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h4
-rw-r--r--include/linux/netfilter/nf_conntrack_tftp.h2
-rw-r--r--include/linux/netfilter/x_tables.h2
-rw-r--r--include/linux/netfilter_arp/arp_tables.h2
-rw-r--r--include/linux/netfilter_bridge/ebtables.h4
-rw-r--r--include/linux/netfilter_ipv4.h4
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h2
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h2
-rw-r--r--include/linux/nfs_fs.h78
-rw-r--r--include/linux/nfs_page.h1
-rw-r--r--include/linux/nfs_xdr.h6
-rw-r--r--include/linux/nfsd/nfsd.h18
-rw-r--r--include/linux/nfsd/nfsfh.h42
-rw-r--r--include/linux/nfsd/xdr4.h4
-rw-r--r--include/linux/pci.h7
-rw-r--r--include/linux/pci_ids.h9
-rw-r--r--include/linux/pci_regs.h8
-rw-r--r--include/linux/platform_device.h7
-rw-r--r--include/linux/rcupdate.h14
-rw-r--r--include/linux/reiserfs_fs_sb.h4
-rw-r--r--include/linux/sched.h99
-rw-r--r--include/linux/scx200_gpio.h8
-rw-r--r--include/linux/skbuff.h6
-rw-r--r--include/linux/stallion.h2
-rw-r--r--include/linux/sunrpc/cache.h10
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--include/linux/sunrpc/debug.h5
-rw-r--r--include/linux/sunrpc/msg_prot.h13
-rw-r--r--include/linux/sunrpc/rpc_rdma.h116
-rw-r--r--include/linux/sunrpc/xdr.h5
-rw-r--r--include/linux/sunrpc/xprt.h42
-rw-r--r--include/linux/sunrpc/xprtrdma.h85
-rw-r--r--include/linux/sunrpc/xprtsock.h51
-rw-r--r--include/linux/sysfs.h147
-rw-r--r--include/linux/tcp.h2
-rw-r--r--include/linux/topology.h5
-rw-r--r--include/linux/tty.h1
-rw-r--r--include/linux/usb.h79
-rw-r--r--include/linux/usb/gadget.h (renamed from include/linux/usb_gadget.h)97
-rw-r--r--include/linux/usb/quirks.h7
-rw-r--r--include/linux/usb/serial.h20
-rw-r--r--include/linux/usb_sl811.h26
-rw-r--r--include/linux/video_output.h4
-rw-r--r--include/linux/writeback.h2
-rw-r--r--include/media/videobuf-core.h2
-rw-r--r--include/net/inet_frag.h60
-rw-r--r--include/net/ip.h13
-rw-r--r--include/net/ip_vs.h13
-rw-r--r--include/net/ipv6.h21
-rw-r--r--include/net/netfilter/ipv6/nf_conntrack_ipv6.h5
-rw-r--r--include/net/netfilter/nf_conntrack_core.h10
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h2
-rw-r--r--include/net/netfilter/nf_nat_core.h4
-rw-r--r--include/net/netfilter/nf_nat_helper.h6
-rw-r--r--include/net/netfilter/nf_nat_protocol.h2
-rw-r--r--include/net/netfilter/nf_nat_rule.h2
-rw-r--r--include/net/protocol.h2
-rw-r--r--include/net/xfrm.h2
-rw-r--r--include/scsi/libsrp.h2
-rw-r--r--include/scsi/scsi_cmnd.h13
-rw-r--r--include/scsi/scsi_dbg.h2
-rw-r--r--include/scsi/scsi_driver.h10
-rw-r--r--include/scsi/scsi_eh.h23
-rw-r--r--include/scsi/scsi_host.h14
-rw-r--r--include/scsi/scsi_tgt.h8
-rw-r--r--include/scsi/scsi_tgt_if.h35
-rw-r--r--include/scsi/scsi_transport.h12
-rw-r--r--include/scsi/scsi_transport_fc.h6
-rw-r--r--include/scsi/scsi_transport_iscsi.h2
-rw-r--r--include/scsi/scsi_transport_srp.h39
-rw-r--r--include/scsi/sd.h14
-rw-r--r--init/Kconfig21
-rw-r--r--kernel/auditsc.c1
-rw-r--r--kernel/delayacct.c2
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/fork.c3
-rw-r--r--kernel/ksysfs.c8
-rw-r--r--kernel/lockdep.c26
-rw-r--r--kernel/lockdep_proc.c61
-rw-r--r--kernel/mutex.c35
-rw-r--r--kernel/posix-timers.c6
-rw-r--r--kernel/rcupdate.c8
-rw-r--r--kernel/sched.c1444
-rw-r--r--kernel/sched_debug.c282
-rw-r--r--kernel/sched_fair.c811
-rw-r--r--kernel/sched_idletask.c8
-rw-r--r--kernel/sched_rt.c19
-rw-r--r--kernel/sched_stats.h28
-rw-r--r--kernel/sysctl.c39
-rw-r--r--kernel/time/Kconfig5
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/clockevents.c3
-rw-r--r--kernel/time/tick-broadcast.c44
-rw-r--r--kernel/time/tick-common.c5
-rw-r--r--kernel/user.c249
-rw-r--r--lib/Makefile3
-rw-r--r--lib/idr.c2
-rw-r--r--lib/kobject.c135
-rw-r--r--lib/kobject_uevent.c216
-rw-r--r--lib/swiotlb.c1
-rw-r--r--lib/zlib_inflate/Makefile2
-rw-r--r--lib/zlib_inflate/inflate.c47
-rw-r--r--lib/zlib_inflate/infutil.c49
-rw-r--r--mm/migrate.c2
-rw-r--r--net/atm/atm_sysfs.c7
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_input.c6
-rw-r--r--net/bridge/br_netfilter.c36
-rw-r--r--net/bridge/br_sysfs_br.c2
-rw-r--r--net/bridge/netfilter/ebt_arpreply.c3
-rw-r--r--net/bridge/netfilter/ebt_dnat.c17
-rw-r--r--net/bridge/netfilter/ebt_mark.c10
-rw-r--r--net/bridge/netfilter/ebt_redirect.c21
-rw-r--r--net/bridge/netfilter/ebt_snat.c23
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
-rw-r--r--net/bridge/netfilter/ebtable_filter.c4
-rw-r--r--net/bridge/netfilter/ebtable_nat.c8
-rw-r--r--net/bridge/netfilter/ebtables.c12
-rw-r--r--net/core/dev.c102
-rw-r--r--net/core/neighbour.c2
-rw-r--r--net/core/net-sysfs.c14
-rw-r--r--net/core/skbuff.c195
-rw-r--r--net/core/sock.c1
-rw-r--r--net/dccp/ipv6.c3
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c4
-rw-r--r--net/ipv4/Makefile3
-rw-r--r--net/ipv4/inet_fragment.c174
-rw-r--r--net/ipv4/inet_lro.c16
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_fragment.c421
-rw-r--r--net/ipv4/ip_input.c10
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_app.c33
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c104
-rw-r--r--net/ipv4/ipvs/ip_vs_ftp.c19
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c51
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c51
-rw-r--r--net/ipv4/ipvs/ip_vs_xmit.c6
-rw-r--r--net/ipv4/netfilter.c77
-rw-r--r--net/ipv4/netfilter/arp_tables.c20
-rw-r--r--net/ipv4/netfilter/arpt_mangle.c28
-rw-r--r--net/ipv4/netfilter/arptable_filter.c4
-rw-r--r--net/ipv4/netfilter/ip_queue.c24
-rw-r--r--net/ipv4/netfilter/ip_tables.c20
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c14
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c27
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c4
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c6
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c8
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c6
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c22
-rw-r--r--net/ipv4/netfilter/ipt_SAME.c4
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c8
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c6
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c4
-rw-r--r--net/ipv4/netfilter/iptable_filter.c12
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c22
-rw-r--r--net/ipv4/netfilter/iptable_raw.c12
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c48
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c50
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c18
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c58
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c118
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c8
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c8
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_icmp.c10
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_tcp.c16
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udp.c16
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_unknown.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c14
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c56
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c14
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c62
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c2
-rw-r--r--net/ipv4/proc.c4
-rw-r--r--net/ipv4/sysctl_net_ipv4.c9
-rw-r--r--net/ipv4/tcp_input.c11
-rw-r--r--net/ipv4/xfrm4_output.c4
-rw-r--r--net/ipv6/exthdrs.c64
-rw-r--r--net/ipv6/icmp.c5
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_input.c6
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/netfilter.c6
-rw-r--r--net/ipv6/netfilter/ip6_queue.c20
-rw-r--r--net/ipv6/netfilter/ip6_tables.c16
-rw-r--r--net/ipv6/netfilter/ip6t_HL.c6
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c5
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c14
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c12
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c32
-rw-r--r--net/ipv6/netfilter/ip6table_raw.c4
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c51
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c314
-rw-r--r--net/ipv6/proc.c2
-rw-r--r--net/ipv6/reassembly.c361
-rw-r--r--net/ipv6/route.c77
-rw-r--r--net/ipv6/sysctl_net_ipv6.c9
-rw-r--r--net/ipv6/tcp_ipv6.c3
-rw-r--r--net/ipv6/tunnel6.c6
-rw-r--r--net/ipv6/udp.c7
-rw-r--r--net/ipv6/udp_impl.h2
-rw-r--r--net/ipv6/udplite.c4
-rw-r--r--net/ipv6/xfrm6_input.c4
-rw-r--r--net/ipv6/xfrm6_output.c4
-rw-r--r--net/netfilter/core.c48
-rw-r--r--net/netfilter/nf_conntrack_amanda.c20
-rw-r--r--net/netfilter/nf_conntrack_core.c30
-rw-r--r--net/netfilter/nf_conntrack_ftp.c18
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c236
-rw-r--r--net/netfilter/nf_conntrack_irc.c16
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c10
-rw-r--r--net/netfilter/nf_conntrack_pptp.c28
-rw-r--r--net/netfilter/nf_conntrack_sane.c10
-rw-r--r--net/netfilter/nf_conntrack_sip.c24
-rw-r--r--net/netfilter/nf_conntrack_tftp.c8
-rw-r--r--net/netfilter/nf_internals.h2
-rw-r--r--net/netfilter/nf_queue.c4
-rw-r--r--net/netfilter/nfnetlink_queue.c20
-rw-r--r--net/netfilter/xt_CLASSIFY.c4
-rw-r--r--net/netfilter/xt_CONNMARK.c14
-rw-r--r--net/netfilter/xt_CONNSECMARK.c3
-rw-r--r--net/netfilter/xt_DSCP.c16
-rw-r--r--net/netfilter/xt_MARK.c12
-rw-r--r--net/netfilter/xt_NFLOG.c4
-rw-r--r--net/netfilter/xt_NFQUEUE.c2
-rw-r--r--net/netfilter/xt_NOTRACK.c10
-rw-r--r--net/netfilter/xt_SECMARK.c4
-rw-r--r--net/netfilter/xt_TCPMSS.c58
-rw-r--r--net/netfilter/xt_TRACE.c4
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/sched/act_ipt.c6
-rw-r--r--net/sched/sch_ingress.c5
-rw-r--r--net/sctp/ipv6.c4
-rw-r--r--net/sctp/socket.c10
-rw-r--r--net/sunrpc/Makefile1
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c6
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c144
-rw-r--r--net/sunrpc/clnt.c52
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/sunrpc/rpcb_clnt.c151
-rw-r--r--net/sunrpc/sched.c2
-rw-r--r--net/sunrpc/socklib.c3
-rw-r--r--net/sunrpc/sunrpc_syms.c2
-rw-r--r--net/sunrpc/svc.c40
-rw-r--r--net/sunrpc/timer.c4
-rw-r--r--net/sunrpc/xprt.c116
-rw-r--r--net/sunrpc/xprtrdma/Makefile3
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c868
-rw-r--r--net/sunrpc/xprtrdma/transport.c800
-rw-r--r--net/sunrpc/xprtrdma/verbs.c1626
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h330
-rw-r--r--net/sunrpc/xprtsock.c567
-rw-r--r--net/unix/af_unix.c4
-rw-r--r--net/wireless/sysfs.c3
-rw-r--r--scripts/mod/file2alias.c11
-rw-r--r--security/selinux/hooks.c11
-rw-r--r--sound/aoa/soundbus/core.c33
-rw-r--r--sound/pci/bt87x.c2
-rw-r--r--sound/usb/usbaudio.c2
1818 files changed, 94531 insertions, 58708 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 43e89b1537d..cc10ce7dc33 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -145,7 +145,7 @@ fb/
feature-removal-schedule.txt
- list of files and features that are going to be removed.
filesystems/
- - directory with info on the various filesystems that Linux supports.
+ - info on the vfs and the various filesystems that Linux supports.
firmware_class/
- request_firmware() hotplug interface info.
floppy.txt
@@ -230,8 +230,6 @@ local_ops.txt
- semantics and behavior of local atomic operations.
lockdep-design.txt
- documentation on the runtime locking correctness validator.
-locks.txt
- - info on file locking implementations, flock() vs. fcntl(), etc.
logo.gif
- full colour GIF image of Linux logo (penguin - Tux).
logo.txt
@@ -240,8 +238,6 @@ m68k/
- directory with info about Linux on Motorola 68k architecture.
magic-number.txt
- list of magic numbers used to mark/protect kernel data structures.
-mandatory.txt
- - info on the Linux implementation of Sys V mandatory file locking.
mca.txt
- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
md.txt
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index cc7a8c39fb6..b939ebb6287 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -68,6 +68,9 @@ size and dma_handle must all be the same as those passed into the
consistent allocate. cpu_addr must be the virtual address returned by
the consistent allocate.
+Note that unlike their sibling allocation calls, these routines
+may only be called with IRQs enabled.
+
Part Ib - Using small dma-coherent buffers
------------------------------------------
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 08687e45e19..1a7f53068ec 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
procfs-guide.xml writing_usb_driver.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
- genericirq.xml
+ genericirq.xml s390-drivers.xml
###
# The build process is as follows (targets):
diff --git a/Documentation/DocBook/deviceiobook.tmpl b/Documentation/DocBook/deviceiobook.tmpl
index c917de681cc..361c884d860 100644
--- a/Documentation/DocBook/deviceiobook.tmpl
+++ b/Documentation/DocBook/deviceiobook.tmpl
@@ -316,7 +316,7 @@ CPU B: spin_unlock_irqrestore(&dev_lock, flags)
<chapter id="pubfunctions">
<title>Public Functions Provided</title>
-!Iinclude/asm-i386/io.h
+!Iinclude/asm-x86/io_32.h
!Elib/iomap.c
</chapter>
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index e5da4f2b7c2..230cbf75378 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -45,8 +45,8 @@
</sect1>
<sect1><title>Atomic and pointer manipulation</title>
-!Iinclude/asm-i386/atomic.h
-!Iinclude/asm-i386/unaligned.h
+!Iinclude/asm-x86/atomic_32.h
+!Iinclude/asm-x86/unaligned_32.h
</sect1>
<sect1><title>Delaying, scheduling, and timer routines</title>
@@ -119,7 +119,7 @@ X!Ilib/string.c
!Elib/string.c
</sect1>
<sect1><title>Bit Operations</title>
-!Iinclude/asm-i386/bitops.h
+!Iinclude/asm-x86/bitops_32.h
</sect1>
</chapter>
@@ -155,8 +155,8 @@ X!Ilib/string.c
!Emm/slab.c
</sect1>
<sect1><title>User Space Memory Access</title>
-!Iinclude/asm-i386/uaccess.h
-!Earch/i386/lib/usercopy.c
+!Iinclude/asm-x86/uaccess_32.h
+!Earch/x86/lib/usercopy_32.c
</sect1>
<sect1><title>More Memory Management Functions</title>
!Emm/readahead.c
@@ -293,7 +293,7 @@ X!Ekernel/module.c
</sect1>
<sect1><title>MTRR Handling</title>
-!Earch/i386/kernel/cpu/mtrr/main.c
+!Earch/x86/kernel/cpu/mtrr/main.c
</sect1>
<sect1><title>PCI Support Library</title>
@@ -316,14 +316,14 @@ X!Edrivers/pci/hotplug.c
<sect1><title>MCA Architecture</title>
<sect2><title>MCA Device Functions</title>
<para>
- Refer to the file arch/i386/kernel/mca.c for more information.
+ Refer to the file arch/x86/kernel/mca_32.c for more information.
</para>
<!-- FIXME: Removed for now since no structured comments in source
-X!Earch/i386/kernel/mca.c
+X!Earch/x86/kernel/mca_32.c
-->
</sect2>
<sect2><title>MCA Bus DMA</title>
-!Iinclude/asm-i386/mca_dma.h
+!Iinclude/asm-x86/mca_dma.h
</sect2>
</sect1>
</chapter>
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index 582032eea87..4c63e586416 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -1239,7 +1239,7 @@ static struct block_device_operations opt_fops = {
</para>
<para>
- <filename>include/asm-i386/delay.h:</filename>
+ <filename>include/asm-x86/delay_32.h:</filename>
</para>
<programlisting>
#define ndelay(n) (__builtin_constant_p(n) ? \
@@ -1265,7 +1265,7 @@ static struct block_device_operations opt_fops = {
</programlisting>
<para>
- <filename>include/asm-i386/uaccess.h:</filename>
+ <filename>include/asm-x86/uaccess_32.h:</filename>
</para>
<programlisting>
diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl
index 42a760cd746..529a53dc138 100644
--- a/Documentation/DocBook/mcabook.tmpl
+++ b/Documentation/DocBook/mcabook.tmpl
@@ -101,7 +101,7 @@
<chapter id="dmafunctions">
<title>DMA Functions Provided</title>
-!Iinclude/asm-i386/mca_dma.h
+!Iinclude/asm-x86/mca_dma.h
</chapter>
</book>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index a8c8cce5063..6fbc41d98c1 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -275,16 +275,13 @@ int __init board_init (void)
int err = 0;
/* Allocate memory for MTD device structure and private data */
- board_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+ board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!board_mtd) {
printk ("Unable to allocate NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
- /* Initialize structures */
- memset ((char *) board_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
-
/* map physical adress */
baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
if(!baseaddr){
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
new file mode 100644
index 00000000000..254e769282a
--- /dev/null
+++ b/Documentation/DocBook/s390-drivers.tmpl
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="s390drivers">
+ <bookinfo>
+ <title>Writing s390 channel device drivers</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Cornelia</firstname>
+ <surname>Huck</surname>
+ <affiliation>
+ <address>
+ <email>cornelia.huck@de.ibm.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2007</year>
+ <holder>IBM Corp.</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This document describes the interfaces available for device drivers that
+ drive s390 based channel attached devices. This includes interfaces for
+ interaction with the hardware and interfaces for interacting with the
+ common driver core. Those interfaces are provided by the s390 common I/O
+ layer.
+ </para>
+ <para>
+ The document assumes a familarity with the technical terms associated
+ with the s390 channel I/O architecture. For a description of this
+ architecture, please refer to the "z/Architecture: Principles of
+ Operation", IBM publication no. SA22-7832.
+ </para>
+ <para>
+ While most I/O devices on a s390 system are typically driven through the
+ channel I/O mechanism described here, there are various other methods
+ (like the diag interface). These are out of the scope of this document.
+ </para>
+ <para>
+ Some additional information can also be found in the kernel source
+ under Documentation/s390/driver-model.txt.
+ </para>
+ </chapter>
+ <chapter id="ccw">
+ <title>The ccw bus</title>
+ <para>
+ The ccw bus typically contains the majority of devices available to
+ a s390 system. Named after the channel command word (ccw), the basic
+ command structure used to address its devices, the ccw bus contains
+ so-called channel attached devices. They are addressed via subchannels,
+ visible on the css bus. A device driver, however, will never interact
+ with the subchannel directly, but only via the device on the ccw bus,
+ the ccw device.
+ </para>
+ <sect1 id="channelIO">
+ <title>I/O functions for channel-attached devices</title>
+ <para>
+ Some hardware structures have been translated into C structures for use
+ by the common I/O layer and device drivers. For more information on
+ the hardware structures represented here, please consult the Principles
+ of Operation.
+ </para>
+!Iinclude/asm-s390/cio.h
+ </sect1>
+ <sect1 id="ccwdev">
+ <title>ccw devices</title>
+ <para>
+ Devices that want to initiate channel I/O need to attach to the ccw bus.
+ Interaction with the driver core is done via the common I/O layer, which
+ provides the abstractions of ccw devices and ccw device drivers.
+ </para>
+ <para>
+ The functions that initiate or terminate channel I/O all act upon a
+ ccw device structure. Device drivers must not bypass those functions
+ or strange side effects may happen.
+ </para>
+!Iinclude/asm-s390/ccwdev.h
+!Edrivers/s390/cio/device.c
+!Edrivers/s390/cio/device_ops.c
+ </sect1>
+ <sect1 id="cmf">
+ <title>The channel-measurement facility</title>
+ <para>
+ The channel-measurement facility provides a means to collect
+ measurement data which is made available by the channel subsystem
+ for each channel attached device.
+ </para>
+!Iinclude/asm-s390/cmb.h
+!Edrivers/s390/cio/cmf.c
+ </sect1>
+ </chapter>
+
+ <chapter id="ccwgroup">
+ <title>The ccwgroup bus</title>
+ <para>
+ The ccwgroup bus only contains artificial devices, created by the user.
+ Many networking devices (e.g. qeth) are in fact composed of several
+ ccw devices (like read, write and data channel for qeth). The
+ ccwgroup bus provides a mechanism to create a meta-device which
+ contains those ccw devices as slave devices and can be associated
+ with the netdevice.
+ </para>
+ <sect1 id="ccwgroupdevices">
+ <title>ccw group devices</title>
+!Iinclude/asm-s390/ccwgroup.h
+!Edrivers/s390/cio/ccwgroup.c
+ </sect1>
+ </chapter>
+
+</book>
diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt
index 0d8240774fc..a51f693c154 100644
--- a/Documentation/MSI-HOWTO.txt
+++ b/Documentation/MSI-HOWTO.txt
@@ -241,68 +241,7 @@ address space of the MSI-X table/MSI-X PBA. Otherwise, the PCI subsystem
will fail enabling MSI-X on its hardware device when it calls the function
pci_enable_msix().
-5.3.2 Handling MSI-X allocation
-
-Determining the number of MSI-X vectors allocated to a function is
-dependent on the number of MSI capable devices and MSI-X capable
-devices populated in the system. The policy of allocating MSI-X
-vectors to a function is defined as the following:
-
-#of MSI-X vectors allocated to a function = (x - y)/z where
-
-x = The number of available PCI vector resources by the time
- the device driver calls pci_enable_msix(). The PCI vector
- resources is the sum of the number of unassigned vectors
- (new) and the number of released vectors when any MSI/MSI-X
- device driver switches its hardware device back to a legacy
- mode or is hot-removed. The number of unassigned vectors
- may exclude some vectors reserved, as defined in parameter
- NR_HP_RESERVED_VECTORS, for the case where the system is
- capable of supporting hot-add/hot-remove operations. Users
- may change the value defined in NR_HR_RESERVED_VECTORS to
- meet their specific needs.
-
-y = The number of MSI capable devices populated in the system.
- This policy ensures that each MSI capable device has its
- vector reserved to avoid the case where some MSI-X capable
- drivers may attempt to claim all available vector resources.
-
-z = The number of MSI-X capable devices populated in the system.
- This policy ensures that maximum (x - y) is distributed
- evenly among MSI-X capable devices.
-
-Note that the PCI subsystem scans y and z during a bus enumeration.
-When the PCI subsystem completes configuring MSI/MSI-X capability
-structure of a device as requested by its device driver, y/z is
-decremented accordingly.
-
-5.3.3 Handling MSI-X shortages
-
-For the case where fewer MSI-X vectors are allocated to a function
-than requested, the function pci_enable_msix() will return the
-maximum number of MSI-X vectors available to the caller. A device
-driver may re-send its request with fewer or equal vectors indicated
-in the return. For example, if a device driver requests 5 vectors, but
-the number of available vectors is 3 vectors, a value of 3 will be
-returned as a result of pci_enable_msix() call. A function could be
-designed for its driver to use only 3 MSI-X table entries as
-different combinations as ABC--, A-B-C, A--CB, etc. Note that this
-patch does not support multiple entries with the same vector. Such
-attempt by a device driver to use 5 MSI-X table entries with 3 vectors
-as ABBCC, AABCC, BCCBA, etc will result as a failure by the function
-pci_enable_msix(). Below are the reasons why supporting multiple
-entries with the same vector is an undesirable solution.
-
- - The PCI subsystem cannot determine the entry that
- generated the message to mask/unmask MSI while handling
- software driver ISR. Attempting to walk through all MSI-X
- table entries (2048 max) to mask/unmask any match vector
- is an undesirable solution.
-
- - Walking through all MSI-X table entries (2048 max) to handle
- SMP affinity of any match vector is an undesirable solution.
-
-5.3.4 API pci_enable_msix
+5.3.2 API pci_enable_msix
int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
@@ -339,7 +278,7 @@ a failure. This failure may be a result of duplicate entries
specified in second argument, or a result of no available vector,
or a result of failing to initialize MSI-X table entries.
-5.3.5 API pci_disable_msix
+5.3.3 API pci_disable_msix
void pci_disable_msix(struct pci_dev *dev)
@@ -349,7 +288,7 @@ always call free_irq() on all MSI-X vectors it has done request_irq()
on before calling this API. Failure to do so results in a BUG_ON() and
a device will be left with MSI-X enabled and leaks its vectors.
-5.3.6 MSI-X mode vs. legacy mode diagram
+5.3.4 MSI-X mode vs. legacy mode diagram
The below diagram shows the events which switch the interrupt
mode on the MSI-X capable device function between MSI-X mode and
@@ -407,7 +346,7 @@ between MSI mod MSI-X mode during a run-time.
MSI/MSI-X support requires support from both system hardware and
individual hardware device functions.
-5.5.1 System hardware support
+5.5.1 Required x86 hardware support
Since the target of MSI address is the local APIC CPU, enabling
MSI/MSI-X support in the Linux kernel is dependent on whether existing
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 63df2262d41..fb8258ebc57 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -205,20 +205,6 @@ Who: Len Brown <len.brown@intel.com>
---------------------------
-What: Compaq touchscreen device emulation
-When: Oct 2007
-Files: drivers/input/tsdev.c
-Why: The code says it was obsolete when it was written in 2001.
- tslib is a userspace library which does anything tsdev can do and
- much more besides in userspace where this code belongs. There is no
- longer any need for tsdev and applications should have converted to
- use tslib by now.
- The name "tsdev" is also extremely confusing and lots of people have
- it loaded when they don't need/use it.
-Who: Richard Purdie <rpurdie@rpsys.net>
-
----------------------------
-
What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
When: September 2007
Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index 59db1bca702..599593a1706 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -52,6 +52,10 @@ isofs.txt
- info and mount options for the ISO 9660 (CDROM) filesystem.
jfs.txt
- info and mount options for the JFS filesystem.
+locks.txt
+ - info on file locking implementations, flock() vs. fcntl(), etc.
+mandatory-locking.txt
+ - info on the Linux implementation of Sys V mandatory file locking.
ncpfs.txt
- info on Novell Netware(tm) filesystem using NCP protocol.
ntfs.txt
diff --git a/Documentation/locks.txt b/Documentation/filesystems/locks.txt
index e3b402ef33b..fab857accbd 100644
--- a/Documentation/locks.txt
+++ b/Documentation/filesystems/locks.txt
@@ -53,11 +53,11 @@ fcntl(), with all the problems that implies.
1.3 Mandatory Locking As A Mount Option
---------------------------------------
-Mandatory locking, as described in 'Documentation/mandatory.txt' was prior
-to this release a general configuration option that was valid for all
-mounted filesystems. This had a number of inherent dangers, not the least
-of which was the ability to freeze an NFS server by asking it to read a
-file for which a mandatory lock existed.
+Mandatory locking, as described in 'Documentation/filesystems/mandatory.txt'
+was prior to this release a general configuration option that was valid for
+all mounted filesystems. This had a number of inherent dangers, not the
+least of which was the ability to freeze an NFS server by asking it to read
+a file for which a mandatory lock existed.
From this release of the kernel, mandatory locking can be turned on and off
on a per-filesystem basis, using the mount options 'mand' and 'nomand'.
diff --git a/Documentation/mandatory.txt b/Documentation/filesystems/mandatory-locking.txt
index bc449d49eee..0979d1d2ca8 100644
--- a/Documentation/mandatory.txt
+++ b/Documentation/filesystems/mandatory-locking.txt
@@ -3,7 +3,26 @@
Andy Walker <andy@lysaker.kvaerner.no>
15 April 1996
-
+ (Updated September 2007)
+
+0. Why you should avoid mandatory locking
+-----------------------------------------
+
+The Linux implementation is prey to a number of difficult-to-fix race
+conditions which in practice make it not dependable:
+
+ - The write system call checks for a mandatory lock only once
+ at its start. It is therefore possible for a lock request to
+ be granted after this check but before the data is modified.
+ A process may then see file data change even while a mandatory
+ lock was held.
+ - Similarly, an exclusive lock may be granted on a file after
+ the kernel has decided to proceed with a read, but before the
+ read has actually completed, and the reading process may see
+ the file data in a state which should not have been visible
+ to it.
+ - Similar races make the claimed mutual exclusion between lock
+ and mmap similarly unreliable.
1. What is mandatory locking?
------------------------------
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 8ee10ec8829..e79ee2db183 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -407,7 +407,7 @@ raiddev /dev/md0
device /dev/hda5
raid-disk 0
device /dev/hdb1
- raid-disl 1
+ raid-disk 1
For linear raid, just change the raid-level above to "raid-level linear", for
mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -457,6 +457,8 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.1.29:
+ - Fix a deadlock when mounting read-write.
2.1.28:
- Fix a deadlock.
2.1.27:
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index 870cda9416e..170bf862437 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -4,7 +4,7 @@ Kernel driver coretemp
Supported chips:
* All Intel Core family
Prefix: 'coretemp'
- CPUID: family 0x6, models 0xe, 0xf
+ CPUID: family 0x6, models 0xe, 0xf, 0x16
Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
Volume 3A: System Programming Guide
diff --git a/Documentation/hwmon/dme1737 b/Documentation/hwmon/dme1737
index 1a0f3d64ab8..8f446070e64 100644
--- a/Documentation/hwmon/dme1737
+++ b/Documentation/hwmon/dme1737
@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'dme1737'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Provided by SMSC upon request and under NDA
+ * SMSC SCH3112, SCH3114, SCH3116
+ Prefix: 'sch311x'
+ Addresses scanned: none, address read from Super-I/O config space
+ Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
Authors:
Juerg Haefliger <juergh@gmail.com>
@@ -27,16 +31,25 @@ Description
-----------
This driver implements support for the hardware monitoring capabilities of the
-SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
-features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
-internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
-fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
-controlling fan speeds both manually and automatically.
-
-Fan[3-6] and pwm[3,5-6] are optional features and their availability is
-dependent on the configuration of the chip. The driver will detect which
-features are present during initialization and create the sysfs attributes
-accordingly.
+SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
+chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
+diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
+to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
+outputs pwm[1-3,5-6] for controlling fan speeds both manually and
+automatically.
+
+For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
+and pwm[3,5-6] are optional features and their availability depends on the
+configuration of the chip. The driver will detect which features are present
+during initialization and create the sysfs attributes accordingly.
+
+For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
+pwm[5-6] don't exist.
+
+The hardware monitoring features of the DME1737 and A8000 are only accessible
+via SMBus, while the SCH311x only provides access via the ISA bus. The driver
+will therefore register itself as an I2C client driver if it detects a DME1737
+or A8000 and as a platform driver if it detects a SCH311x chip.
Voltage Monitoring
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f
index 94e0d2cbd3d..f0d55976740 100644
--- a/Documentation/hwmon/f71805f
+++ b/Documentation/hwmon/f71805f
@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'f71805f'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Available from the Fintek website
+ * Fintek F71806F/FG
+ Prefix: 'f71872f'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Available from the Fintek website
* Fintek F71872F/FG
Prefix: 'f71872f'
Addresses scanned: none, address read from Super I/O config space
@@ -38,6 +42,9 @@ The Fintek F71872F/FG Super I/O chip is almost the same, with two
additional internal voltages monitored (VSB and battery). It also features
6 VID inputs. The VID inputs are not yet supported by this driver.
+The Fintek F71806F/FG Super-I/O chip is essentially the same as the
+F71872F/FG, and is undistinguishable therefrom.
+
The driver assumes that no more than one chip is present, which seems
reasonable.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 81ecc7e41c5..5b704a40256 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -90,7 +90,8 @@ upper VID bits share their pins with voltage inputs (in5 and in6) so you
can't have both on a given board.
The IT8716F, IT8718F and later IT8712F revisions have support for
-2 additional fans. They are not yet supported by the driver.
+2 additional fans. They are supported by the driver for the IT8716F and
+IT8718F but not for the IT8712F
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
16-bit tachometer counters for fans 1 to 3. This is better (no more fan
diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78
index fd5dc7a19f0..dfc318a60fd 100644
--- a/Documentation/hwmon/lm78
+++ b/Documentation/hwmon/lm78
@@ -56,16 +56,6 @@ should work with. This is hardcoded by the mainboard and/or processor itself.
It is a value in volts. When it is unconnected, you will often find the
value 3.50 V here.
-In addition to the alarms described above, there are a couple of additional
-ones. There is a BTI alarm, which gets triggered when an external chip has
-crossed its limits. Usually, this is connected to all LM75 chips; if at
-least one crosses its limits, this bit gets set. The CHAS alarm triggers
-if your computer case is open. The FIFO alarms should never trigger; it
-indicates an internal error. The SMI_IN alarm indicates some other chip
-has triggered an SMI interrupt. As we do not use SMI interrupts at all,
-this condition usually indicates there is a problem with some other
-device.
-
If an alarm triggers, it will remain triggered until the hardware register
is read at least once. This means that the cause for the alarm may
already have disappeared! Note that in the current implementation, all
diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93
index 4e4a1dc1d2d..ac711f357fa 100644
--- a/Documentation/hwmon/lm93
+++ b/Documentation/hwmon/lm93
@@ -7,7 +7,7 @@ Supported chips:
Addresses scanned: I2C 0x2c-0x2e
Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
-Author:
+Authors:
Mark M. Hoffman <mhoffman@lightlink.com>
Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
@@ -16,7 +16,6 @@ Author:
Module Parameters
-----------------
-(specific to LM93)
* init: integer
Set to non-zero to force some initializations (default is 0).
* disable_block: integer
@@ -37,30 +36,13 @@ Module Parameters
I.e. this parameter controls the VID pin input thresholds; if your VID
inputs are not working, try changing this. The default value is "0".
-(common among sensor drivers)
-* force: short array (min = 1, max = 48)
- List of adapter,address pairs to assume to be present. Autodetection
- of the target device will still be attempted. Use one of the more
- specific force directives below if this doesn't detect the device.
-* force_lm93: short array (min = 1, max = 48)
- List of adapter,address pairs which are unquestionably assumed to contain
- a 'lm93' chip
-* ignore: short array (min = 1, max = 48)
- List of adapter,address pairs not to scan
-* ignore_range: short array (min = 1, max = 48)
- List of adapter,start-addr,end-addr triples not to scan
-* probe: short array (min = 1, max = 48)
- List of adapter,address pairs to scan additionally
-* probe_range: short array (min = 1, max = 48)
- List of adapter,start-addr,end-addr triples to scan additionally
-
Hardware Description
--------------------
(from the datasheet)
-The LM93, hardware monitor, has a two wire digital interface compatible with
+The LM93 hardware monitor has a two wire digital interface compatible with
SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
diode connected transistors as well as its own die and 16 power supply
voltages. To set fan speed, the LM93 has two PWM outputs that are each
@@ -69,18 +51,12 @@ table based. The LM93 includes a digital filter that can be invoked to smooth
temperature readings for better control of fan speed. The LM93 has four
tachometer inputs to measure fan speed. Limit and status registers for all
measured values are included. The LM93 builds upon the functionality of
-previous motherboard management ASICs and uses some of the LM85 s features
+previous motherboard management ASICs and uses some of the LM85's features
(i.e. smart tachometer mode). It also adds measurement and control support
for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
processor Xeon class motherboard with a minimum of external components.
-Driver Description
-------------------
-
-This driver implements support for the National Semiconductor LM93.
-
-
User Interface
--------------
@@ -101,7 +77,7 @@ These intervals can be found in the sysfs files prochot1_interval and
prochot2_interval. The values in these files specify the intervals for
#P1_PROCHOT and #P2_PROCHOT, respectively. Selecting a value not in this
list will cause the driver to use the next largest interval. The available
-intervals are:
+intervals are (in seconds):
#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
@@ -111,12 +87,12 @@ assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a
non-zero integer to the sysfs file prochot_short.
The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
-one or both of them. When overridden, the signal has a period of 3.56 mS,
+one or both of them. When overridden, the signal has a period of 3.56 ms,
a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
The sysfs files prochot1_override and prochot2_override contain boolean
-intgers which enable or disable the override function for #P1_PROCHOT and
+integers which enable or disable the override function for #P1_PROCHOT and
#P2_PROCHOT, respectively. The sysfs file prochot_override_duty_cycle
contains a value controlling the duty cycle for the PWM signal used when
the override function is enabled. This value ranges from 0 to 15, with 0
@@ -166,7 +142,7 @@ frequency values are constrained by the hardware. Selecting a value which is
not available will cause the driver to use the next largest value. Also note
that this parameter has implications for the Smart Tach Mode (see above).
-PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
+PWM Output Frequencies (in Hz): 12, 36, 48, 60, 72, 84, 96, 22500 (default)
Automatic PWM:
@@ -178,7 +154,7 @@ individual control sources to which the PWM output is bound.
The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask
in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
- a "0" disables it. The h/w default is 0x0f (all temperatures bound).
+a "0" disables it. The h/w default is 0x0f (all temperatures bound).
0x01 - Temp 1
0x02 - Temp 2
@@ -324,89 +300,3 @@ LM93 Unique sysfs Files
gpio input state of 8 GPIO pins; read-only
-
-Sample Configuration File
--------------------------
-
-Here is a sample LM93 chip config for sensors.conf:
-
----------- cut here ----------
-chip "lm93-*"
-
-# VOLTAGE INPUTS
-
- # labels and scaling based on datasheet recommendations
- label in1 "+12V1"
- compute in1 @ * 12.945, @ / 12.945
- set in1_min 12 * 0.90
- set in1_max 12 * 1.10
-
- label in2 "+12V2"
- compute in2 @ * 12.945, @ / 12.945
- set in2_min 12 * 0.90
- set in2_max 12 * 1.10
-
- label in3 "+12V3"
- compute in3 @ * 12.945, @ / 12.945
- set in3_min 12 * 0.90
- set in3_max 12 * 1.10
-
- label in4 "FSB_Vtt"
-
- label in5 "3GIO"
-
- label in6 "ICH_Core"
-
- label in7 "Vccp1"
-
- label in8 "Vccp2"
-
- label in9 "+3.3V"
- set in9_min 3.3 * 0.90
- set in9_max 3.3 * 1.10
-
- label in10 "+5V"
- set in10_min 5.0 * 0.90
- set in10_max 5.0 * 1.10
-
- label in11 "SCSI_Core"
-
- label in12 "Mem_Core"
-
- label in13 "Mem_Vtt"
-
- label in14 "Gbit_Core"
-
- # Assuming R1/R2 = 4.1143, and 3.3V reference
- # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
- label in15 "-12V"
- compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
- set in15_min -12 * 0.90
- set in15_max -12 * 1.10
-
- label in16 "+3.3VSB"
- set in16_min 3.3 * 0.90
- set in16_max 3.3 * 1.10
-
-# TEMPERATURE INPUTS
-
- label temp1 "CPU1"
- label temp2 "CPU2"
- label temp3 "LM93"
-
-# TACHOMETER INPUTS
-
- label fan1 "Fan1"
- set fan1_min 3000
- label fan2 "Fan2"
- set fan2_min 3000
- label fan3 "Fan3"
- set fan3_min 3000
- label fan4 "Fan4"
- set fan4_min 3000
-
-# PWM OUTPUTS
-
- label pwm1 "CPU1"
- label pwm2 "CPU2"
-
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index b3a9e1b9dbd..a17b692d267 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -67,6 +67,10 @@ between readings to be caught and alarmed. The exact definition of an
alarm (for example, whether a threshold must be met or must be exceeded
to cause an alarm) is chip-dependent.
+When setting values of hwmon sysfs attributes, the string representation of
+the desired value must be written, note that strings which are not a number
+are interpreted as 0! For more on how written strings are interpreted see the
+"sysfs attribute writes interpretation" section at the end of this file.
-------------------------------------------------------------------------
@@ -78,8 +82,21 @@ RW read/write value
Read/write values may be read-only for some chips, depending on the
hardware implementation.
-All entries are optional, and should only be created in a given driver
-if the chip has the feature.
+All entries (except name) are optional, and should only be created in a
+given driver if the chip has the feature.
+
+
+********
+* Name *
+********
+
+name The chip name.
+ This should be a short, lowercase string, not containing
+ spaces nor dashes, representing the chip name. This is
+ the only mandatory attribute.
+ I2C devices get this attribute created automatically.
+ RO
+
************
* Voltages *
@@ -104,18 +121,17 @@ in[0-*]_input Voltage input value.
by the chip driver, and must be done by the application.
However, some drivers (notably lm87 and via686a)
do scale, because of internal resistors built into a chip.
- These drivers will output the actual voltage.
-
- Typical usage:
- in0_* CPU #1 voltage (not scaled)
- in1_* CPU #2 voltage (not scaled)
- in2_* 3.3V nominal (not scaled)
- in3_* 5.0V nominal (scaled)
- in4_* 12.0V nominal (scaled)
- in5_* -12.0V nominal (scaled)
- in6_* -5.0V nominal (scaled)
- in7_* varies
- in8_* varies
+ These drivers will output the actual voltage. Rule of
+ thumb: drivers should report the voltage values at the
+ "pins" of the chip.
+
+in[0-*]_label Suggested voltage channel label.
+ Text string
+ Should only be created if the driver has hints about what
+ this voltage channel is being used for, and user-space
+ doesn't. In all other cases, the label is provided by
+ user-space.
+ RO
cpu[0-*]_vid CPU core reference voltage.
Unit: millivolt
@@ -159,6 +175,13 @@ fan[1-*]_target
Only makes sense if the chip supports closed-loop fan speed
control based on the measured fan speed.
+fan[1-*]_label Suggested fan channel label.
+ Text string
+ Should only be created if the driver has hints about what
+ this fan channel is being used for, and user-space doesn't.
+ In all other cases, the label is provided by user-space.
+ RO
+
Also see the Alarms section for status flags associated with fans.
@@ -219,12 +242,12 @@ temp[1-*]_auto_point[1-*]_temp_hyst
****************
temp[1-*]_type Sensor type selection.
- Integers 1 to 6 or thermistor Beta value (typically 3435)
+ Integers 1 to 6
RW
1: PII/Celeron Diode
2: 3904 transistor
3: thermal diode
- 4: thermistor (default/unknown Beta)
+ 4: thermistor
5: AMD AMDSI
6: Intel PECI
Not all types are supported by all chips
@@ -260,18 +283,19 @@ temp[1-*]_crit_hyst
from the critical value.
RW
-temp[1-4]_offset
+temp[1-*]_offset
Temperature offset which is added to the temperature reading
by the chip.
Unit: millidegree Celsius
Read/Write value.
- If there are multiple temperature sensors, temp1_* is
- generally the sensor inside the chip itself,
- reported as "motherboard temperature". temp2_* to
- temp4_* are generally sensors external to the chip
- itself, for example the thermal diode inside the CPU or
- a thermistor nearby.
+temp[1-*]_label Suggested temperature channel label.
+ Text string
+ Should only be created if the driver has hints about what
+ this temperature channel is being used for, and user-space
+ doesn't. In all other cases, the label is provided by
+ user-space.
+ RO
Some chips measure temperature using external thermistors and an ADC, and
report the temperature measurement as a voltage. Converting this voltage
@@ -393,14 +417,53 @@ beep_mask Bitmask for beep.
RW
-*********
-* Other *
-*********
-
-eeprom Raw EEPROM data in binary form.
- RO
-
-pec Enable or disable PEC (SMBus only)
- 0: disable
- 1: enable
- RW
+sysfs attribute writes interpretation
+-------------------------------------
+
+hwmon sysfs attributes always contain numbers, so the first thing to do is to
+convert the input to a number, there are 2 ways todo this depending whether
+the number can be negative or not:
+unsigned long u = simple_strtoul(buf, NULL, 10);
+long s = simple_strtol(buf, NULL, 10);
+
+With buf being the buffer with the user input being passed by the kernel.
+Notice that we do not use the second argument of strto[u]l, and thus cannot
+tell when 0 is returned, if this was really 0 or is caused by invalid input.
+This is done deliberately as checking this everywhere would add a lot of
+code to the kernel.
+
+Notice that it is important to always store the converted value in an
+unsigned long or long, so that no wrap around can happen before any further
+checking.
+
+After the input string is converted to an (unsigned) long, the value should be
+checked if its acceptable. Be careful with further conversions on the value
+before checking it for validity, as these conversions could still cause a wrap
+around before the check. For example do not multiply the result, and only
+add/subtract if it has been divided before the add/subtract.
+
+What to do if a value is found to be invalid, depends on the type of the
+sysfs attribute that is being set. If it is a continuous setting like a
+tempX_max or inX_max attribute, then the value should be clamped to its
+limits using SENSORS_LIMIT(value, min_limit, max_limit). If it is not
+continuous like for example a tempX_type, then when an invalid value is
+written, -EINVAL should be returned.
+
+Example1, temp1_max, register is a signed 8 bit value (-128 - 127 degrees):
+
+ long v = simple_strtol(buf, NULL, 10) / 1000;
+ v = SENSORS_LIMIT(v, -128, 127);
+ /* write v to register */
+
+Example2, fan divider setting, valid values 2, 4 and 8:
+
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ switch (v) {
+ case 2: v = 1; break;
+ case 4: v = 2; break;
+ case 8: v = 3; break;
+ default:
+ return -EINVAL;
+ }
+ /* write v to register */
diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
index db9881df88a..f153b2f6d62 100644
--- a/Documentation/hwmon/w83791d
+++ b/Documentation/hwmon/w83791d
@@ -75,46 +75,64 @@ Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum
or maximum limit.
-The bit ordering for the alarm "realtime status register" and the
-"beep enable registers" are different.
-
-in0 (VCORE) : alarms: 0x000001 beep_enable: 0x000001
-in1 (VINR0) : alarms: 0x000002 beep_enable: 0x002000 <== mismatch
-in2 (+3.3VIN): alarms: 0x000004 beep_enable: 0x000004
-in3 (5VDD) : alarms: 0x000008 beep_enable: 0x000008
-in4 (+12VIN) : alarms: 0x000100 beep_enable: 0x000100
-in5 (-12VIN) : alarms: 0x000200 beep_enable: 0x000200
-in6 (-5VIN) : alarms: 0x000400 beep_enable: 0x000400
-in7 (VSB) : alarms: 0x080000 beep_enable: 0x010000 <== mismatch
-in8 (VBAT) : alarms: 0x100000 beep_enable: 0x020000 <== mismatch
-in9 (VINR1) : alarms: 0x004000 beep_enable: 0x004000
-temp1 : alarms: 0x000010 beep_enable: 0x000010
-temp2 : alarms: 0x000020 beep_enable: 0x000020
-temp3 : alarms: 0x002000 beep_enable: 0x000002 <== mismatch
-fan1 : alarms: 0x000040 beep_enable: 0x000040
-fan2 : alarms: 0x000080 beep_enable: 0x000080
-fan3 : alarms: 0x000800 beep_enable: 0x000800
-fan4 : alarms: 0x200000 beep_enable: 0x200000
-fan5 : alarms: 0x400000 beep_enable: 0x400000
-tart1 : alarms: 0x010000 beep_enable: 0x040000 <== mismatch
-tart2 : alarms: 0x020000 beep_enable: 0x080000 <== mismatch
-tart3 : alarms: 0x040000 beep_enable: 0x100000 <== mismatch
-case_open : alarms: 0x001000 beep_enable: 0x001000
-user_enable : alarms: -------- beep_enable: 0x800000
-
-*** NOTE: It is the responsibility of user-space code to handle the fact
-that the beep enable and alarm bits are in different positions when using that
-feature of the chip.
-
-When an alarm goes off, you can be warned by a beeping signal through your
-computer speaker. It is possible to enable all beeping globally, or only
-the beeping for some alarms.
-
-The driver only reads the chip values each 3 seconds; reading them more
-often will do no harm, but will return 'old' values.
+The w83791d has a global bit used to enable beeping from the speaker when an
+alarm is triggered as well as a bitmask to enable or disable the beep for
+specific alarms. You need both the global beep enable bit and the
+corresponding beep bit to be on for a triggered alarm to sound a beep.
+
+The sysfs interface to the gloabal enable is via the sysfs beep_enable file.
+This file is used for both legacy and new code.
+
+The sysfs interface to the beep bitmask has migrated from the original legacy
+method of a single sysfs beep_mask file to a newer method using multiple
+*_beep files as described in .../Documentation/hwmon/sysfs-interface.
+
+A similar change has occured for the bitmap corresponding to the alarms. The
+original legacy method used a single sysfs alarms file containing a bitmap
+of triggered alarms. The newer method uses multiple sysfs *_alarm files
+(again following the pattern described in sysfs-interface).
+
+Since both methods read and write the underlying hardware, they can be used
+interchangeably and changes in one will automatically be reflected by
+the other. If you use the legacy bitmask method, your user-space code is
+responsible for handling the fact that the alarms and beep_mask bitmaps
+are not the same (see the table below).
+
+NOTE: All new code should be written to use the newer sysfs-interface
+specification as that avoids bitmap problems and is the preferred interface
+going forward.
+
+The driver reads the hardware chip values at most once every three seconds.
+User mode code requesting values more often will receive cached values.
+
+Alarms bitmap vs. beep_mask bitmask
+------------------------------------
+For legacy code using the alarms and beep_mask files:
+
+in0 (VCORE) : alarms: 0x000001 beep_mask: 0x000001
+in1 (VINR0) : alarms: 0x000002 beep_mask: 0x002000 <== mismatch
+in2 (+3.3VIN): alarms: 0x000004 beep_mask: 0x000004
+in3 (5VDD) : alarms: 0x000008 beep_mask: 0x000008
+in4 (+12VIN) : alarms: 0x000100 beep_mask: 0x000100
+in5 (-12VIN) : alarms: 0x000200 beep_mask: 0x000200
+in6 (-5VIN) : alarms: 0x000400 beep_mask: 0x000400
+in7 (VSB) : alarms: 0x080000 beep_mask: 0x010000 <== mismatch
+in8 (VBAT) : alarms: 0x100000 beep_mask: 0x020000 <== mismatch
+in9 (VINR1) : alarms: 0x004000 beep_mask: 0x004000
+temp1 : alarms: 0x000010 beep_mask: 0x000010
+temp2 : alarms: 0x000020 beep_mask: 0x000020
+temp3 : alarms: 0x002000 beep_mask: 0x000002 <== mismatch
+fan1 : alarms: 0x000040 beep_mask: 0x000040
+fan2 : alarms: 0x000080 beep_mask: 0x000080
+fan3 : alarms: 0x000800 beep_mask: 0x000800
+fan4 : alarms: 0x200000 beep_mask: 0x200000
+fan5 : alarms: 0x400000 beep_mask: 0x400000
+tart1 : alarms: 0x010000 beep_mask: 0x040000 <== mismatch
+tart2 : alarms: 0x020000 beep_mask: 0x080000 <== mismatch
+tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch
+case_open : alarms: 0x001000 beep_mask: 0x001000
+global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
W83791D TODO:
---------------
-Provide a patch for per-file alarms and beep enables as defined in the hwmon
- documentation (Documentation/hwmon/sysfs-interface)
Provide a patch for smart-fan control (still need appropriate motherboard/fans)
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index fe6406f2f9a..fde4420e3f7 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -13,7 +13,8 @@ Supported adapters:
* Intel 631xESB/632xESB (ESB2)
* Intel 82801H (ICH8)
* Intel ICH9
- Datasheets: Publicly available at the Intel website
+ * Intel Tolapai
+ Datasheets: Publicly available at the Intel website
Authors:
Frodo Looijaard <frodol@dds.nl>,
diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574
index 2752c8ce316..5c1ad1376b6 100644
--- a/Documentation/i2c/chips/pcf8574
+++ b/Documentation/i2c/chips/pcf8574
@@ -62,8 +62,6 @@ if the corresponding output is set as 1, otherwise the current output
value, that is to say 0.
The write file is read/write. Writing a value outputs it on the I/O
-port. Reading returns the last written value.
-
-On module initialization the chip is configured as eight inputs (all
-outputs to 1), so you can connect any circuit to the PCF8574(A) without
-being afraid of short-circuit.
+port. Reading returns the last written value. As it is not possible
+to read this value from the chip, you need to write at least once to
+this file before you can read back from it.
diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface
index b849ad63658..9dd79123ddd 100644
--- a/Documentation/i2c/dev-interface
+++ b/Documentation/i2c/dev-interface
@@ -90,12 +90,15 @@ ioctl(file,I2C_SLAVE,long addr)
ioctl(file,I2C_TENBIT,long select)
Selects ten bit addresses if select not equals 0, selects normal 7 bit
- addresses if select equals 0. Default 0.
+ addresses if select equals 0. Default 0. This request is only valid
+ if the adapter has I2C_FUNC_10BIT_ADDR.
ioctl(file,I2C_PEC,long select)
Selects SMBus PEC (packet error checking) generation and verification
if select not equals 0, disables if select equals 0. Default 0.
- Used only for SMBus transactions.
+ Used only for SMBus transactions. This request only has an effect if the
+ the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
+ doesn't have any effect.
ioctl(file,I2C_FUNCS,unsigned long *funcs)
Gets the adapter functionality and puts it in *funcs.
@@ -103,8 +106,10 @@ ioctl(file,I2C_FUNCS,unsigned long *funcs)
ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
Do combined read/write transaction without stop in between.
- The argument is a pointer to a struct i2c_rdwr_ioctl_data {
+ Only valid if the adapter has I2C_FUNC_I2C. The argument is
+ a pointer to a
+ struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
}
diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
index 9cc081e6976..89e69ad3436 100644
--- a/Documentation/i2c/i2c-stub
+++ b/Documentation/i2c/i2c-stub
@@ -6,13 +6,14 @@ This module is a very simple fake I2C/SMBus driver. It implements four
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
(r/w) word data.
-You need to provide a chip address as a module parameter when loading
-this driver, which will then only react to SMBus commands to this address.
+You need to provide chip addresses as a module parameter when loading this
+driver, which will then only react to SMBus commands to these addresses.
No hardware is needed nor associated with this module. It will accept write
-quick commands to one address; it will respond to the other commands (also
-to one address) by reading from or writing to an array in memory. It will
-also spam the kernel logs for every command it handles.
+quick commands to the specified addresses; it will respond to the other
+commands (also to the specified addresses) by reading from or writing to
+arrays in memory. It will also spam the kernel logs for every command it
+handles.
A pointer register with auto-increment is implemented for all byte
operations. This allows for continuous byte reads like those supported by
@@ -26,8 +27,8 @@ The typical use-case is like this:
PARAMETERS:
-int chip_addr:
- The SMBus address to emulate a chip at.
+int chip_addr[10]:
+ The SMBus addresses to emulate chips at.
CAVEATS:
@@ -41,9 +42,6 @@ If the hardware for your driver has banked registers (e.g. Winbond sensors
chips) this module will not work well - although it could be extended to
support that pretty easily.
-Only one chip address is supported - although this module could be
-extended to support more.
-
If you spam it hard enough, printk can be lossy. This module really wants
something like relayfs.
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index 9f08dab1e75..d9d832c010e 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -1,4 +1,4 @@
-NOTE:
+NOTE:
This is a version of Documentation/HOWTO translated into Japanese.
This document is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
and the JF Project team <www.linux.or.jp/JF>.
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
fork. So if you have any comments or updates for this file, please try
to update the original English file first.
-Last Updated: 2007/07/18
+Last Updated: 2007/09/23
==================================
ã“ã‚Œã¯ã€
-linux-2.6.22/Documentation/HOWTO
+linux-2.6.23/Documentation/HOWTO
ã®å’Œè¨³ã§ã™ã€‚
翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2007/07/16
+翻訳日: 2007/09/19
翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
校正者: æ¾å€‰ã•ã‚“ <nbh--mats at nifty dot com>
å°æž— é›…å…¸ã•ã‚“ (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -27,6 +27,7 @@ linux-2.6.22/Documentation/HOWTO
野å£ã•ã‚“ (Kenji Noguchi) <tokyo246 at gmail dot com>
河内ã•ã‚“ (Takayoshi Kochi) <t-kochi at bq dot jp dot nec dot com>
岩本ã•ã‚“ (iwamoto) <iwamoto.kn at ncos dot nec dot co dot jp>
+ 内田ã•ã‚“ (Satoshi Uchida) <s-uchida at ap dot jp dot nec dot com>
==================================
Linux カーãƒãƒ«é–‹ç™ºã®ã‚„ã‚Šæ–¹
@@ -40,7 +41,7 @@ Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«æ´»å‹•ã™ã‚‹ã‚„り方を学ã
手助ã‘ã«ãªã‚Šã¾ã™ã€‚
ã‚‚ã—ã€ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®ã©ã“ã‹ãŒå¤ããªã£ã¦ã„ãŸå ´åˆã«ã¯ã€ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³
-トã®æœ€å¾Œã«ãƒªã‚¹ãƒˆã—ãŸãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼ã«ãƒ‘ッãƒã‚’é€ã£ã¦ãã ã•ã„。
+トã®æœ€å¾Œã«ãƒªã‚¹ãƒˆã—ãŸãƒ¡ãƒ³ãƒ†ãƒŠã«ãƒ‘ッãƒã‚’é€ã£ã¦ãã ã•ã„。
ã¯ã˜ã‚ã«
---------
@@ -59,7 +60,7 @@ Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«æ´»å‹•ã™ã‚‹ã‚„り方を学ã
ãƒãƒ«é–‹ç™ºè€…ã«ã¯å¿…è¦ã§ã™ã€‚アーキテクãƒãƒ£å‘ã‘ã®ä½Žãƒ¬ãƒ™ãƒ«éƒ¨åˆ†ã®é–‹ç™ºã‚’ã™ã‚‹ã®
ã§ãªã‘ã‚Œã°ã€(ã©ã‚“ãªã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ã§ã‚‚)アセンブリ(訳注: 言語)ã¯å¿…è¦ã‚ã‚Š
ã¾ã›ã‚“。以下ã®æœ¬ã¯ã€C 言語ã®å分ãªçŸ¥è­˜ã‚„何年もã®çµŒé¨“ã«å–ã£ã¦ä»£ã‚ã‚‹ã‚‚ã®
-ã§ã¯ã‚ã‚Šã¾ã›ã‚“ãŒã€å°‘ãªãã¨ã‚‚リファレンスã¨ã—ã¦ã¯ã„ã„本ã§ã™ã€‚
+ã§ã¯ã‚ã‚Šã¾ã›ã‚“ãŒã€å°‘ãªãã¨ã‚‚リファレンスã¨ã—ã¦ã¯è‰¯ã„本ã§ã™ã€‚
- "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
-『プログラミング言語C第2版ã€(B.W. カーニãƒãƒ³/D.M. リッãƒãƒ¼è‘— 石田晴久訳) [共立出版]
- "Practical C Programming" by Steve Oualline [O'Reilly]
@@ -76,7 +77,7 @@ Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«æ´»å‹•ã™ã‚‹ã‚„り方を学ã
ã¨ãã©ãã€ã‚«ãƒ¼ãƒãƒ«ãŒãƒ„ールãƒã‚§ã‚¤ãƒ³ã‚„ C 言語拡張ã«ç½®ã„ã¦ã„ã‚‹å‰æãŒã©ã†
ãªã£ã¦ã„ã‚‹ã®ã‹ã‚ã‹ã‚Šã«ãã„ã“ã¨ãŒã‚ã‚Šã€ã¾ãŸã€æ®‹å¿µãªã“ã¨ã«æ±ºå®šçš„ãªãƒªãƒ•ã‚¡
レンスã¯å­˜åœ¨ã—ã¾ã›ã‚“。情報を得るã«ã¯ã€gcc ã® info ページ( info gcc )ã‚’
-ã¿ã¦ãã ã•ã„。
+見ã¦ãã ã•ã„。
ã‚ãªãŸã¯æ—¢å­˜ã®é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¸€ç·’ã«ä½œæ¥­ã™ã‚‹æ–¹æ³•ã‚’å­¦ã¼ã†ã¨ã—ã¦ã„ã‚‹ã“
ã¨ã«ç•™æ„ã—ã¦ãã ã•ã„。ãã®ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã€ã‚¹ã‚¿ã‚¤ãƒ«ã€
@@ -92,7 +93,7 @@ Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«æ´»å‹•ã™ã‚‹ã‚„り方を学ã
Linux カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã¯ GPL ライセンスã®ä¸‹ã§ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¦ã„ã¾
ã™ã€‚ライセンスã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€ã‚½ãƒ¼ã‚¹ãƒ„リーã®ãƒ¡ã‚¤ãƒ³ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å­˜åœ¨
-ã™ã‚‹ã€COPYING ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ã¿ã¦ãã ã•ã„。もã—ライセンスã«ã¤ã„ã¦ã•ã‚‰ã«è³ª
+ã™ã‚‹ã€COPYING ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’見ã¦ãã ã•ã„。もã—ライセンスã«ã¤ã„ã¦ã•ã‚‰ã«è³ª
å•ãŒã‚ã‚Œã°ã€Linux Kernel メーリングリストã«è³ªå•ã™ã‚‹ã®ã§ã¯ãªãã€ã©ã†ãž
法律家ã«ç›¸è«‡ã—ã¦ãã ã•ã„。メーリングリストã®äººé”ã¯æ³•å¾‹å®¶ã§ã¯ãªãã€æ³•çš„
å•é¡Œã«ã¤ã„ã¦ã¯å½¼ã‚‰ã®å£°æ˜Žã¯ã‚ã¦ã«ã™ã‚‹ã¹ãã§ã¯ã‚ã‚Šã¾ã›ã‚“。
@@ -109,7 +110,8 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã¯å¹…広ã„範囲ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’å
æ–°ã—ã„ドキュメントファイルも追加ã™ã‚‹ã“ã¨ã‚’勧ã‚ã¾ã™ã€‚
カーãƒãƒ«ã®å¤‰æ›´ãŒã€ã‚«ãƒ¼ãƒãƒ«ãŒãƒ¦ãƒ¼ã‚¶ç©ºé–“ã«å…¬é–‹ã—ã¦ã„るインターフェイスã®
変更を引ãèµ·ã“ã™å ´åˆã€ãã®å¤‰æ›´ã‚’説明ã™ã‚‹ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ãƒšãƒ¼ã‚¸ã®ãƒ‘ッãƒã‚„情報
-をマニュアルページã®ãƒ¡ãƒ³ãƒ†ãƒŠ mtk-manpages@gmx.net ã«é€ã‚‹ã“ã¨ã‚’勧ã‚ã¾ã™ã€‚
+をマニュアルページã®ãƒ¡ãƒ³ãƒ†ãƒŠ mtk-manpages@gmx.net ã«é€ã‚‹ã“ã¨ã‚’勧ã‚ã¾
+ã™ã€‚
以下ã¯ã‚«ãƒ¼ãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã«å«ã¾ã‚Œã¦ã„る読んã§ãŠãã¹ãファイルã®ä¸€è¦§ã§
ã™-
@@ -117,7 +119,7 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã¯å¹…広ã„範囲ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’å
README
ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ Linuxカーãƒãƒ«ã®ç°¡å˜ãªèƒŒæ™¯ã¨ã‚«ãƒ¼ãƒãƒ«ã‚’設定(訳注
configure )ã—ã€ç”Ÿæˆ(訳注 build )ã™ã‚‹ãŸã‚ã«å¿…è¦ãªã“ã¨ã¯ä½•ã‹ãŒæ›¸ã‹ã‚Œ
- ã¦ã„ã¾ã™ã€‚カーãƒãƒ«ã«é–¢ã—ã¦åˆã‚ã¦ã®äººã¯ã“ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã™ã‚‹ã¨ã‚ˆã„ã§
+ ã¦ã„ã¾ã™ã€‚カーãƒãƒ«ã«é–¢ã—ã¦åˆã‚ã¦ã®äººã¯ã“ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã™ã‚‹ã¨è‰¯ã„ã§
ã—ょã†ã€‚
Documentation/Changes
@@ -128,7 +130,7 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã¯å¹…広ã„範囲ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’å
Documentation/CodingStyle
ã“れ㯠Linux カーãƒãƒ«ã®ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã‚¹ã‚¿ã‚¤ãƒ«ã¨èƒŒæ™¯ã«ã‚ã‚‹ç†ç”±ã‚’記述
ã—ã¦ã„ã¾ã™ã€‚å…¨ã¦ã®æ–°ã—ã„コードã¯ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã«ã‚るガイドライン
- ã«å¾“ã£ã¦ã„ã‚‹ã“ã¨ã‚’期待ã•ã‚Œã¦ã„ã¾ã™ã€‚大部分ã®ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼ã¯ã“れらã®ãƒ«ãƒ¼
+ ã«å¾“ã£ã¦ã„ã‚‹ã“ã¨ã‚’期待ã•ã‚Œã¦ã„ã¾ã™ã€‚大部分ã®ãƒ¡ãƒ³ãƒ†ãƒŠã¯ã“れらã®ãƒ«ãƒ¼
ルã«å¾“ã£ã¦ã„ã‚‹ã‚‚ã®ã ã‘ã‚’å—ã‘付ã‘ã€å¤šãã®äººã¯æ­£ã—ã„スタイルã®ã‚³ãƒ¼ãƒ‰
ã ã‘をレビューã—ã¾ã™ã€‚
@@ -168,16 +170,16 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã¯å¹…広ã„範囲ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’å
支æ´ã—ã¦ãã ã•ã„。
Documentation/ManagementStyle
- ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ Linux カーãƒãƒ«ã®ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”ãŒã©ã†è¡Œå‹•ã™ã‚‹ã‹ã€
+ ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ Linux カーãƒãƒ«ã®ãƒ¡ãƒ³ãƒ†ãƒŠé”ãŒã©ã†è¡Œå‹•ã™ã‚‹ã‹ã€
彼らã®æ‰‹æ³•ã®èƒŒæ™¯ã«ã‚る共有ã•ã‚Œã¦ã„る精神ã«ã¤ã„ã¦è¨˜è¿°ã—ã¦ã„ã¾ã™ã€‚ã“
ã‚Œã¯ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºã®åˆå¿ƒè€…ãªã‚‰ï¼ˆã‚‚ã—ãã¯ã€å˜ã«èˆˆå‘³ãŒã‚ã‚‹ã ã‘ã®äººã§ã‚‚)
- é‡è¦ã§ã™ã€‚ãªãœãªã‚‰ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ã€ã‚«ãƒ¼ãƒãƒ«ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”ã®ç‹¬ç‰¹ãª
+ é‡è¦ã§ã™ã€‚ãªãœãªã‚‰ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ã€ã‚«ãƒ¼ãƒãƒ«ãƒ¡ãƒ³ãƒ†ãƒŠé”ã®ç‹¬ç‰¹ãª
行動ã«ã¤ã„ã¦ã®å¤šãã®èª¤è§£ã‚„混乱を解消ã™ã‚‹ã‹ã‚‰ã§ã™ã€‚
Documentation/stable_kernel_rules.txt
ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã©ã®ã‚ˆã†ã« stable カーãƒãƒ«ã®ãƒªãƒªãƒ¼ã‚¹ãŒè¡Œã‚れるã‹ã®ãƒ«ãƒ¼
ルãŒè¨˜è¿°ã•ã‚Œã¦ã„ã¾ã™ã€‚ãã—ã¦ã“れらã®ãƒªãƒªãƒ¼ã‚¹ã®ä¸­ã®ã©ã“ã‹ã§å¤‰æ›´ã‚’å–
- り入れã¦ã‚‚らã„ãŸã„å ´åˆã«ä½•ã‚’ã™ã‚Œã°ã„ã„ã‹ãŒç¤ºã•ã‚Œã¦ã„ã¾ã™ã€‚
+ り入れã¦ã‚‚らã„ãŸã„å ´åˆã«ä½•ã‚’ã™ã‚Œã°è‰¯ã„ã‹ãŒç¤ºã•ã‚Œã¦ã„ã¾ã™ã€‚
Documentation/kernel-docs.txt
  カーãƒãƒ«é–‹ç™ºã«ä»˜éšã™ã‚‹å¤–部ドキュメントã®ãƒªã‚¹ãƒˆã§ã™ã€‚ã‚‚ã—ã‚ãªãŸãŒ
@@ -218,9 +220,9 @@ web サイトã«ã¯ã€ã‚³ãƒ¼ãƒ‰ã®æ§‹æˆã€ã‚µãƒ–システムã€ç¾åœ¨å­˜åœ¨ã™ã
ã“ã“ã«ã¯ã€ã¾ãŸã€ã‚«ãƒ¼ãƒãƒ«ã®ã‚³ãƒ³ãƒ‘イルã®ã‚„り方やパッãƒã®å½“ã¦æ–¹ãªã©ã®é–“接
çš„ãªåŸºæœ¬æƒ…報も記述ã•ã‚Œã¦ã„ã¾ã™ã€‚
-ã‚ãªãŸãŒã©ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ã¦ã‚ˆã„ã‹ã‚ã‹ã‚‰ãªã„ãŒã€Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥
+ã‚ãªãŸãŒã©ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ã¦è‰¯ã„ã‹ã‚ã‹ã‚‰ãªã„ãŒã€Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥
ニティã«å‚加ã—ã¦ä½•ã‹ã™ã‚‹ã“ã¨ã‚’ã•ãŒã—ã¦ã„ã‚‹å ´åˆã«ã¯ã€Linux kernel
-Janitor's プロジェクトã«ã„ã‘ã°ã‚ˆã„ã§ã—ょㆠ-
+Janitor's プロジェクトã«ã„ã‘ã°è‰¯ã„ã§ã—ょㆠ-
http://janitor.kernelnewbies.org/
ã“ã“ã¯ãã®ã‚ˆã†ãªã‚¹ã‚¿ãƒ¼ãƒˆã‚’ã™ã‚‹ã®ã«ã†ã£ã¦ã¤ã‘ã®å ´æ‰€ã§ã™ã€‚ã“ã“ã«ã¯ã€
Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ä¸­ã«å«ã¾ã‚Œã‚‹ã€ãã‚Œã„ã«ã—ã€ä¿®æ­£ã—ãªã‘ã‚Œã°ãª
@@ -243,7 +245,7 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ä¸­ã«å«ã¾ã‚Œã‚‹ã€ãã‚Œã„ã«ã—ã€ä¿
自己å‚照方å¼ã§ã€ç´¢å¼•ãŒã¤ã„㟠web å½¢å¼ã§ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‚’å‚ç…§ã™ã‚‹ã“ã¨ãŒ
ã§ãã¾ã™ã€‚ã“ã®æœ€æ–°ã®ç´ æ™´ã—ã„カーãƒãƒ«ã‚³ãƒ¼ãƒ‰ã®ãƒªãƒã‚¸ãƒˆãƒªã¯ä»¥ä¸‹ã§è¦‹ã¤ã‹ã‚Š
ã¾ã™-
- http://sosdg.org/~coywolf/lxr/
+ http://sosdg.org/~qiyong/lxr/
開発プロセス
-----------------------
@@ -265,9 +267,9 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ã‚
以下ã®ã¨ãŠã‚Š-
- æ–°ã—ã„カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚ŒãŸç›´å¾Œã«ã€2週間ã®ç‰¹åˆ¥æœŸé–“ãŒè¨­ã‘られã€
- ã“ã®æœŸé–“中ã«ã€ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”㯠Linus ã«å¤§ããªå·®åˆ†ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾
- ã™ã€‚ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -mm カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§
- ã™ã€‚ 大ããªå¤‰æ›´ã¯ git(カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ç®¡ç†ãƒ„ールã€è©³ç´°ã¯
+ ã“ã®æœŸé–“中ã«ã€ãƒ¡ãƒ³ãƒ†ãƒŠé”㯠Linus ã«å¤§ããªå·®åˆ†ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
+ ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -mm カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§ã™ã€‚
+ 大ããªå¤‰æ›´ã¯ git(カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ç®¡ç†ãƒ„ールã€è©³ç´°ã¯
http://git.or.cz/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„ã‚„ã‚Šæ–¹ã§ã™ãŒã€ãƒ‘ッ
ãƒãƒ•ã‚¡ã‚¤ãƒ«ã®å½¢å¼ã®ã¾ã¾é€ã‚‹ã®ã§ã‚‚å分ã§ã™ã€‚
@@ -285,6 +287,10 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ã‚
ã«å®‰å®šã—ãŸçŠ¶æ…‹ã«ã‚ã‚‹ã¨åˆ¤æ–­ã—ãŸã¨ãã«ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¾ã™ã€‚目標ã¯æ¯Žé€±æ–°
ã—ã„ -rc カーãƒãƒ«ã‚’リリースã™ã‚‹ã“ã¨ã§ã™ã€‚
+ - 以下㮠URL ã§å„ -rc リリースã«å­˜åœ¨ã™ã‚‹æ—¢çŸ¥ã®å¾Œæˆ»ã‚Šå•é¡Œã®ãƒªã‚¹ãƒˆ
+ ãŒè¿½è·¡ã•ã‚Œã¾ã™-
+ http://kernelnewbies.org/known_regressions
+
- ã“ã®ãƒ—ロセスã¯ã‚«ãƒ¼ãƒãƒ«ãŒ 「準備ãŒã§ããŸã€ã¨è€ƒãˆã‚‰ã‚Œã‚‹ã¾ã§ç¶™ç¶šã—ã¾
ã™ã€‚ã“ã®ãƒ—ロセスã¯ã ã„ãŸã„ 6週間継続ã—ã¾ã™ã€‚
@@ -331,8 +337,8 @@ Andrew ã¯å€‹åˆ¥ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒã‚’å…¨ã¦é
linux-kernel メーリングリストã§åŽé›†ã•ã‚ŒãŸå¤šæ•°ã®ãƒ‘ッãƒã¨åŒæ™‚ã«ä¸€ã¤ã«ã¾
ã¨ã‚ã¾ã™ã€‚
ã“ã®ãƒ„リーã¯æ–°æ©Ÿèƒ½ã¨ãƒ‘ッãƒãŒæ¤œè¨¼ã•ã‚Œã‚‹å ´ã¨ãªã‚Šã¾ã™ã€‚ã‚る期間ã®é–“パッãƒ
-㌠-mm ã«å…¥ã£ã¦ä¾¡å€¤ã‚’証明ã•ã‚ŒãŸã‚‰ã€Andrew やサブシステムメンテナãŒã€ãƒ¡
-インラインã¸å…¥ã‚Œã‚‹ã‚ˆã†ã« Linus ã«ãƒ—ッシュã—ã¾ã™ã€‚
+㌠-mm ã«å…¥ã£ã¦ä¾¡å€¤ã‚’証明ã•ã‚ŒãŸã‚‰ã€Andrew やサブシステムメンテナãŒã€
+メインラインã¸å…¥ã‚Œã‚‹ã‚ˆã†ã« Linus ã«ãƒ—ッシュã—ã¾ã™ã€‚
メインカーãƒãƒ«ãƒ„リーã«å«ã‚ã‚‹ãŸã‚ã« Linus ã«é€ã‚‹å‰ã«ã€ã™ã¹ã¦ã®æ–°ã—ã„パッ
ãƒãŒ -mm ツリーã§ãƒ†ã‚¹ãƒˆã•ã‚Œã‚‹ã“ã¨ãŒå¼·ã推奨ã•ã‚Œã¾ã™ã€‚
@@ -460,7 +466,7 @@ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™ã®ã§å‚ç…§ã—ã¦ãã ã•ã
ã›ã‚“-
彼らã¯ã‚ãªãŸã®ãƒ‘ッãƒã®è¡Œæ¯Žã«ã‚³ãƒ¡ãƒ³ãƒˆã‚’入れãŸã„ã®ã§ã€ãã®ãŸã‚ã«ã¯ãã†ã™
ã‚‹ã—ã‹ã‚ã‚Šã¾ã›ã‚“。ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ãƒ—ログラムãŒç©ºç™½ã‚„タブを圧縮ã—ãªã„よã†
-ã«ç¢ºèªã—ãŸæ–¹ãŒã„ã„ã§ã™ã€‚最åˆã®è‰¯ã„テストã¨ã—ã¦ã¯ã€è‡ªåˆ†ã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ã£ã¦
+ã«ç¢ºèªã—ãŸæ–¹ãŒè‰¯ã„ã§ã™ã€‚最åˆã®è‰¯ã„テストã¨ã—ã¦ã¯ã€è‡ªåˆ†ã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ã£ã¦
ã¿ã¦ã€ãã®ãƒ‘ッãƒã‚’自分ã§å½“ã¦ã¦ã¿ã‚‹ã“ã¨ã§ã™ã€‚ã‚‚ã—ãã‚ŒãŒã†ã¾ãè¡Œã‹ãªã„ãª
らã€ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ãƒ—ログラムを直ã—ã¦ã‚‚らã†ã‹ã€æ­£ã—ãå‹•ãよã†ã«å¤‰ãˆã‚‹ã¹
ãã§ã™ã€‚
@@ -507,14 +513,14 @@ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™ã®ã§å‚ç…§ã—ã¦ãã ã•ã
ã¨ã‚‚普通ã®ã“ã¨ã§ã™ã€‚ã“ã‚Œã¯ã‚ãªãŸã®ãƒ‘ッãƒãŒå—ã‘入れられãªã„ã¨ã„ã†ã“ã¨ã§
㯠*ã‚ã‚Šã¾ã›ã‚“*ã€ãã—ã¦ã‚ãªãŸè‡ªèº«ã«å対ã™ã‚‹ã“ã¨ã‚’æ„味ã™ã‚‹ã®ã§ã‚‚ *ã‚ã‚Šã¾
ã›ã‚“*。å˜ã«è‡ªåˆ†ã®ãƒ‘ッãƒã«å¯¾ã—ã¦æŒ‡æ‘˜ã•ã‚ŒãŸå•é¡Œã‚’å…¨ã¦ä¿®æ­£ã—ã¦å†é€ã™ã‚Œã°
-ã„ã„ã®ã§ã™ã€‚
+良ã„ã®ã§ã™ã€‚
カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¼æ¥­çµ„ç¹”ã®ã¡ãŒã„
-----------------------------------------------------------------
カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯å¤§éƒ¨åˆ†ã®ä¼çµ±çš„ãªä¼šç¤¾ã®é–‹ç™ºç’°å¢ƒã¨ã¯ç•°ã£ãŸã‚„ã‚Šæ–¹ã§
-å‹•ã„ã¦ã„ã¾ã™ã€‚以下ã¯å•é¡Œã‚’é¿ã‘ã‚‹ãŸã‚ã«ã§ãã‚‹ã¨ã‚ˆã„ã“ã¨ã®ã®ãƒªã‚¹ãƒˆã§ã™-
+å‹•ã„ã¦ã„ã¾ã™ã€‚以下ã¯å•é¡Œã‚’é¿ã‘ã‚‹ãŸã‚ã«ã§ãã‚‹ã¨è‰¯ã„ã“ã¨ã®ãƒªã‚¹ãƒˆã§ã™-
ã‚ãªãŸã®æ案ã™ã‚‹å¤‰æ›´ã«ã¤ã„ã¦è¨€ã†ã¨ãã®ã†ã¾ã„言ã„方:
@@ -525,7 +531,7 @@ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™ã®ã§å‚ç…§ã—ã¦ãã ã•ã
- "以下ã¯ä¸€é€£ã®å°ã•ãªãƒ‘ッãƒç¾¤ã§ã™ãŒ..."
- "ã“ã‚Œã¯å…¸åž‹çš„ãªãƒžã‚·ãƒ³ã§ã®æ€§èƒ½ã‚’å‘上ã•ã›ã¾ã™.."
- ã‚„ã‚ãŸæ–¹ãŒã„ã„悪ã„言ã„方:
+ ã‚„ã‚ãŸæ–¹ãŒè‰¯ã„悪ã„言ã„方:
- ã“ã®ã‚„り方㧠AIX/ptx/Solaris ã§ã¯ã§ããŸã®ã§ã€ã§ãã‚‹ã¯ãšã 
- ç§ã¯ã“れを20å¹´ã‚‚ã®é–“ã‚„ã£ã¦ããŸã€ã ã‹ã‚‰
@@ -575,10 +581,10 @@ Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’å–
1) å°ã•ã„パッãƒã¯ã‚ãªãŸã®ãƒ‘ッãƒãŒé©ç”¨ã•ã‚Œã‚‹è¦‹è¾¼ã¿ã‚’大ããã—ã¾ã™ã€ã‚«ãƒ¼
ãƒãƒ«ã®äººé”ã¯ãƒ‘ッãƒãŒæ­£ã—ã„ã‹ã©ã†ã‹ã‚’確èªã™ã‚‹æ™‚間や労力をã‹ã‘ãªã„ã‹
- らã§ã™ã€‚5è¡Œã®ãƒ‘ッãƒã¯ãƒ¡ãƒ³ãƒ†ãƒŠãŒãŸã£ãŸ1秒見るã ã‘ã§é©ç”¨ã§ãã¾ã™ã€‚ã—
- ã‹ã—ã€500è¡Œã®ãƒ‘ッãƒã¯ã€æ­£ã—ã„ã“ã¨ã‚’レビューã™ã‚‹ã®ã«æ•°æ™‚é–“ã‹ã‹ã‚‹ã‹ã‚‚
- ã—ã‚Œã¾ã›ã‚“(時間ã¯ãƒ‘ッãƒã®ã‚µã‚¤ã‚ºãªã©ã«ã‚ˆã‚ŠæŒ‡æ•°é–¢æ•°ã«æ¯”例ã—ã¦ã‹ã‹ã‚Šã¾
- ã™)
+ らã§ã™ã€‚5è¡Œã®ãƒ‘ッãƒã¯ãƒ¡ãƒ³ãƒ†ãƒŠãŒãŸã£ãŸ1秒見るã ã‘ã§é©ç”¨ã§ãã¾ã™ã€‚
+ ã—ã‹ã—ã€500è¡Œã®ãƒ‘ッãƒã¯ã€æ­£ã—ã„ã“ã¨ã‚’レビューã™ã‚‹ã®ã«æ•°æ™‚é–“ã‹ã‹ã‚‹ã‹
+ ã‚‚ã—ã‚Œã¾ã›ã‚“(時間ã¯ãƒ‘ッãƒã®ã‚µã‚¤ã‚ºãªã©ã«ã‚ˆã‚ŠæŒ‡æ•°é–¢æ•°ã«æ¯”例ã—ã¦ã‹ã‹ã‚Š
+ ã¾ã™)
å°ã•ã„パッãƒã¯ä½•ã‹ã‚ã£ãŸã¨ãã«ãƒ‡ãƒãƒƒã‚°ã‚‚ã¨ã¦ã‚‚ç°¡å˜ã«ãªã‚Šã¾ã™ã€‚パッ
ãƒã‚’1個1個å–り除ãã®ã¯ã€ã¨ã¦ã‚‚大ããªãƒ‘ッãƒã‚’当ã¦ãŸå¾Œã«(ã‹ã¤ã€ä½•ã‹ãŠ
@@ -587,23 +593,23 @@ Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’å–
2) å°ã•ã„パッãƒã‚’é€ã‚‹ã ã‘ã§ãªãã€é€ã‚‹ã¾ãˆã«ã€æ›¸ãç›´ã—ã¦ã€ã‚·ãƒ³ãƒ—ルã«ã™
ã‚‹(ã‚‚ã—ãã¯ã€å˜ã«é †ç•ªã‚’変ãˆã‚‹ã ã‘ã§ã‚‚)ã“ã¨ã‚‚ã€ã¨ã¦ã‚‚é‡è¦ã§ã™ã€‚
-以下ã¯ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã® Al Viro ã®ãŸã¨ãˆè©±ã—ã§ã™ï¼š
+以下ã¯ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã® Al Viro ã®ãŸã¨ãˆè©±ã§ã™ï¼š
"生徒ã®æ•°å­¦ã®å®¿é¡Œã‚’採点ã™ã‚‹å…ˆç”Ÿã®ã“ã¨ã‚’考ãˆã¦ã¿ã¦ãã ã•ã„ã€å…ˆ
- 生ã¯ç”Ÿå¾’ãŒè§£ã«åˆ°é”ã™ã‚‹ã¾ã§ã®è©¦è¡ŒéŒ¯èª¤ã‚’ã¿ãŸã„ã¨ã¯æ€ã‚ãªã„ã§ã—ょ
- ã†ã€‚先生ã¯ç°¡æ½”ãªæœ€é«˜ã®è§£ã‚’ã¿ãŸã„ã®ã§ã™ã€‚良ã„生徒ã¯ã“れを知ã£ã¦
+ 生ã¯ç”Ÿå¾’ãŒè§£ã«åˆ°é”ã™ã‚‹ã¾ã§ã®è©¦è¡ŒéŒ¯èª¤ã‚’見ãŸã„ã¨ã¯æ€ã‚ãªã„ã§ã—ょ
+ ã†ã€‚先生ã¯ç°¡æ½”ãªæœ€é«˜ã®è§£ã‚’見ãŸã„ã®ã§ã™ã€‚良ã„生徒ã¯ã“れを知ã£ã¦
ãŠã‚Šã€ãã—ã¦æœ€çµ‚解ã®å‰ã®ä¸­é–“作業をæ出ã™ã‚‹ã“ã¨ã¯æ±ºã—ã¦ãªã„ã®ã§
ã™"
- カーãƒãƒ«é–‹ç™ºã§ã‚‚ã“ã‚Œã¯åŒã˜ã§ã™ã€‚メンテナーé”ã¨ãƒ¬ãƒ“ューアé”ã¯ã€
- å•é¡Œã‚’解決ã™ã‚‹è§£ã®èƒŒå¾Œã«ãªã‚‹æ€è€ƒãƒ—ロセスをã¿ãŸã„ã¨ã¯æ€ã„ã¾ã›ã‚“。
- 彼らã¯å˜ç´”ã§ã‚ã–ã‚„ã‹ãªè§£æ±ºæ–¹æ³•ã‚’ã¿ãŸã„ã®ã§ã™ã€‚
+ カーãƒãƒ«é–‹ç™ºã§ã‚‚ã“ã‚Œã¯åŒã˜ã§ã™ã€‚メンテナé”ã¨ãƒ¬ãƒ“ューアé”ã¯ã€
+ å•é¡Œã‚’解決ã™ã‚‹è§£ã®èƒŒå¾Œã«ãªã‚‹æ€è€ƒãƒ—ロセスを見ãŸã„ã¨ã¯æ€ã„ã¾ã›ã‚“。
+ 彼らã¯å˜ç´”ã§ã‚ã–ã‚„ã‹ãªè§£æ±ºæ–¹æ³•ã‚’見ãŸã„ã®ã§ã™ã€‚
ã‚ã–ã‚„ã‹ãªè§£ã‚’説明ã™ã‚‹ã®ã¨ã€ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«ä»•äº‹ã‚’ã—ã€æœªè§£æ±ºã®ä»•äº‹ã‚’
è­°è«–ã™ã‚‹ã“ã¨ã®ãƒãƒ©ãƒ³ã‚¹ã‚’キープã™ã‚‹ã®ã¯é›£ã—ã„ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“。
ã§ã™ã‹ã‚‰ã€é–‹ç™ºãƒ—ロセスã®æ—©æœŸæ®µéšŽã§æ”¹å–„ã®ãŸã‚ã®ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’もらã†ã‚ˆ
-ã†ã«ã™ã‚‹ã®ã‚‚ã„ã„ã§ã™ãŒã€å¤‰æ›´ç‚¹ã‚’å°ã•ã„部分ã«åˆ†å‰²ã—ã¦å…¨ä½“ã§ã¯ã¾ã å®Œæˆã—
-ã¦ã„ãªã„仕事を(部分的ã«)å–り込んã§ã‚‚らãˆã‚‹ã‚ˆã†ã«ã™ã‚‹ã“ã¨ã‚‚ã„ã„ã“ã¨ã§ã™ã€‚
+ã†ã«ã™ã‚‹ã®ã‚‚良ã„ã§ã™ãŒã€å¤‰æ›´ç‚¹ã‚’å°ã•ã„部分ã«åˆ†å‰²ã—ã¦å…¨ä½“ã§ã¯ã¾ã å®Œæˆã—
+ã¦ã„ãªã„仕事を(部分的ã«)å–り込んã§ã‚‚らãˆã‚‹ã‚ˆã†ã«ã™ã‚‹ã“ã¨ã‚‚良ã„ã“ã¨ã§ã™ã€‚
ã¾ãŸã€ã§ã上ãŒã£ã¦ã„ãªã„ã‚‚ã®ã‚„ã€"å°†æ¥ç›´ã™" よã†ãªãƒ‘ッãƒã‚’ã€æœ¬æµã«å«ã‚
ã¦ã‚‚らã†ã‚ˆã†ã«é€ã£ã¦ã‚‚ã€ãã‚Œã¯å—ã‘付ã‘られãªã„ã“ã¨ã‚’ç†è§£ã—ã¦ãã ã•ã„。
@@ -629,7 +635,7 @@ Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’å–
- テストçµæžœ
ã“ã‚Œã«ã¤ã„ã¦å…¨ã¦ãŒã©ã®ã‚ˆã†ã«ã‚ã‚‹ã¹ãã‹ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€ä»¥ä¸‹ã®ãƒ‰ã‚­ãƒ¥ãƒ¡
-ント㮠ChangeLog セクションをã¿ã¦ãã ã•ã„-
+ント㮠ChangeLog セクションを見ã¦ãã ã•ã„-
"The Perfect Patch"
http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a57c1f216b2..085e4a095ea 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -68,6 +68,7 @@ parameter is applicable:
PARIDE The ParIDE (parallel port IDE) subsystem is enabled.
PARISC The PA-RISC architecture is enabled.
PCI PCI bus support is enabled.
+ PCIE PCI Express support is enabled.
PCMCIA The PCMCIA subsystem is enabled.
PNP Plug & Play support is enabled.
PPC PowerPC architecture is enabled.
@@ -864,6 +865,10 @@ and is between 256 and 4096 characters. It is defined in the file
lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip
Format: addr:<io>,irq:<irq>
+ libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume
+ when set.
+ Format: <int>
+
load_ramdisk= [RAM] List of ramdisks to load from floppy
See Documentation/ramdisk.txt.
@@ -1009,6 +1014,10 @@ and is between 256 and 4096 characters. It is defined in the file
meye.*= [HW] Set MotionEye Camera parameters
See Documentation/video4linux/meye.txt.
+ mfgpt_irq= [IA-32] Specify the IRQ to use for the
+ Multi-Function General Purpose Timers on AMD Geode
+ platforms.
+
mga= [HW,DRM]
mousedev.tap_time=
@@ -1074,16 +1083,19 @@ and is between 256 and 4096 characters. It is defined in the file
[NFS] set the maximum lifetime for idmapper cache
entries.
+ nfs.enable_ino64=
+ [NFS] enable 64-bit inode numbers.
+ If zero, the NFS client will fake up a 32-bit inode
+ number for the readdir() and stat() syscalls instead
+ of returning the full 64-bit number.
+ The default is to return 64-bit inode numbers.
+
nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels
no387 [BUGS=X86-32] Tells the kernel to use the 387 maths
emulation library even if a 387 maths coprocessor
is present.
- noacpi [LIBATA] Disables use of ACPI in libata suspend/resume
- when set.
- Format: <int>
-
noaliencache [MM, NUMA, SLAB] Disables the allocation of alien
caches in the slab allocator. Saves per-node memory,
but will impact performance.
@@ -1160,6 +1172,9 @@ and is between 256 and 4096 characters. It is defined in the file
nomce [X86-32] Machine Check Exception
+ nomfgpt [X86-32] Disable Multi-Function General Purpose
+ Timer usage (for AMD Geode machines).
+
noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
@@ -1270,6 +1285,11 @@ and is between 256 and 4096 characters. It is defined in the file
Mechanism 1.
conf2 [X86-32] Force use of PCI Configuration
Mechanism 2.
+ noaer [PCIE] If the PCIEAER kernel config parameter is
+ enabled, this kernel boot option can be used to
+ disable the use of PCIE advanced error reporting.
+ nodomains [PCI] Disable support for multiple PCI
+ root domains (aka PCI segments, in ACPI-speak).
nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI
Configuration
nomsi [MSI] If the PCI_MSI kernel config parameter is
@@ -1314,6 +1334,8 @@ and is between 256 and 4096 characters. It is defined in the file
IRQ routing is enabled.
noacpi [X86-32] Do not use ACPI for IRQ routing
or for PCI scanning.
+ use_crs [X86-32] Use _CRS for PCI resource
+ allocation.
routeirq Do IRQ routing for all PCI devices.
This is normally done in pci_enable_device(),
so this option is a temporary workaround
@@ -1430,6 +1452,10 @@ and is between 256 and 4096 characters. It is defined in the file
pt. [PARIDE]
See Documentation/paride.txt.
+ pty.legacy_count=
+ [KNL] Number of legacy pty's. Overwrites compiled-in
+ default number.
+
quiet [KNL] Disable most log messages
r128= [HW,DRM]
@@ -1864,9 +1890,6 @@ and is between 256 and 4096 characters. It is defined in the file
Format:
<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
- tsdev.xres= [TS] Horizontal screen resolution.
- tsdev.yres= [TS] Vertical screen resolution.
-
turbografx.map[2|3]= [HW,JOY]
TurboGraFX parallel port interface
Format:
diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
index 8ee49ee7c96..ca86a885ad8 100644
--- a/Documentation/kobject.txt
+++ b/Documentation/kobject.txt
@@ -54,7 +54,6 @@ embedded in larger data structures and replace fields they duplicate.
struct kobject {
const char * k_name;
- char name[KOBJ_NAME_LEN];
struct kref kref;
struct list_head entry;
struct kobject * parent;
@@ -223,18 +222,15 @@ decl_subsys(devices, &ktype_device, &device_uevent_ops);
is equivalent to doing:
struct kset devices_subsys = {
- .kobj = {
- .name = "devices",
- },
.ktype = &ktype_devices,
.uevent_ops = &device_uevent_ops,
};
-
+kobject_set_name(&devices_subsys, name);
The objects that are registered with a subsystem that use the
subsystem's default list must have their kset ptr set properly. These
objects may have embedded kobjects or ksets. The
-following helpers make setting the kset easier:
+following helper makes setting the kset easier:
kobj_set_kset_s(obj,subsys)
@@ -242,22 +238,8 @@ kobj_set_kset_s(obj,subsys)
- Assumes that obj->kobj exists, and is a struct kobject.
- Sets the kset of that kobject to the kset <subsys>.
-
-kset_set_kset_s(obj,subsys)
-
-- Assumes that obj->kset exists, and is a struct kset.
-- Sets the kset of the embedded kobject to the kset <subsys>.
-
-subsys_set_kset(obj,subsys)
-
-- Assumes obj->subsys exists, and is a struct subsystem.
-- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset.
-
-void subsystem_init(struct kset *s);
int subsystem_register(struct kset *s);
void subsystem_unregister(struct kset *s);
-struct kset *subsys_get(struct kset *s);
-void kset_put(struct kset *s);
These are just wrappers around the respective kset_* functions.
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 1da56663083..11340625e36 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -281,6 +281,39 @@ downdelay
will be rounded down to the nearest multiple. The default
value is 0.
+fail_over_mac
+
+ Specifies whether active-backup mode should set all slaves to
+ the same MAC address (the traditional behavior), or, when
+ enabled, change the bond's MAC address when changing the
+ active interface (i.e., fail over the MAC address itself).
+
+ Fail over MAC is useful for devices that cannot ever alter
+ their MAC address, or for devices that refuse incoming
+ broadcasts with their own source MAC (which interferes with
+ the ARP monitor).
+
+ The down side of fail over MAC is that every device on the
+ network must be updated via gratuitous ARP, vs. just updating
+ a switch or set of switches (which often takes place for any
+ traffic, not just ARP traffic, if the switch snoops incoming
+ traffic to update its tables) for the traditional method. If
+ the gratuitous ARP is lost, communication may be disrupted.
+
+ When fail over MAC is used in conjuction with the mii monitor,
+ devices which assert link up prior to being able to actually
+ transmit and receive are particularly susecptible to loss of
+ the gratuitous ARP, and an appropriate updelay setting may be
+ required.
+
+ A value of 0 disables fail over MAC, and is the default. A
+ value of 1 enables fail over MAC. This option is enabled
+ automatically if the first slave added cannot change its MAC
+ address. This option may be modified via sysfs only when no
+ slaves are present in the bond.
+
+ This option was added in bonding version 3.2.0.
+
lacp_rate
Option specifying the rate in which we'll ask our link partner
diff --git a/Documentation/networking/proc_net_tcp.txt b/Documentation/networking/proc_net_tcp.txt
index 5e21f7cb638..4a79209e77a 100644
--- a/Documentation/networking/proc_net_tcp.txt
+++ b/Documentation/networking/proc_net_tcp.txt
@@ -1,8 +1,9 @@
This document describes the interfaces /proc/net/tcp and /proc/net/tcp6.
+Note that these interfaces are deprecated in favor of tcp_diag.
These /proc interfaces provide information about currently active TCP
-connections, and are implemented by tcp_get_info() in net/ipv4/tcp_ipv4.c and
-tcp6_get_info() in net/ipv6/tcp_ipv6.c, respectively.
+connections, and are implemented by tcp4_seq_show() in net/ipv4/tcp_ipv4.c
+and tcp6_seq_show() in net/ipv6/tcp_ipv6.c, respectively.
It will first list all listening TCP sockets, and next list all established
TCP connections. A typical entry of /proc/net/tcp would look like this (split
diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX
new file mode 100644
index 00000000000..3a2b96302ec
--- /dev/null
+++ b/Documentation/s390/00-INDEX
@@ -0,0 +1,26 @@
+00-INDEX
+ - this file.
+3270.ChangeLog
+ - ChangeLog for the UTS Global 3270-support patch (outdated).
+3270.txt
+ - how to use the IBM 3270 display system support.
+cds.txt
+ - s390 common device support (common I/O layer).
+CommonIO
+ - common I/O layer command line parameters, procfs and debugfs entries
+config3270.sh
+ - example configuration for 3270 devices.
+DASD
+ - information on the DASD disk device driver.
+Debugging390.txt
+ - hints for debugging on s390 systems.
+driver-model.txt
+ - information on s390 devices and the driver model.
+monreader.txt
+ - information on accessing the z/VM monitor stream from Linux.
+s390dbf.txt
+ - information on using the s390 debug feature.
+TAPE
+ - information on the driver for channel-attached tapes.
+zfcpdump
+ - information on the s390 SCSI dump tool.
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index 22f82f21bc6..86320aa3fb0 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -1,5 +1,5 @@
-S/390 common I/O-Layer - command line parameters and /proc entries
-==================================================================
+S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
+============================================================================
Command line parameters
-----------------------
@@ -7,9 +7,9 @@ Command line parameters
* cio_msg = yes | no
Determines whether information on found devices and sensed device
- characteristics should be shown during startup, i. e. messages of the types
- "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device
- 0.0.4711 reports: ...".
+ characteristics should be shown during startup or when new devices are
+ found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
+ 0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
Default is off.
@@ -26,8 +26,10 @@ Command line parameters
An ignored device can be un-ignored later; see the "/proc entries"-section for
details.
- The devices must be given either as bus ids (0.0.abcd) or as hexadecimal
- device numbers (0xabcd or abcd, for 2.4 backward compatibility).
+ The devices must be given either as bus ids (0.x.abcd) or as hexadecimal
+ device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you
+ give a device number 0xabcd, it will be interpreted as 0.0.abcd.
+
You can use the 'all' keyword to ignore all devices.
The '!' operator will cause the I/O-layer to _not_ ignore a device.
The command line is parsed from left to right.
@@ -81,31 +83,36 @@ Command line parameters
will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
devices.
- The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
- compatibility, by the device number in hexadecimal (0xabcd or abcd).
+ The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
+ compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
+ numbers given as 0xabcd will be interpreted as 0.0.abcd.
+
+* For some of the information present in the /proc filesystem in 2.4 (namely,
+ /proc/subchannels and /proc/chpids), see driver-model.txt.
+ Information formerly in /proc/irq_count is now in /proc/interrupts.
+
+debugfs entries
+---------------
-* /proc/s390dbf/cio_*/ (S/390 debug feature)
+* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature)
Some views generated by the debug feature to hold various debug outputs.
- - /proc/s390dbf/cio_crw/sprintf
+ - /sys/kernel/debug/s390dbf/cio_crw/sprintf
Messages from the processing of pending channel report words (machine check
- handling), which will also show when CONFIG_DEBUG_CRW is defined.
+ handling).
- - /proc/s390dbf/cio_msg/sprintf
- Various debug messages from the common I/O-layer; generally, messages which
- will also show when CONFIG_DEBUG_IO is defined.
+ - /sys/kernel/debug/s390dbf/cio_msg/sprintf
+ Various debug messages from the common I/O-layer, including messages
+ printed when cio_msg=yes.
- - /proc/s390dbf/cio_trace/hex_ascii
+ - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
Logs the calling of functions in the common I/O-layer and, if applicable,
which subchannel they were called for, as well as dumps of some data
structures (like irb in an error case).
The level of logging can be changed to be more or less verbose by piping to
- /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
- the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
-
-* For some of the information present in the /proc filesystem in 2.4 (namely,
- /proc/subchannels and /proc/chpids), see driver-model.txt.
- Information formerly in /proc/irq_count is now in /proc/interrupts.
+ /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
+ documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
+ for details.
diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
index 58919d6a593..3081927cc2d 100644
--- a/Documentation/s390/cds.txt
+++ b/Documentation/s390/cds.txt
@@ -286,10 +286,10 @@ first:
timeout value
-EIO: the common I/O layer terminated the request due to an error state
-If the concurrent sense flag in the extended status word in the irb is set, the
-field irb->scsw.count describes the number of device specific sense bytes
-available in the extended control word irb->scsw.ecw[0]. No device sensing by
-the device driver itself is required.
+If the concurrent sense flag in the extended status word (esw) in the irb is
+set, the field erw.scnt in the esw describes the number of device specific
+sense bytes available in the extended control word irb->scsw.ecw[]. No device
+sensing by the device driver itself is required.
The device interrupt handler can use the following definitions to investigate
the primary unit check source coded in sense byte 0 :
diff --git a/Documentation/sched-design-CFS.txt b/Documentation/sched-design-CFS.txt
index 84901e7c050..88bcb876733 100644
--- a/Documentation/sched-design-CFS.txt
+++ b/Documentation/sched-design-CFS.txt
@@ -117,3 +117,70 @@ Some implementation details:
iterators of the scheduling modules are used. The balancing code got
quite a bit simpler as a result.
+
+Group scheduler extension to CFS
+================================
+
+Normally the scheduler operates on individual tasks and strives to provide
+fair CPU time to each task. Sometimes, it may be desirable to group tasks
+and provide fair CPU time to each such task group. For example, it may
+be desirable to first provide fair CPU time to each user on the system
+and then to each task belonging to a user.
+
+CONFIG_FAIR_GROUP_SCHED strives to achieve exactly that. It lets
+SCHED_NORMAL/BATCH tasks be be grouped and divides CPU time fairly among such
+groups. At present, there are two (mutually exclusive) mechanisms to group
+tasks for CPU bandwidth control purpose:
+
+ - Based on user id (CONFIG_FAIR_USER_SCHED)
+ In this option, tasks are grouped according to their user id.
+ - Based on "cgroup" pseudo filesystem (CONFIG_FAIR_CGROUP_SCHED)
+ This options lets the administrator create arbitrary groups
+ of tasks, using the "cgroup" pseudo filesystem. See
+ Documentation/cgroups.txt for more information about this
+ filesystem.
+
+Only one of these options to group tasks can be chosen and not both.
+
+Group scheduler tunables:
+
+When CONFIG_FAIR_USER_SCHED is defined, a directory is created in sysfs for
+each new user and a "cpu_share" file is added in that directory.
+
+ # cd /sys/kernel/uids
+ # cat 512/cpu_share # Display user 512's CPU share
+ 1024
+ # echo 2048 > 512/cpu_share # Modify user 512's CPU share
+ # cat 512/cpu_share # Display user 512's CPU share
+ 2048
+ #
+
+CPU bandwidth between two users are divided in the ratio of their CPU shares.
+For ex: if you would like user "root" to get twice the bandwidth of user
+"guest", then set the cpu_share for both the users such that "root"'s
+cpu_share is twice "guest"'s cpu_share
+
+
+When CONFIG_FAIR_CGROUP_SCHED is defined, a "cpu.shares" file is created
+for each group created using the pseudo filesystem. See example steps
+below to create task groups and modify their CPU share using the "cgroups"
+pseudo filesystem
+
+ # mkdir /dev/cpuctl
+ # mount -t cgroup -ocpu none /dev/cpuctl
+ # cd /dev/cpuctl
+
+ # mkdir multimedia # create "multimedia" group of tasks
+ # mkdir browser # create "browser" group of tasks
+
+ # #Configure the multimedia group to receive twice the CPU bandwidth
+ # #that of browser group
+
+ # echo 2048 > multimedia/cpu.shares
+ # echo 1024 > browser/cpu.shares
+
+ # firefox & # Launch firefox and move it to "browser" group
+ # echo <firefox_pid> > browser/tasks
+
+ # #Launch gmplayer (or your favourite movie player)
+ # echo <movie_player_pid> > multimedia/tasks
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index 12354830c6b..aa1f7e92783 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -2,14 +2,20 @@
- this file
53c700.txt
- info on driver for 53c700 based adapters
-AM53C974.txt
- - info on driver for AM53c974 based adapters
BusLogic.txt
- info on driver for adapters with BusLogic chips
-ChangeLog
+ChangeLog.1992-1997
- Changes to scsi files, if not listed elsewhere
+ChangeLog.arcmsr
+ - Changes to driver for ARECA's SATA RAID controller cards
ChangeLog.ips
- IBM ServeRAID driver Changelog
+ChangeLog.lpfc
+ - Changes to lpfc driver
+ChangeLog.megaraid
+ - Changes to LSI megaraid controller.
+ChangeLog.megaraid_sas
+ - Changes to serial attached scsi version of LSI megaraid controller.
ChangeLog.ncr53c8xx
- Changes to ncr53c8xx driver
ChangeLog.sym53c8xx
@@ -20,26 +26,44 @@ FlashPoint.txt
- info on driver for BusLogic FlashPoint adapters
LICENSE.FlashPoint
- Licence of the Flashpoint driver
+LICENSE.qla2xxx
+ - License for QLogic Linux Fibre Channel HBA Driver firmware.
Mylex.txt
- info on driver for Mylex adapters
NinjaSCSI.txt
- info on WorkBiT NinjaSCSI-32/32Bi driver
+aacraid.txt
+ - Driver supporting Adaptec RAID controllers
aha152x.txt
- info on driver for Adaptec AHA152x based adapters
+aic79xx.txt
+ - Adaptec Ultra320 SCSI host adapters
aic7xxx.txt
- info on driver for Adaptec controllers
aic7xxx_old.txt
- info on driver for Adaptec controllers, old generation
+arcmsr_spec.txt
+ - ARECA FIRMWARE SPEC (for IOP331 adapter)
+dc395x.txt
+ - README file for the dc395x SCSI driver
dpti.txt
- info on driver for DPT SmartRAID and Adaptec I2O RAID based adapters
dtc3x80.txt
- info on driver for DTC 2x80 based adapters
g_NCR5380.txt
- info on driver for NCR5380 and NCR53c400 based adapters
+hptiop.txt
+ - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
ibmmca.txt
- info on driver for IBM adapters with MCA bus
in2000.txt
- info on in2000 driver
+libsas.txt
+ - Serial Attached SCSI management layer.
+lpfc.txt
+ - LPFC driver release notes
+megaraid.txt
+ - Common Management Module, shared code handling ioctls for LSI drivers
ncr53c7xx.txt
- info on driver for NCR53c7xx based adapters
ncr53c8xx.txt
@@ -50,6 +74,8 @@ ppa.txt
- info on driver for IOmega zip drive
qlogicfas.txt
- info on driver for QLogic FASxxx based adapters
+scsi-changer.txt
+ - README for the SCSI media changer driver
scsi-generic.txt
- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
scsi.txt
@@ -58,6 +84,8 @@ scsi_mid_low_api.txt
- info on API between SCSI layer and low level drivers
scsi_eh.txt
- info on SCSI midlayer error handling infrastructure
+scsi_fc_transport.txt
+ - SCSI Fiber Channel Tansport
st.txt
- info on scsi tape driver
sym53c500_cs.txt
diff --git a/Documentation/scsi/ChangeLog.arcmsr b/Documentation/scsi/ChangeLog.arcmsr
index 162c47fdf45..cd8403a33ee 100644
--- a/Documentation/scsi/ChangeLog.arcmsr
+++ b/Documentation/scsi/ChangeLog.arcmsr
@@ -53,4 +53,19 @@
** for linux standard list
** enable usage of pci message signal interrupt
** follow Randy.Danlup kindness suggestion cleanup this code
-************************************************************************** \ No newline at end of file
+** 1.20.00.14 05/02/2007 Erich Chen & Nick Cheng
+** 1.implement PCI-Express error recovery function and AER capability
+** 2.implement the selection of ARCMSR_MAX_XFER_SECTORS_B=4096
+** if firmware version is newer than 1.42
+** 3.modify arcmsr_iop_reset to improve the ability
+** 4.modify the ISR, arcmsr_interrupt routine,to prevent the
+** inconsistency with sg_mod driver if application directly calls
+** the arcmsr driver w/o passing through scsi mid layer
+** specially thanks to Yanmin Zhang's openhanded help about AER
+** 1.20.00.15 08/30/2007 Erich Chen & Nick Cheng
+** 1. support ARC1200/1201/1202 SATA RAID adapter, which is named
+** ACB_ADAPTER_TYPE_B
+** 2. modify the arcmsr_pci_slot_reset function
+** 3. modify the arcmsr_pci_ers_disconnect_forepart function
+** 4. modify the arcmsr_pci_ers_need_reset_forepart function
+**************************************************************************
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index cc12b55d4b3..a8257840695 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -38,10 +38,8 @@ Supported Cards/Chipsets
9005:0286:9005:02ac Adaptec 1800 (Typhoon44)
9005:0285:9005:02b5 Adaptec 5445 (Voodoo44)
9005:0285:15d9:02b5 SMC AOC-USAS-S4i
- 9005:0285:15d9:02c9 SMC AOC-USAS-S4iR
9005:0285:9005:02b6 Adaptec 5805 (Voodoo80)
9005:0285:15d9:02b6 SMC AOC-USAS-S8i
- 9005:0285:15d9:02ca SMC AOC-USAS-S8iR
9005:0285:9005:02b7 Adaptec 5085 (Voodoo08)
9005:0285:9005:02bb Adaptec 3405 (Marauder40LP)
9005:0285:9005:02bc Adaptec 3805 (Marauder80LP)
@@ -50,9 +48,14 @@ Supported Cards/Chipsets
9005:0285:9005:02be Adaptec 31605 (Marauder160)
9005:0285:9005:02c3 Adaptec 51205 (Voodoo120)
9005:0285:9005:02c4 Adaptec 51605 (Voodoo160)
+ 9005:0285:15d9:02c9 SMC AOC-USAS-S4iR
+ 9005:0285:15d9:02ca SMC AOC-USAS-S8iR
9005:0285:9005:02ce Adaptec 51245 (Voodoo124)
9005:0285:9005:02cf Adaptec 51645 (Voodoo164)
9005:0285:9005:02d0 Adaptec 52445 (Voodoo244)
+ 9005:0285:9005:02d1 Adaptec 5405 (Voodoo40)
+ 9005:0285:15d9:02d2 SMC AOC-USAS-S8i-LP
+ 9005:0285:15d9:02d3 SMC AOC-USAS-S8iR-LP
1011:0046:9005:0364 Adaptec 5400S (Mustang)
9005:0287:9005:0800 Adaptec Themisto (Jupiter)
9005:0200:9005:0200 Adaptec Themisto (Jupiter)
@@ -103,6 +106,7 @@ Supported Cards/Chipsets
9005:0285:108e:7aac SUN STK RAID REM (Voodoo44 Coyote)
9005:0285:108e:0286 SUN STK RAID INT (Cougar)
9005:0285:108e:0287 SUN STK RAID EXT (Prometheus)
+ 9005:0285:108e:7aae SUN STK RAID EM (Narvi)
People
-------------------------
diff --git a/Documentation/scsi/advansys.txt b/Documentation/scsi/advansys.txt
new file mode 100644
index 00000000000..4a3db62b742
--- /dev/null
+++ b/Documentation/scsi/advansys.txt
@@ -0,0 +1,243 @@
+AdvanSys (Advanced System Products, Inc.) manufactures the following
+RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
+(8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
+buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
+transfer) SCSI Host Adapters for the PCI bus.
+
+The CDB counts below indicate the number of SCSI CDB (Command
+Descriptor Block) requests that can be stored in the RISC chip
+cache and board LRAM. A CDB is a single SCSI command. The driver
+detect routine will display the number of CDBs available for each
+adapter detected. The number of CDBs used by the driver can be
+lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
+
+Laptop Products:
+ ABP-480 - Bus-Master CardBus (16 CDB)
+
+Connectivity Products:
+ ABP510/5150 - Bus-Master ISA (240 CDB)
+ ABP5140 - Bus-Master ISA PnP (16 CDB)
+ ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+ ABP902/3902 - Bus-Master PCI (16 CDB)
+ ABP3905 - Bus-Master PCI (16 CDB)
+ ABP915 - Bus-Master PCI (16 CDB)
+ ABP920 - Bus-Master PCI (16 CDB)
+ ABP3922 - Bus-Master PCI (16 CDB)
+ ABP3925 - Bus-Master PCI (16 CDB)
+ ABP930 - Bus-Master PCI (16 CDB)
+ ABP930U - Bus-Master PCI Ultra (16 CDB)
+ ABP930UA - Bus-Master PCI Ultra (16 CDB)
+ ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+ ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+
+Single Channel Products:
+ ABP542 - Bus-Master ISA with floppy (240 CDB)
+ ABP742 - Bus-Master EISA (240 CDB)
+ ABP842 - Bus-Master VL (240 CDB)
+ ABP940 - Bus-Master PCI (240 CDB)
+ ABP940U - Bus-Master PCI Ultra (240 CDB)
+ ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
+ ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+ ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+ ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+ ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+
+Multi-Channel Products:
+ ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
+ ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
+ ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+ ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
+ ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+ ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+ ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
+ ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
+ ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
+
+Driver Compile Time Options and Debugging
+
+The following constants can be defined in the source file.
+
+1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
+
+ Enabling this option adds assertion logic statements to the
+ driver. If an assertion fails a message will be displayed to
+ the console, but the system will continue to operate. Any
+ assertions encountered should be reported to the person
+ responsible for the driver. Assertion statements may proactively
+ detect problems with the driver and facilitate fixing these
+ problems. Enabling assertions will add a small overhead to the
+ execution of the driver.
+
+2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
+
+ Enabling this option adds tracing functions to the driver and the
+ ability to set a driver tracing level at boot time. This option is
+ very useful for debugging the driver, but it will add to the size
+ of the driver execution image and add overhead to the execution of
+ the driver.
+
+ The amount of debugging output can be controlled with the global
+ variable 'asc_dbglvl'. The higher the number the more output. By
+ default the debug level is 0.
+
+ If the driver is loaded at boot time and the LILO Driver Option
+ is included in the system, the debug level can be changed by
+ specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
+ first three hex digits of the pseudo I/O Port must be set to
+ 'deb' and the fourth hex digit specifies the debug level: 0 - F.
+ The following command line will look for an adapter at 0x330
+ and set the debug level to 2.
+
+ linux advansys=0x330,0,0,0,0xdeb2
+
+ If the driver is built as a loadable module this variable can be
+ defined when the driver is loaded. The following insmod command
+ will set the debug level to one.
+
+ insmod advansys.o asc_dbglvl=1
+
+ Debugging Message Levels:
+ 0: Errors Only
+ 1: High-Level Tracing
+ 2-N: Verbose Tracing
+
+ To enable debug output to console, please make sure that:
+
+ a. System and kernel logging is enabled (syslogd, klogd running).
+ b. Kernel messages are routed to console output. Check
+ /etc/syslog.conf for an entry similar to this:
+
+ kern.* /dev/console
+
+ c. klogd is started with the appropriate -c parameter
+ (e.g. klogd -c 8)
+
+ This will cause printk() messages to be be displayed on the
+ current console. Refer to the klogd(8) and syslogd(8) man pages
+ for details.
+
+ Alternatively you can enable printk() to console with this
+ program. However, this is not the 'official' way to do this.
+ Debug output is logged in /var/log/messages.
+
+ main()
+ {
+ syscall(103, 7, 0, 0);
+ }
+
+ Increasing LOG_BUF_LEN in kernel/printk.c to something like
+ 40960 allows more debug messages to be buffered in the kernel
+ and written to the console or log file.
+
+3. ADVANSYS_STATS - Enable statistics (Def: Enabled)
+
+ Enabling this option adds statistics collection and display
+ through /proc to the driver. The information is useful for
+ monitoring driver and device performance. It will add to the
+ size of the driver execution image and add minor overhead to
+ the execution of the driver.
+
+ Statistics are maintained on a per adapter basis. Driver entry
+ point call counts and transfer size counts are maintained.
+ Statistics are only available for kernels greater than or equal
+ to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
+
+ AdvanSys SCSI adapter files have the following path name format:
+
+ /proc/scsi/advansys/{0,1,2,3,...}
+
+ This information can be displayed with cat. For example:
+
+ cat /proc/scsi/advansys/0
+
+ When ADVANSYS_STATS is not defined the AdvanSys /proc files only
+ contain adapter and device configuration information.
+
+Driver LILO Option
+
+If init/main.c is modified as described in the 'Directions for Adding
+the AdvanSys Driver to Linux' section (B.4.) above, the driver will
+recognize the 'advansys' LILO command line and /etc/lilo.conf option.
+This option can be used to either disable I/O port scanning or to limit
+scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
+PCI boards will still be searched for and detected. This option only
+affects searching for ISA and VL boards.
+
+Examples:
+ 1. Eliminate I/O port scanning:
+ boot: linux advansys=
+ or
+ boot: linux advansys=0x0
+ 2. Limit I/O port scanning to one I/O port:
+ boot: linux advansys=0x110
+ 3. Limit I/O port scanning to four I/O ports:
+ boot: linux advansys=0x110,0x210,0x230,0x330
+
+For a loadable module the same effect can be achieved by setting
+the 'asc_iopflag' variable and 'asc_ioport' array when loading
+the driver, e.g.
+
+ insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
+
+If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
+I/O Port may be added to specify the driver debug level. Refer to
+the 'Driver Compile Time Options and Debugging' section above for
+more information.
+
+Credits (Chronological Order)
+
+Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
+and maintained it up to 3.3F. He continues to answer questions
+and help maintain the driver.
+
+Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
+basis for the Linux v1.3.X changes which were included in the
+1.2 release.
+
+Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
+in advansys_biosparam() which was fixed in the 1.3 release.
+
+Erik Ratcliffe <erik@caldera.com> has done testing of the
+AdvanSys driver in the Caldera releases.
+
+Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+AscWaitTixISRDone() which he found necessary to make the
+driver work with a SCSI-1 disk.
+
+Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
+support in the 3.1A driver.
+
+Doug Gilbert <dgilbert@interlog.com> has made changes and
+suggestions to improve the driver and done a lot of testing.
+
+Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
+in 3.2K.
+
+Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
+patch and helped with PowerPC wide and narrow board support.
+
+Philip Blundell <philb@gnu.org> provided an
+advansys_interrupts_enabled patch.
+
+Dave Jones <dave@denial.force9.co.uk> reported the compiler
+warnings generated when CONFIG_PROC_FS was not defined in
+the 3.2M driver.
+
+Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
+problems) for wide cards.
+
+Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
+card error handling.
+
+Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
+board support and fixed a bug in AscGetEEPConfig().
+
+Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
+save_flags/restore_flags changes.
+
+Andy Kellner <AKellner@connectcom.net> continued the Advansys SCSI
+driver development for ConnectCom (Version > 3.3F).
+
+Ken Witherow for extensive testing during the development of version 3.4.
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
index 8418d35484f..eb1e28ad882 100644
--- a/Documentation/sparc/sbus_drivers.txt
+++ b/Documentation/sparc/sbus_drivers.txt
@@ -67,10 +67,12 @@ probe in an SBUS driver under Linux:
MODULE_DEVICE_TABLE(of, mydevice_match);
static struct of_platform_driver mydevice_driver = {
- .name = "mydevice",
.match_table = mydevice_match,
.probe = mydevice_probe,
.remove = __devexit_p(mydevice_remove),
+ .driver = {
+ .name = "mydevice",
+ },
};
static int __init mydevice_init(void)
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
new file mode 100644
index 00000000000..2af40060949
--- /dev/null
+++ b/Documentation/usb/authorization.txt
@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+ echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+ echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+ echo 1 > authorized # temporarily authorize it
+ # FIXME: make sure none can mount it
+ mount DEVICENODE /mntpoint
+ sum=$(md5sum /mntpoint/.signature)
+ if [ $sum = $(cat /etc/lockdown/keysum) ]
+ then
+ echo "We are good, connected"
+ umount /mntpoint
+ # Other stuff so others can use it
+ else
+ echo 0 > authorized
+ fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
new file mode 100644
index 00000000000..97842deec47
--- /dev/null
+++ b/Documentation/usb/power-management.txt
@@ -0,0 +1,517 @@
+ Power Management for USB
+
+ Alan Stern <stern@rowland.harvard.edu>
+
+ October 5, 2007
+
+
+
+ What is Power Management?
+ -------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used. While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely. A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it. (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate. This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend". When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend"). This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled. System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+ What is Remote Wakeup?
+ ----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to. Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume. This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup". When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event. Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+ When is a USB device idle?
+ --------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended. The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place. (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+ Forms of dynamic PM
+ -------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device. Automatic suspend is called "autosuspend" for
+short. In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly. If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume). For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend. In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count). If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended. In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal. External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device). Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+ The user interface for dynamic PM
+ ---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+ power/wakeup
+
+ This file is empty if the device does not support
+ remote wakeup. Otherwise the file contains either the
+ word "enabled" or the word "disabled", and you can
+ write those words to the file. The setting determines
+ whether or not remote wakeup will be enabled when the
+ device is next suspended. (If the setting is changed
+ while the device is suspended, the change won't take
+ effect until the following suspend.)
+
+ power/level
+
+ This file contains one of three words: "on", "auto",
+ or "suspend". You can write those words to the file
+ to change the device's setting.
+
+ "on" means that the device should be resumed and
+ autosuspend is not allowed. (Of course, system
+ suspends are still allowed.)
+
+ "auto" is the normal state in which the kernel is
+ allowed to autosuspend and autoresume the device.
+
+ "suspend" means that the device should remain
+ suspended, and autoresume is not allowed. (But remote
+ wakeup may still be allowed, since it is controlled
+ separately by the power/wakeup attribute.)
+
+ power/autosuspend
+
+ This file contains an integer value, which is the
+ number of seconds the device should remain idle before
+ the kernel will autosuspend it (the idle-delay time).
+ The default is 2. 0 means to autosuspend as soon as
+ the device becomes idle, and -1 means never to
+ autosuspend. You can write a number to the file to
+ change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended. Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22. The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+ Changing the default idle-delay time
+ ------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore. You can specify the value when usbcore is
+loaded. For example, to set it to 5 seconds instead of 2 you would
+do:
+
+ modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+ options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image. To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+ usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running. If you do:
+
+ echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5. (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device. This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+ Warnings
+ --------
+
+The USB specification states that all USB devices must support power
+management. Nevertheless, the sad fact is that many devices do not
+support it very well. You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely. This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs. Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case. Autosuspend was enabled
+by default for almost all USB devices. A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it. As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility. In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script. You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems. For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things. Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes. Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it. It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.) Take care.
+
+
+ The driver interface for Power Management
+ -----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+ .suspend
+ .resume
+ .reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional. The methods' jobs are quite simple:
+
+ The suspend method is called to warn the driver that the
+ device is going to be suspended. If the driver returns a
+ negative error code, the suspend will be aborted. Normally
+ the driver will return 0, in which case it must cancel all
+ outstanding URBs (usb_kill_urb()) and not submit any more.
+
+ The resume method is called to tell the driver that the
+ device has been resumed and the driver can return to normal
+ operation. URBs may once more be submitted.
+
+ The reset_resume method is called to tell the driver that
+ the device has been resumed and it also has been reset.
+ The driver should redo any necessary device initialization,
+ since the device has probably lost most or all of its state
+ (although the interfaces will be in the same altsettings as
+ before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled. Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume. Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed. In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces. The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed. It isn't possible
+to suspend or resume some but not all of a device's interfaces. The
+closest you can come is to unbind the interfaces' drivers.
+
+
+ The driver interface for autosuspend and autoresume
+ ---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above. In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure. It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle. The
+driver does so by calling these three functions:
+
+ int usb_autopm_get_interface(struct usb_interface *intf);
+ void usb_autopm_put_interface(struct usb_interface *intf);
+ int usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure. When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device. When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes. A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+ usb_autopm_get_interface() increments pm_usage_count and
+ attempts an autoresume if the new value is > 0 and the
+ device is suspended.
+
+ usb_autopm_put_interface() decrements pm_usage_count and
+ attempts an autosuspend if the new value is <= 0 and the
+ device isn't suspended.
+
+ usb_autopm_set_interface() leaves pm_usage_count alone.
+ It attempts an autoresume if the value is > 0 and the device
+ is suspended, and it attempts an autosuspend if the value is
+ <= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+ usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+ usb_autopm_set_interface(), which will attempt an autoresume.
+
+ usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+ usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine. But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another. For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle. This is perfectly normal. If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail. This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+ Other parts of the driver interface
+ -----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend. For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it. If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute. (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock. In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation. However there is one thing a
+driver can do in an interrupt handler:
+
+ usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time. udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back. The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method. The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls. The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument. But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead. Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+ Locking requirements
+ --------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex. For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held. This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+ down(&udev->dev.sem);
+ rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+ if (!rc)
+ usb_autopm_put_interface(intf);
+ up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails. (Exercise: Why?)
+
+The rules for locking order are:
+
+ Never acquire any device semaphore while holding any PM mutex.
+
+ Never acquire udev->pm_mutex while holding the PM mutex for
+ a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold. These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful. For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method. Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method. It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second. Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex. It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+ Interaction between dynamic PM and system PM
+ --------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs. Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume. The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up. (Presumably they will be
+autosuspended again after their idle-delay time expires.) In later
+kernels this behavior will be fixed.
+
+(There is an exception. If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began. The justification is
+that a reset-resume is a kind of remote-wakeup event. Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway. The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending. The remote wakeup may succeed, which would
+cause the system suspend to abort. If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete. Or the remote
+wakeup may fail and get lost. Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend. With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer. However there are plans to do away with the freezer, which
+would mean these things would become possible. If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 5b635ae8494..4e0b62b8566 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -428,6 +428,17 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
+Winchiphead CH341 Driver
+
+ This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+ also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+ supported by the driver. The protocol was analyzed from the behaviour
+ of the Windows driver, no datasheet is available at present.
+ The manufacturer's website: http://www.winchiphead.com/.
+ For any questions or problems with this driver, please contact
+ frank@kingswood-consulting.co.uk.
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index 53ae866ae37..2917ce4ffdc 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon
-1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
+0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
#
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
2. Find which bus connects to the desired device
Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
+
This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going
to be quite long.
diff --git a/MAINTAINERS b/MAINTAINERS
index c4eca56ed5b..c7355e7f09f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -297,6 +297,12 @@ P: Colin Leroy
M: colin@colino.net
S: Maintained
+ADVANSYS SCSI DRIVER
+P: Matthew Wilcox
+M: matthew@wil.cx
+L: linux-scsi@vger.kernel.org
+S: Maintained
+
AEDSP16 DRIVER
P: Riccardo Facchetti
M: fizban@tin.it
@@ -677,6 +683,13 @@ P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
+ATMEL USBA UDC DRIVER
+P: Haavard Skinnemoen
+M: hskinnemoen@atmel.com
+L: kernel@avr32linux.org
+W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S: Supported
+
ATMEL WIRELESS DRIVER
P: Simon Kelley
M: simon@thekelleys.org.uk
@@ -1653,7 +1666,8 @@ P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
-T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
+T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git testing
+T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git release
S: Maintained
HARDWARE RANDOM NUMBER GENERATOR CORE
@@ -1769,8 +1783,8 @@ M: venkatesh.pallipadi@intel.com
S: Maintained
HPET: x86_64
-P: Andi Kleen and Vojtech Pavlik
-M: andi@firstfloor.org and vojtech@suse.cz
+P: Vojtech Pavlik
+M: vojtech@suse.cz
S: Maintained
HPET: ACPI hpet.c
@@ -1881,6 +1895,11 @@ M: Gadi Oxman <gadio@netvision.net.il>
L: linux-kernel@vger.kernel.org
S: Maintained
+IDE-SCSI DRIVER
+L: linux-ide@vger.kernel.org
+L: linux-scsi@vger.kernel.org
+S: Orphan
+
IEEE 1394 SUBSYSTEM
P: Ben Collins
M: ben.collins@ubuntu.com
@@ -2385,6 +2404,15 @@ M: khali@linux-fr.org
L: lm-sensors@lm-sensors.org
S: Maintained
+LOCKDEP AND LOCKSTAT
+P: Peter Zijlstra
+M: peterz@infradead.org
+P: Ingo Molnar
+M: mingo@redhat.com
+L: linux-kernel@vger.kernel.org
+T: git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git
+S: Maintained
+
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
P: Richard Russon (FlatCap)
M: ldm@flatcap.org
@@ -2396,7 +2424,7 @@ LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
P: Eric Moore
M: Eric.Moore@lsi.com
M: support@lsi.com
-L: mpt_linux_developer@lsi.com
+L: DL-MPTFusionLinux@lsi.com
L: linux-scsi@vger.kernel.org
W: http://www.lsilogic.com/support
S: Supported
@@ -4170,7 +4198,7 @@ W83791D HARDWARE MONITORING DRIVER
P: Charles Spirakis
M: bezaur@gmail.com
L: lm-sensors@lm-sensors.org
-S: Maintained
+S: Odd Fixes
W83793 HARDWARE MONITORING DRIVER
P: Rudolf Marek
@@ -4258,14 +4286,6 @@ P: Ingo Molnar
M: mingo@redhat.com
S: Maintained
-X86-64 port
-P: Andi Kleen
-M: ak@suse.de
-L: discuss@x86-64.org
-W: http://www.x86-64.org
-T: quilt ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt-current
-S: Maintained
-
YAM DRIVER FOR AX.25
P: Jean-Paul Roubelat
M: jpr@f6fbb.org
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
index 467d899fbe7..e548ba74a4d 100644
--- a/arch/arm/mach-imx/cpufreq.c
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -269,7 +269,6 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
return -EINVAL;
policy->cur = policy->min = policy->max = imx_get_speed(0);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 8000;
policy->cpuinfo.max_freq = 200000;
/* Manual states, that PLL stabilizes in two CLK32 periods */
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index d901dcbe806..b0921622566 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -20,22 +20,23 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/input.h>
-#include <linux/workqueue.h>
#include <asm/hardware.h>
+#include <asm/gpio.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/arch/irda.h>
@@ -342,6 +343,20 @@ static struct platform_device *h2_devices[] __initdata = {
&h2_mcbsp1_device,
};
+static struct i2c_board_info __initdata h2_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("tps65010", 0x48),
+ .type = "tps65010",
+ .irq = OMAP_GPIO_IRQ(58),
+ },
+ /* TODO when driver support is ready:
+ * - isp1301 OTG transceiver
+ * - optional ov9640 camera sensor at 0x30
+ * - pcf9754 for aGPS control
+ * - ... etc
+ */
+};
+
static void __init h2_init_smc91x(void)
{
if ((omap_request_gpio(0)) < 0) {
@@ -446,6 +461,14 @@ static void __init h2_init(void)
omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config);
omap_serial_init();
+
+ /* irq for tps65010 chip */
+ omap_cfg_reg(W4_GPIO58);
+ if (gpio_request(58, "tps65010") == 0)
+ gpio_direction_input(58);
+
+ i2c_register_board_info(1, h2_i2c_board_info,
+ ARRAY_SIZE(h2_i2c_board_info));
}
static void __init h2_map_io(void)
@@ -453,6 +476,22 @@ static void __init h2_map_io(void)
omap1_map_common_io();
}
+#ifdef CONFIG_TPS65010
+static int __init h2_tps_init(void)
+{
+ if (!machine_is_omap_h2())
+ return 0;
+
+ /* gpio3 for SD, gpio4 for VDD_DSP */
+ /* FIXME send power to DSP iff it's configured */
+
+ /* Enable LOW_PWR */
+ tps65010_set_low_pwr(ON);
+ return 0;
+}
+fs_initcall(h2_tps_init);
+#endif
+
MACHINE_START(OMAP_H2, "TI-H2")
/* Maintainer: Imre Deak <imre.deak@nokia.com> */
.phys_io = 0xfff00000,
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 4167f348097..4f84ae273a1 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
+#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -29,12 +30,14 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/hardware.h>
+#include <asm/gpio.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
#include <asm/arch/gpioexpander.h>
#include <asm/arch/irqs.h>
#include <asm/arch/mux.h>
@@ -454,6 +457,19 @@ static struct omap_board_config_kernel h3_config[] = {
{ OMAP_TAG_LCD, &h3_lcd_config },
};
+static struct i2c_board_info __initdata h3_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("tps65010", 0x48),
+ .type = "tps65013",
+ /* .irq = OMAP_GPIO_IRQ(??), */
+ },
+ /* TODO when driver support is ready:
+ * - isp1301 OTG transceiver
+ * - optional ov9640 camera sensor at 0x30
+ * - ...
+ */
+};
+
#define H3_NAND_RB_GPIO_PIN 10
static int nand_dev_ready(struct nand_platform_data *data)
@@ -487,6 +503,10 @@ static void __init h3_init(void)
omap_board_config = h3_config;
omap_board_config_size = ARRAY_SIZE(h3_config);
omap_serial_init();
+
+ /* FIXME setup irq for tps65013 chip */
+ i2c_register_board_info(1, h3_i2c_board_info,
+ ARRAY_SIZE(h3_i2c_board_info));
}
static void __init h3_init_smc91x(void)
@@ -511,6 +531,23 @@ static void __init h3_map_io(void)
omap1_map_common_io();
}
+#ifdef CONFIG_TPS65010
+static int __init h3_tps_init(void)
+{
+ if (!machine_is_omap_h3())
+ return 0;
+
+ /* gpio4 for SD, gpio3 for VDD_DSP */
+ /* FIXME send power to DSP iff it's configured */
+
+ /* Enable LOW_PWR */
+ tps65013_set_low_pwr(ON);
+
+ return 0;
+}
+fs_initcall(h3_tps_init);
+#endif
+
MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
/* Maintainer: Texas Instruments, Inc. */
.phys_io = 0xfff00000,
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 1825781f435..5db182da322 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -32,18 +32,21 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/hardware.h>
+#include <asm/gpio.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/usb.h>
+#include <asm/arch/tps65010.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/arch/common.h>
@@ -180,6 +183,19 @@ static struct platform_device *osk5912_devices[] __initdata = {
&osk5912_mcbsp1_device,
};
+static struct i2c_board_info __initdata osk_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("tps65010", 0x48),
+ .type = "tps65010",
+ .irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
+ },
+ /* TODO when driver support is ready:
+ * - aic23 audio chip at 0x1a
+ * - on Mistral, 24c04 eeprom at 0x50
+ * - optionally on Mistral, ov9640 camera sensor at 0x30
+ */
+};
+
static void __init osk_init_smc91x(void)
{
if ((omap_request_gpio(0)) < 0) {
@@ -452,6 +468,14 @@ static void __init osk_init(void)
omap_board_config_size = ARRAY_SIZE(osk_config);
USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
+ /* irq for tps65010 chip */
+ /* bootloader effectively does: omap_cfg_reg(U19_1610_MPUIO1); */
+ if (gpio_request(OMAP_MPUIO(1), "tps65010") == 0)
+ gpio_direction_input(OMAP_MPUIO(1));
+
+ i2c_register_board_info(1, osk_i2c_board_info,
+ ARRAY_SIZE(osk_i2c_board_info));
+
omap_serial_init();
osk_mistral_init();
}
@@ -461,6 +485,44 @@ static void __init osk_map_io(void)
omap1_map_common_io();
}
+#ifdef CONFIG_TPS65010
+static int __init osk_tps_init(void)
+{
+ if (!machine_is_omap_osk())
+ return 0;
+
+ /* Let LED1 (D9) blink */
+ tps65010_set_led(LED1, BLINK);
+
+ /* Disable LED 2 (D2) */
+ tps65010_set_led(LED2, OFF);
+
+ /* Set GPIO 1 HIGH to disable VBUS power supply;
+ * OHCI driver powers it up/down as needed.
+ */
+ tps65010_set_gpio_out_value(GPIO1, HIGH);
+
+ /* Set GPIO 2 low to turn on LED D3 */
+ tps65010_set_gpio_out_value(GPIO2, HIGH);
+
+ /* Set GPIO 3 low to take ethernet out of reset */
+ tps65010_set_gpio_out_value(GPIO3, LOW);
+
+ /* gpio4 for VDD_DSP */
+ /* FIXME send power to DSP iff it's configured */
+
+ /* Enable LOW_PWR */
+ tps65010_set_low_pwr(ON);
+
+ /* Switch VLDO2 to 3.0V for AIC23 */
+ tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V
+ | TPS_LDO1_ENABLE);
+
+ return 0;
+}
+fs_initcall(osk_tps_init);
+#endif
+
MACHINE_START(OMAP_OSK, "TI-OSK")
/* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
.phys_io = 0xfff00000,
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 78f4c134604..36b47ff5af1 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -331,7 +331,6 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index a0c71dca237..c0d63b0c61c 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -108,7 +108,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = omap_getspeed(0);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
index 6fd9cfd0a31..b7a0e0fbd9a 100644
--- a/arch/blackfin/mach-bf533/cpu.c
+++ b/arch/blackfin/mach-bf533/cpu.c
@@ -118,8 +118,6 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
/*Now ,only support one cpu */
policy->cur = bf533_getfreq(0);
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index 5e9d09eb857..6668c8e4a3f 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 20507e92a3a..f83a2544004 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -40,7 +40,7 @@
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
#include <linux/spi/ad7877.h>
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 47d7d4a0e73..f42ba3aa86d 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 2c47db494f7..046e6d84bbf 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -88,7 +88,7 @@ static struct platform_device bf54x_lq043_device = {
#endif
#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
-static int bf548_keymap[] = {
+static const unsigned int bf548_keymap[] = {
KEYVAL(0, 0, KEY_ENTER),
KEYVAL(0, 1, KEY_HELP),
KEYVAL(0, 2, KEY_0),
@@ -110,8 +110,8 @@ static int bf548_keymap[] = {
static struct bfin_kpad_platform_data bf54x_kpad_data = {
.rows = 4,
.cols = 4,
- .keymap = bf548_keymap,
- .keymapsize = ARRAY_SIZE(bf548_keymap),
+ .keymap = bf548_keymap,
+ .keymapsize = ARRAY_SIZE(bf548_keymap),
.repeat = 0,
.debounce_time = 5000, /* ns (5ms) */
.coldrive_time = 1000, /* ns (1ms) */
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 2d85e4b8730..bf9aafad497 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -214,6 +214,17 @@ config X86_ES7000
endchoice
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool "Single-depth WCHAN output"
+ default y
+ help
+ Calculate simpler /proc/<PID>/wchan values. If this option
+ is disabled then wchan values will recurse back to the
+ caller function. This provides more accurate wchan values,
+ at the expense of slightly more scheduling overhead.
+
+ If in doubt, say "Y".
+
config PARAVIRT
bool "Paravirtualization support (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -1137,6 +1148,11 @@ config PCI_MMCONFIG
depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
default y
+config PCI_DOMAINS
+ bool
+ depends on PCI
+ default y
+
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/Kconfig"
@@ -1206,6 +1222,16 @@ config SCx200HR_TIMER
processor goes idle (as is done by the scheduler). The
other workaround is idle=poll boot option.
+config GEODE_MFGPT_TIMER
+ bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
+ depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
+ default y
+ help
+ This driver provides a clock event source based on the MFGPT
+ timer(s) in the CS5535 and CS5536 companion chip for the geode.
+ MFGPTs have a better resolution and max interval than the
+ generic PIT, and are suitable for use as high-res timers.
+
config K8_NB
def_bool y
depends on AGP_AMD64
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 8c39913d172..2e6310b8eab 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -461,6 +461,16 @@ config IA64_ESI
firmware extensions, such as the ability to inject memory-errors
for test-purposes. If you're unsure, say N.
+config IA64_HP_AML_NFW
+ bool "Support ACPI AML calls to native firmware"
+ help
+ This driver installs a global ACPI Operation Region handler for
+ region 0xA1. AML methods can use this OpRegion to call arbitrary
+ native firmware functions. The driver installs the OpRegion
+ handler if there is an HPQ5001 device or if the user supplies
+ the "force" module parameter, e.g., with the "aml_nfw.force"
+ kernel command line option.
+
source "drivers/sn/Kconfig"
config KEXEC
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 9aecfceeb38..449d3e75bfc 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -1,40 +1,40 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc1
-# Mon Oct 9 10:53:59 2006
+# Linux kernel version: 2.6.23-rc6
+# Tue Sep 18 11:24:01 2007
#
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_TASKSTATS=y
# CONFIG_TASK_DELAY_ACCT is not set
-# CONFIG_UTS_NS is not set
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=20
CONFIG_CPUSETS=y
+CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_TASK_XACCT=y
CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -44,18 +44,20 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLUB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
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
@@ -63,12 +65,9 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_BLK_DEV_BSG=y
#
# IO Schedulers
@@ -88,12 +87,15 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
CONFIG_IA64=y
CONFIG_64BIT=y
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
-CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_DMI=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
@@ -116,6 +118,7 @@ CONFIG_IA64_PAGE_SIZE_16KB=y
CONFIG_PGTABLE_4=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_IA64_L1_CACHE_SHIFT=7
@@ -128,7 +131,10 @@ CONFIG_NR_CPUS=1024
# CONFIG_HOTPLUG_CPU is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
CONFIG_DISCONTIGMEM_MANUAL=y
@@ -140,6 +146,9 @@ CONFIG_NEED_MULTIPLE_NODES=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -154,16 +163,17 @@ CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
CONFIG_IA32_SUPPORT=y
CONFIG_COMPAT=y
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
+CONFIG_IA64_MC_ERR_INJECT=y
CONFIG_SGI_SN=y
# CONFIG_IA64_ESI is not set
#
# SN Devices
#
-CONFIG_SGI_IOC4=y
CONFIG_SGI_IOC3=y
#
@@ -171,6 +181,7 @@ CONFIG_SGI_IOC3=y
#
CONFIG_EFI_VARS=y
CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
@@ -180,12 +191,9 @@ CONFIG_BINFMT_ELF=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
CONFIG_ACPI=y
+# CONFIG_ACPI_PROCFS is not set
+CONFIG_ACPI_PROC_EVENT=y
# CONFIG_ACPI_BUTTON is not set
# CONFIG_ACPI_FAN is not set
# CONFIG_ACPI_DOCK is not set
@@ -208,17 +216,14 @@ CONFIG_ACPI_SYSTEM=y
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI_PCIE=y
# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
CONFIG_PCIEAER=y
+CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
-# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
CONFIG_HOTPLUG_PCI=y
# CONFIG_HOTPLUG_PCI_FAKE is not set
# CONFIG_HOTPLUG_PCI_ACPI is not set
@@ -239,13 +244,13 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -261,7 +266,7 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
@@ -270,9 +275,11 @@ CONFIG_INET_TCP_DIAG=m
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
CONFIG_IPV6=m
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
@@ -283,25 +290,13 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_SUBTREES is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -327,7 +322,17 @@ CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -340,31 +345,19 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
+# Protocols
#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -379,13 +372,13 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
CONFIG_ATA_OVER_ETH=m
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_SGI_IOC4=y
+# CONFIG_TIFM_CORE is not set
CONFIG_IDE=y
CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
@@ -400,20 +393,23 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
#
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_GENERIC is not set
# 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 is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -428,6 +424,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -438,10 +435,10 @@ CONFIG_BLK_DEV_SGIIOC4=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
# 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
#
@@ -449,6 +446,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -469,6 +468,8 @@ CONFIG_CHR_DEV_SCH=m
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -478,11 +479,9 @@ CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=y
CONFIG_SCSI_SAS_LIBSAS=y
+# CONFIG_SCSI_SAS_ATA is not set
# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
CONFIG_ISCSI_TCP=m
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
@@ -512,11 +511,10 @@ CONFIG_SCSI_QLA_FC=y
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
+# CONFIG_SCSI_SRP is not set
CONFIG_ATA=y
+CONFIG_ATA_NONSTANDARD=y
+CONFIG_ATA_ACPI=y
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SVW is not set
# CONFIG_ATA_PIIX is not set
@@ -532,10 +530,12 @@ CONFIG_ATA=y
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
CONFIG_SATA_VITESSE=y
+# CONFIG_SATA_INIC162X is not set
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -547,8 +547,10 @@ CONFIG_SATA_VITESSE=y
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_NETCELL is not set
@@ -565,10 +567,6 @@ CONFIG_SATA_VITESSE=y
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_LINEAR=y
@@ -587,6 +585,8 @@ CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
#
# Fusion MPT device support
@@ -597,43 +597,25 @@ CONFIG_FUSION_FC=y
CONFIG_FUSION_SAS=y
CONFIG_FUSION_MAX_SGE=128
CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LOGGING=y
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_NET_SB1000 is not set
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-
-#
-# Ethernet (10 or 100Mbit)
-#
# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
@@ -645,32 +627,39 @@ CONFIG_NETDEVICES=y
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+# CONFIG_CHELSIO_T1_NAPI is not set
+CONFIG_CHELSIO_T3=m
# CONFIG_IXGB is not set
CONFIG_S2IO=m
# CONFIG_S2IO_NAPI is not set
# CONFIG_MYRI10GE is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_MLX4_CORE is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
-# Wan interfaces
+# 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_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -680,18 +669,9 @@ CONFIG_S2IO=m
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -699,6 +679,7 @@ CONFIG_NET_POLL_CONTROLLER=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -718,6 +699,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -741,6 +723,7 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_DIGIEPCA is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
# CONFIG_ISI is not set
# CONFIG_SYNCLINKMP is not set
# CONFIG_SYNCLINK_GT is not set
@@ -752,7 +735,6 @@ CONFIG_SERIAL_NONSTANDARD=y
CONFIG_SGI_SNSC=y
CONFIG_SGI_TIOCX=y
CONFIG_SGI_MBCS=m
-CONFIG_MSPEC=y
#
# Serial drivers
@@ -771,28 +753,13 @@ CONFIG_SERIAL_SGI_IOC3=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
CONFIG_AGP=y
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_VIA is not set
CONFIG_AGP_SGI_TIOCA=y
# CONFIG_DRM is not set
CONFIG_RAW_DRIVER=m
@@ -800,16 +767,8 @@ CONFIG_MAX_RAW_DEVS=256
# CONFIG_HPET is not set
# CONFIG_HANGCHECK_TIMER is not set
CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -817,37 +776,33 @@ CONFIG_MMTIMER=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
#
-# Misc devices
+# Multifunction device drivers
#
-# CONFIG_TIFM_CORE is not set
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
# CONFIG_FB is not set
#
@@ -856,16 +811,29 @@ CONFIG_FIRMWARE_EDID=y
CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
#
# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
#
-# USB support
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -876,9 +844,10 @@ CONFIG_USB=m
# Miscellaneous USB options
#
# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set
#
@@ -890,10 +859,12 @@ CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=m
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -912,47 +883,10 @@ CONFIG_USB_UHCI_HCD=m
# CONFIG_USB_LIBUSUAL is not set
#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_TRANCEVIBRATOR 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 is not set
CONFIG_USB_MON=y
#
@@ -974,6 +908,7 @@ CONFIG_USB_MON=y
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
@@ -983,6 +918,8 @@ CONFIG_USB_MON=y
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
#
# USB DSL modem support
@@ -992,48 +929,24 @@ CONFIG_USB_MON=y
# 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=m
# CONFIG_INFINIBAND_USER_MAD is not set
CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MEM=y
CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
CONFIG_INFINIBAND_MTHCA_DEBUG=y
# CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_INFINIBAND_CXGB3 is not set
+# CONFIG_MLX4_INFINIBAND is not set
CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_CM is not set
CONFIG_INFINIBAND_IPOIB_DEBUG=y
# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
CONFIG_INFINIBAND_SRP=m
# CONFIG_INFINIBAND_ISER is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
# CONFIG_RTC_CLASS is not set
#
@@ -1050,6 +963,12 @@ CONFIG_INFINIBAND_SRP=m
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+CONFIG_MSPEC=y
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1061,6 +980,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -1161,6 +1081,7 @@ CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
+# CONFIG_SUNRPC_BIND34 is not set
CONFIG_RPCSEC_GSS_KRB5=m
# CONFIG_RPCSEC_GSS_SPKM3 is not set
CONFIG_SMB_FS=m
@@ -1174,7 +1095,6 @@ CONFIG_CIFS=m
# 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
@@ -1196,6 +1116,7 @@ CONFIG_SGI_PARTITION=y
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
#
# Native Language Support
@@ -1244,18 +1165,25 @@ CONFIG_NLS_UTF8=y
#
# Distributed Lock Manager
#
+# CONFIG_DLM is not set
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
@@ -1274,25 +1202,28 @@ CONFIG_IRQ_PER_CPU=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=20
+# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON 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_RWSEMS is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
CONFIG_IA64_GRANULE_16MB=y
# CONFIG_IA64_GRANULE_64MB is not set
# CONFIG_IA64_PRINT_HAZARDS is not set
@@ -1306,16 +1237,17 @@ CONFIG_SYSVIPC_COMPAT=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=m
CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=m
+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
@@ -1324,9 +1256,14 @@ CONFIG_CRYPTO_SHA1=m
# 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=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
@@ -1340,8 +1277,6 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_MICHAEL_MIC is not set
CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/ia64/hp/common/Makefile b/arch/ia64/hp/common/Makefile
index f61a60057ff..9e179dd06b8 100644
--- a/arch/ia64/hp/common/Makefile
+++ b/arch/ia64/hp/common/Makefile
@@ -8,3 +8,4 @@
obj-y := sba_iommu.o
obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += hwsw_iommu.o
obj-$(CONFIG_IA64_GENERIC) += hwsw_iommu.o
+obj-$(CONFIG_IA64_HP_AML_NFW) += aml_nfw.o
diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c
new file mode 100644
index 00000000000..4abd2c79bb1
--- /dev/null
+++ b/arch/ia64/hp/common/aml_nfw.c
@@ -0,0 +1,236 @@
+/*
+ * OpRegion handler to allow AML to call native firmware
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver implements HP Open Source Review Board proposal 1842,
+ * which was approved on 9/20/2006.
+ *
+ * For technical documentation, see the HP SPPA Firmware EAS, Appendix F.
+ *
+ * ACPI does not define a mechanism for AML methods to call native firmware
+ * interfaces such as PAL or SAL. This OpRegion handler adds such a mechanism.
+ * After the handler is installed, an AML method can call native firmware by
+ * storing the arguments and firmware entry point to specific offsets in the
+ * OpRegion. When AML reads the "return value" offset from the OpRegion, this
+ * handler loads up the arguments, makes the firmware call, and returns the
+ * result.
+ */
+
+#include <linux/module.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <asm/sal.h>
+
+MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ACPI opregion handler for native firmware calls");
+
+static int force_register;
+module_param_named(force, force_register, bool, 0);
+MODULE_PARM_DESC(force, "Install opregion handler even without HPQ5001 device");
+
+#define AML_NFW_SPACE 0xA1
+
+struct ia64_pdesc {
+ void *ip;
+ void *gp;
+};
+
+/*
+ * N.B. The layout of this structure is defined in the HP SPPA FW EAS, and
+ * the member offsets are embedded in AML methods.
+ */
+struct ia64_nfw_context {
+ u64 arg[8];
+ struct ia64_sal_retval ret;
+ u64 ip;
+ u64 gp;
+ u64 pad[2];
+};
+
+static void *virt_map(u64 address)
+{
+ if (address & (1UL << 63))
+ return (void *) (__IA64_UNCACHED_OFFSET | address);
+
+ return __va(address);
+}
+
+static void aml_nfw_execute(struct ia64_nfw_context *c)
+{
+ struct ia64_pdesc virt_entry;
+ ia64_sal_handler entry;
+
+ virt_entry.ip = virt_map(c->ip);
+ virt_entry.gp = virt_map(c->gp);
+
+ entry = (ia64_sal_handler) &virt_entry;
+
+ IA64_FW_CALL(entry, c->ret,
+ c->arg[0], c->arg[1], c->arg[2], c->arg[3],
+ c->arg[4], c->arg[5], c->arg[6], c->arg[7]);
+}
+
+static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+{
+ switch (bit_width) {
+ case 8:
+ *value = *(u8 *)offset;
+ break;
+ case 16:
+ *value = *(u16 *)offset;
+ break;
+ case 32:
+ *value = *(u32 *)offset;
+ break;
+ case 64:
+ *value = *(u64 *)offset;
+ break;
+ }
+}
+
+static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+{
+ switch (bit_width) {
+ case 8:
+ *(u8 *) offset = *value;
+ break;
+ case 16:
+ *(u16 *) offset = *value;
+ break;
+ case 32:
+ *(u32 *) offset = *value;
+ break;
+ case 64:
+ *(u64 *) offset = *value;
+ break;
+ }
+}
+
+static acpi_status aml_nfw_handler(u32 function, acpi_physical_address address,
+ u32 bit_width, acpi_integer *value, void *handler_context,
+ void *region_context)
+{
+ struct ia64_nfw_context *context = handler_context;
+ u8 *offset = (u8 *) context + address;
+
+ if (bit_width != 8 && bit_width != 16 &&
+ bit_width != 32 && bit_width != 64)
+ return AE_BAD_PARAMETER;
+
+ if (address + (bit_width >> 3) > sizeof(struct ia64_nfw_context))
+ return AE_BAD_PARAMETER;
+
+ switch (function) {
+ case ACPI_READ:
+ if (address == offsetof(struct ia64_nfw_context, ret))
+ aml_nfw_execute(context);
+ aml_nfw_read_arg(offset, bit_width, value);
+ break;
+ case ACPI_WRITE:
+ aml_nfw_write_arg(offset, bit_width, value);
+ break;
+ }
+
+ return AE_OK;
+}
+
+static struct ia64_nfw_context global_context;
+static int global_handler_registered;
+
+static int aml_nfw_add_global_handler(void)
+{
+ acpi_status status;
+
+ if (global_handler_registered)
+ return 0;
+
+ status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+ AML_NFW_SPACE, aml_nfw_handler, NULL, &global_context);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ global_handler_registered = 1;
+ printk(KERN_INFO "Global 0x%02X opregion handler registered\n",
+ AML_NFW_SPACE);
+ return 0;
+}
+
+static int aml_nfw_remove_global_handler(void)
+{
+ acpi_status status;
+
+ if (!global_handler_registered)
+ return 0;
+
+ status = acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+ AML_NFW_SPACE, aml_nfw_handler);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ global_handler_registered = 0;
+ printk(KERN_INFO "Global 0x%02X opregion handler removed\n",
+ AML_NFW_SPACE);
+ return 0;
+}
+
+static int aml_nfw_add(struct acpi_device *device)
+{
+ /*
+ * We would normally allocate a new context structure and install
+ * the address space handler for the specific device we found.
+ * But the HP-UX implementation shares a single global context
+ * and always puts the handler at the root, so we'll do the same.
+ */
+ return aml_nfw_add_global_handler();
+}
+
+static int aml_nfw_remove(struct acpi_device *device, int type)
+{
+ return aml_nfw_remove_global_handler();
+}
+
+static const struct acpi_device_id aml_nfw_ids[] = {
+ {"HPQ5001", 0},
+ {"", 0}
+};
+
+static struct acpi_driver acpi_aml_nfw_driver = {
+ .name = "native firmware",
+ .ids = aml_nfw_ids,
+ .ops = {
+ .add = aml_nfw_add,
+ .remove = aml_nfw_remove,
+ },
+};
+
+static int __init aml_nfw_init(void)
+{
+ int result;
+
+ if (force_register)
+ aml_nfw_add_global_handler();
+
+ result = acpi_bus_register_driver(&acpi_aml_nfw_driver);
+ if (result < 0) {
+ aml_nfw_remove_global_handler();
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit aml_nfw_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_aml_nfw_driver);
+ aml_nfw_remove_global_handler();
+}
+
+module_init(aml_nfw_init);
+module_exit(aml_nfw_exit);
diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
index 4552a1cf5b3..d62fa76e5a7 100644
--- a/arch/ia64/hp/sim/simscsi.c
+++ b/arch/ia64/hp/sim/simscsi.c
@@ -372,8 +372,13 @@ simscsi_init(void)
return -ENOMEM;
error = scsi_add_host(host, NULL);
- if (!error)
- scsi_scan_host(host);
+ if (error)
+ goto free_host;
+ scsi_scan_host(host);
+ return 0;
+
+ free_host:
+ scsi_host_put(host);
return error;
}
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index 8c6ec707084..b8498ea6206 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -321,8 +321,6 @@ acpi_cpufreq_cpu_init (
data->acpi_data.states[i].transition_latency * 1000;
}
}
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
policy->cur = processor_get_freq(data, policy->cpu);
/* table init */
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 1d64ef478dd..f1cf2df97a2 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -118,11 +118,6 @@ machine_crash_shutdown(struct pt_regs *pt)
static void
machine_kdump_on_init(void)
{
- if (!ia64_kimage) {
- printk(KERN_NOTICE "machine_kdump_on_init(): "
- "kdump not configured\n");
- return;
- }
local_irq_disable();
kexec_disable_iosapic();
machine_kexec(ia64_kimage);
@@ -156,6 +151,14 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
if (!kdump_on_init)
return NOTIFY_DONE;
+ if (!ia64_kimage) {
+ if (val == DIE_INIT_MONARCH_LEAVE)
+ ia64_mca_printk(KERN_NOTICE
+ "%s: kdump not configured\n",
+ __FUNCTION__);
+ return NOTIFY_DONE;
+ }
+
if (val != DIE_INIT_MONARCH_LEAVE &&
val != DIE_INIT_SLAVE_LEAVE &&
val != DIE_INIT_MONARCH_PROCESS &&
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index 4f0f3b8c1ee..58e943a5d95 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -79,7 +79,6 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
relocate_new_kernel_t rnk;
void *pal_addr = efi_get_pal_addr();
unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
- unsigned long vector;
int ii;
BUG_ON(!image);
@@ -107,11 +106,8 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
/* unmask TPR and clear any pending interrupts */
ia64_setreg(_IA64_REG_CR_TPR, 0);
ia64_srlz_d();
- vector = ia64_get_ivr();
- while (vector != IA64_SPURIOUS_INT_VECTOR) {
+ while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
ia64_eoi();
- vector = ia64_get_ivr();
- }
platform_kernel_launch_event();
rnk = (relocate_new_kernel_t)&code_addr;
(*rnk)(image->head, image->start, ia64_boot_param,
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 63b73f3d4c9..cc87025e8f5 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -701,8 +701,7 @@ ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused)
/*
* ia64_mca_wakeup
*
- * Send an inter-cpu interrupt to wake-up a particular cpu
- * and mark that cpu to be out of rendez.
+ * Send an inter-cpu interrupt to wake-up a particular cpu.
*
* Inputs : cpuid
* Outputs : None
@@ -711,14 +710,12 @@ static void
ia64_mca_wakeup(int cpu)
{
platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
- ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
-
}
/*
* ia64_mca_wakeup_all
*
- * Wakeup all the cpus which have rendez'ed previously.
+ * Wakeup all the slave cpus which have rendez'ed previously.
*
* Inputs : None
* Outputs : None
@@ -741,7 +738,10 @@ ia64_mca_wakeup_all(void)
*
* This is handler used to put slave processors into spinloop
* while the monarch processor does the mca handling and later
- * wake each slave up once the monarch is done.
+ * wake each slave up once the monarch is done. The state
+ * IA64_MCA_RENDEZ_CHECKIN_DONE indicates the cpu is rendez'ed
+ * in SAL. The state IA64_MCA_RENDEZ_CHECKIN_NOTDONE indicates
+ * the cpu has come out of OS rendezvous.
*
* Inputs : None
* Outputs : None
@@ -778,6 +778,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg)
(long)&nd, 0, 0) == NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
/* Enable all interrupts */
local_irq_restore(flags);
return IRQ_HANDLED;
@@ -1135,30 +1136,27 @@ no_mod:
static void
ia64_wait_for_slaves(int monarch, const char *type)
{
- int c, wait = 0, missing = 0;
- for_each_online_cpu(c) {
- if (c == monarch)
- continue;
- if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
- udelay(1000); /* short wait first */
- wait = 1;
- break;
- }
- }
- if (!wait)
- goto all_in;
- for_each_online_cpu(c) {
- if (c == monarch)
- continue;
- if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
- udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */
- if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE)
- missing = 1;
- break;
+ int c, i , wait;
+
+ /*
+ * wait 5 seconds total for slaves (arbitrary)
+ */
+ for (i = 0; i < 5000; i++) {
+ wait = 0;
+ for_each_online_cpu(c) {
+ if (c == monarch)
+ continue;
+ if (ia64_mc_info.imi_rendez_checkin[c]
+ == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
+ udelay(1000); /* short wait */
+ wait = 1;
+ break;
+ }
}
+ if (!wait)
+ goto all_in;
}
- if (!missing)
- goto all_in;
+
/*
* Maybe slave(s) dead. Print buffered messages immediately.
*/
@@ -1224,26 +1222,27 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
+
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
if (sos->monarch) {
ia64_wait_for_slaves(cpu, "MCA");
+
+ /* Wakeup all the processors which are spinning in the
+ * rendezvous loop. They will leave SAL, then spin in the OS
+ * with interrupts disabled until this monarch cpu leaves the
+ * MCA handler. That gets control back to the OS so we can
+ * backtrace the other cpus, backtrace when spinning in SAL
+ * does not work.
+ */
+ ia64_mca_wakeup_all();
+ if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0)
+ == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
} else {
- ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
while (cpu_isset(cpu, mca_cpu))
cpu_relax(); /* spin until monarch wakes us */
- ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
}
- /* Wakeup all the processors which are spinning in the rendezvous loop.
- * They will leave SAL, then spin in the OS with interrupts disabled
- * until this monarch cpu leaves the MCA handler. That gets control
- * back to the OS so we can backtrace the other cpus, backtrace when
- * spinning in SAL does not work.
- */
- ia64_mca_wakeup_all();
- if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0)
- == NOTIFY_STOP)
- ia64_mca_spin(__FUNCTION__);
-
/* Get the MCA error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
@@ -1277,21 +1276,22 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
/* wake up the next monarch cpu,
* and put this cpu in the rendez loop.
*/
- ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
for_each_online_cpu(i) {
if (cpu_isset(i, mca_cpu)) {
monarch_cpu = i;
cpu_clear(i, mca_cpu); /* wake next cpu */
while (monarch_cpu != -1)
cpu_relax(); /* spin until last cpu leaves */
- ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
set_curr_task(cpu, previous_current);
+ ia64_mc_info.imi_rendez_checkin[cpu]
+ = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
return;
}
}
}
set_curr_task(cpu, previous_current);
- monarch_cpu = -1;
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+ monarch_cpu = -1; /* This frees the slaves and previous monarchs */
}
static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd);
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
index c85e943ba5f..485e34d0b19 100644
--- a/arch/ia64/kernel/mca_drv.h
+++ b/arch/ia64/kernel/mca_drv.h
@@ -118,7 +118,5 @@ struct mca_table_entry {
extern const struct mca_table_entry *search_mca_tables (unsigned long addr);
extern int mca_recover_range(unsigned long);
-extern void ia64_mca_printk(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
extern void ia64_mlogbuf_dump(void);
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index 85829e27785..6ef6ffb943a 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -907,7 +907,7 @@ palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
return len;
}
-static void
+static void __cpuinit
create_palinfo_proc_entries(unsigned int cpu)
{
# define CPUSTR "cpu%d"
@@ -968,7 +968,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
}
}
-static int palinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int hotcpu = (unsigned long)hcpu;
@@ -986,7 +986,7 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block palinfo_cpu_notifier =
+static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
{
.notifier_call = palinfo_cpu_callback,
.priority = 0,
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 14b8e5a6222..f55fa07849c 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -1538,13 +1538,6 @@ init_pfm_fs(void)
return err;
}
-static void __exit
-exit_pfm_fs(void)
-{
- unregister_filesystem(&pfm_fs_type);
- mntput(pfmfs_mnt);
-}
-
static ssize_t
pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index 25cd75f50ab..779c3cca206 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -574,7 +574,7 @@ static const struct file_operations salinfo_data_fops = {
.write = salinfo_log_write,
};
-static int __devinit
+static int __cpuinit
salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
{
unsigned int i, cpu = (unsigned long)hcpu;
@@ -615,7 +615,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
return NOTIFY_OK;
}
-static struct notifier_block salinfo_cpu_notifier =
+static struct notifier_block salinfo_cpu_notifier __cpuinitdata =
{
.notifier_call = salinfo_cpu_callback,
.priority = 0,
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 94ae3c87d82..14261fee5f4 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -118,11 +118,11 @@ struct cpu_cache_info {
struct kobject kobj;
};
-static struct cpu_cache_info all_cpu_cache_info[NR_CPUS];
+static struct cpu_cache_info all_cpu_cache_info[NR_CPUS] __cpuinitdata;
#define LEAF_KOBJECT_PTR(x,y) (&all_cpu_cache_info[x].cache_leaves[y])
#ifdef CONFIG_SMP
-static void cache_shared_cpu_map_setup( unsigned int cpu,
+static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
struct cache_info * this_leaf)
{
pal_cache_shared_info_t csi;
@@ -157,7 +157,7 @@ static void cache_shared_cpu_map_setup( unsigned int cpu,
&csi) == PAL_STATUS_SUCCESS);
}
#else
-static void cache_shared_cpu_map_setup(unsigned int cpu,
+static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu,
struct cache_info * this_leaf)
{
cpu_set(cpu, this_leaf->shared_cpu_map);
@@ -428,13 +428,13 @@ static struct notifier_block __cpuinitdata cache_cpu_notifier =
.notifier_call = cache_cpu_callback
};
-static int __cpuinit cache_sysfs_init(void)
+static int __init cache_sysfs_init(void)
{
int i;
for_each_online_cpu(i) {
- cache_cpu_callback(&cache_cpu_notifier, CPU_ONLINE,
- (void *)(long)i);
+ struct sys_device *sys_dev = get_cpu_sysdev((unsigned int)i);
+ cache_add_dev(sys_dev);
}
register_hotcpu_notifier(&cache_cpu_notifier);
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 5a289e4de83..a88eba3314d 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv)
}
-static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 2b5f64726a2..880add120eb 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -1,6 +1,4 @@
/*
- * linux/atari/atakeyb.c
- *
* Atari Keyboard driver for 680x0 Linux
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -11,6 +9,9 @@
/*
* Atari support by Robert de Vries
* enhanced by Bjoern Brauel and Roman Hodek
+ *
+ * 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21
+ * 06/07 Michael Schmitz
*/
#include <linux/module.h>
@@ -32,7 +33,6 @@
#include <asm/atari_joystick.h>
#include <asm/irq.h>
-static void atakeyb_rep(unsigned long ignore);
extern unsigned int keymap_count;
/* Hook for MIDI serial driver */
@@ -104,25 +104,6 @@ static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
* - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
*/
-static u_short ataplain_map[NR_KEYS] __initdata = {
- 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
- 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
- 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
- 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
- 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
- 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
- 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
- 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
- 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
- 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
- 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
- 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
- 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
typedef enum kb_state_t {
KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
} KB_STATE_T;
@@ -137,41 +118,6 @@ typedef struct keyboard_state {
KEYBOARD_STATE kb_state;
-#define DEFAULT_KEYB_REP_DELAY (HZ/4)
-#define DEFAULT_KEYB_REP_RATE (HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static struct timer_list atakeyb_rep_timer = {
- .function = atakeyb_rep,
-};
-
-static void atakeyb_rep(unsigned long ignore)
-{
- /* Disable keyboard for the time we call handle_scancode(), else a race
- * in the keyboard tty queue may happen */
- atari_disable_irq(IRQ_MFP_ACIA);
- del_timer(&atakeyb_rep_timer);
-
- /* A keyboard int may have come in before we disabled the irq, so
- * double-check whether rep_scancode is still != 0 */
- if (rep_scancode) {
- init_timer(&atakeyb_rep_timer);
- atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
- add_timer(&atakeyb_rep_timer);
-
- //handle_scancode(rep_scancode, 1);
- if (atari_input_keyboard_interrupt_hook)
- atari_input_keyboard_interrupt_hook(rep_scancode, 1);
- }
-
- atari_enable_irq(IRQ_MFP_ACIA);
-}
-
-
/* ++roman: If a keyboard overrun happened, we can't tell in general how much
* bytes have been lost and in which state of the packet structure we are now.
* This usually causes keyboards bytes to be interpreted as mouse movements
@@ -209,9 +155,6 @@ repeat:
/* ...happens often if interrupts were disabled for too long */
printk(KERN_DEBUG "Keyboard overrun\n");
scancode = acia.key_data;
- /* Turn off autorepeating in case a break code has been lost */
- del_timer(&atakeyb_rep_timer);
- rep_scancode = 0;
if (ikbd_self_test)
/* During self test, don't do resyncing, just process the code */
goto interpret_scancode;
@@ -281,11 +224,12 @@ repeat:
* make codes instead. Therefore, simply ignore
* break_flag...
*/
- int keyval = plain_map[scancode], keytyp;
+ int keyval, keytyp;
set_bit(scancode, broken_keys);
self_test_last_rcv = jiffies;
- keyval = plain_map[scancode];
+ /* new Linux scancodes; approx. */
+ keyval = scancode;
keytyp = KTYP(keyval) - 0xf0;
keyval = KVAL(keyval);
@@ -301,19 +245,6 @@ repeat:
} else if (test_bit(scancode, broken_keys))
break;
-#if 0 // FIXME; hangs at boot
- if (break_flag) {
- del_timer(&atakeyb_rep_timer);
- rep_scancode = 0;
- } else {
- del_timer(&atakeyb_rep_timer);
- rep_scancode = scancode;
- atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
- add_timer(&atakeyb_rep_timer);
- }
-#endif
-
- // handle_scancode(scancode, !break_flag);
if (atari_input_keyboard_interrupt_hook)
atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
break;
@@ -639,9 +570,6 @@ int __init atari_keyb_init(void)
if (atari_keyb_done)
return 0;
- /* setup key map */
- memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
-
kb_state.state = KEYBOARD;
kb_state.len = 0;
@@ -704,26 +632,6 @@ int __init atari_keyb_init(void)
return 0;
}
-int atari_kbdrate(struct kbd_repeat *k)
-{
- if (k->delay > 0) {
- /* convert from msec to jiffies */
- key_repeat_delay = (k->delay * HZ + 500) / 1000;
- if (key_repeat_delay < 1)
- key_repeat_delay = 1;
- }
- if (k->period > 0) {
- key_repeat_rate = (k->period * HZ + 500) / 1000;
- if (key_repeat_rate < 1)
- key_repeat_rate = 1;
- }
-
- k->delay = key_repeat_delay * 1000 / HZ;
- k->period = key_repeat_rate * 1000 / HZ;
-
- return 0;
-}
-
int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
{
#ifdef CONFIG_MAGIC_SYSRQ
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c
index a8637cdb5b4..90d70695aa6 100644
--- a/arch/mips/au1000/common/prom.c
+++ b/arch/mips/au1000/common/prom.c
@@ -33,7 +33,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -41,18 +40,16 @@
#include <asm/bootinfo.h>
-/* #define DEBUG_CMDLINE */
-
-extern int prom_argc;
-extern char **prom_argv, **prom_envp;
-
+int prom_argc;
+char **prom_argv;
+char **prom_envp;
char * __init_or_module prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
-void prom_init_cmdline(void)
+void prom_init_cmdline(void)
{
char *cp;
int actr;
@@ -61,7 +58,7 @@ void prom_init_cmdline(void)
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
- strcpy(cp, prom_argv[actr]);
+ strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
@@ -70,10 +67,8 @@ void prom_init_cmdline(void)
--cp;
if (prom_argc > 1)
*cp = '\0';
-
}
-
char *prom_getenv(char *envname)
{
/*
@@ -95,21 +90,23 @@ char *prom_getenv(char *envname)
}
env++;
}
+
return NULL;
}
-inline unsigned char str2hexnum(unsigned char c)
+static inline unsigned char str2hexnum(unsigned char c)
{
- if(c >= '0' && c <= '9')
+ if (c >= '0' && c <= '9')
return c - '0';
- if(c >= 'a' && c <= 'f')
+ if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
- if(c >= 'A' && c <= 'F')
+ if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
+
return 0; /* foo */
}
-inline void str2eaddr(unsigned char *ea, unsigned char *str)
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
@@ -124,35 +121,29 @@ inline void str2eaddr(unsigned char *ea, unsigned char *str)
}
}
-int get_ethernet_addr(char *ethernet_addr)
+int prom_get_ethernet_addr(char *ethernet_addr)
{
- char *ethaddr_str;
+ char *ethaddr_str;
+ char *argptr;
- ethaddr_str = prom_getenv("ethaddr");
+ /* Check the environment variables first */
+ ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
- printk("ethaddr not set in boot prom\n");
- return -1;
- }
- str2eaddr(ethernet_addr, ethaddr_str);
-
-#if 0
- {
- int i;
+ /* Check command line */
+ argptr = prom_getcmdline();
+ ethaddr_str = strstr(argptr, "ethaddr=");
+ if (!ethaddr_str)
+ return -1;
- printk("get_ethernet_addr: ");
- for (i=0; i<5; i++)
- printk("%02x:", (unsigned char)*(ethernet_addr+i));
- printk("%02x\n", *(ethernet_addr+i));
+ ethaddr_str += strlen("ethaddr=");
}
-#endif
+
+ str2eaddr(ethernet_addr, ethaddr_str);
return 0;
}
+EXPORT_SYMBOL(prom_get_ethernet_addr);
void __init prom_free_prom_memory(void)
{
}
-
-EXPORT_SYMBOL(prom_getcmdline);
-EXPORT_SYMBOL(get_ethernet_addr);
-EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index b212c072612..a90d425d465 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -40,10 +40,11 @@
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
-#include <asm/mach-au1x00/au1000.h>
#include <asm/time.h>
-extern char * prom_getcmdline(void);
+#include <au1000.h>
+#include <prom.h>
+
extern void __init board_setup(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c
index 4d7bcfc8cf7..43298fd9459 100644
--- a/arch/mips/au1000/db1x00/init.c
+++ b/arch/mips/au1000/db1x00/init.c
@@ -31,15 +31,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c
index 2aa7b2ed6a8..cdeae3212a2 100644
--- a/arch/mips/au1000/mtx-1/init.c
+++ b/arch/mips/au1000/mtx-1/init.c
@@ -34,13 +34,11 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
+
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c
index 4535f7208e1..ddccaf6997d 100644
--- a/arch/mips/au1000/pb1000/init.c
+++ b/arch/mips/au1000/pb1000/init.c
@@ -30,15 +30,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c
index 7ba6852de7c..c93fd39b4ab 100644
--- a/arch/mips/au1000/pb1100/init.c
+++ b/arch/mips/au1000/pb1100/init.c
@@ -31,15 +31,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c
index 2122515f79d..5dbc9868f59 100644
--- a/arch/mips/au1000/pb1200/board_setup.c
+++ b/arch/mips/au1000/pb1200/board_setup.c
@@ -41,8 +41,10 @@
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include <au1000.h>
+#include <au1xxx_dbdma.h>
+#include <prom.h>
#ifdef CONFIG_MIPS_PB1200
#include <asm/mach-pb1x00/pb1200.h>
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c
index 5a70029d538..c251570749e 100644
--- a/arch/mips/au1000/pb1200/init.c
+++ b/arch/mips/au1000/pb1200/init.c
@@ -31,15 +31,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c
index e58a9d6c502..507d4b20416 100644
--- a/arch/mips/au1000/pb1500/init.c
+++ b/arch/mips/au1000/pb1500/init.c
@@ -31,15 +31,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c
index fad53bf5aad..b03eee601e3 100644
--- a/arch/mips/au1000/pb1550/init.c
+++ b/arch/mips/au1000/pb1550/init.c
@@ -31,15 +31,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c
index 9f839c36f69..6532939f377 100644
--- a/arch/mips/au1000/xxs1500/init.c
+++ b/arch/mips/au1000/xxs1500/init.c
@@ -30,15 +30,13 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 432f2e376ae..63989e9df4f 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -379,7 +379,7 @@ void flush_tlb_mm(struct mm_struct *mm)
unsigned int cpu;
cpu_clear(smp_processor_id(), mask);
- for_each_online_cpu(cpu)
+ for_each_cpu_mask(cpu, mask)
if (cpu_context(cpu, mm))
cpu_context(cpu, mm) = 0;
}
@@ -419,7 +419,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l
unsigned int cpu;
cpu_clear(smp_processor_id(), mask);
- for_each_online_cpu(cpu)
+ for_each_cpu_mask(cpu, mask)
if (cpu_context(cpu, mm))
cpu_context(cpu, mm) = 0;
}
@@ -466,7 +466,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
unsigned int cpu;
cpu_clear(smp_processor_id(), mask);
- for_each_online_cpu(cpu)
+ for_each_cpu_mask(cpu, mask)
if (cpu_context(cpu, vma->vm_mm))
cpu_context(cpu, vma->vm_mm) = 0;
}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 01b0961acfb..a61246d3533 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -66,7 +66,7 @@ static inline int __maybe_unused r10000_llsc_war(void)
* why; it's not an issue caused by the core RTL.
*
*/
-static int __init m4kc_tlbp_war(void)
+static __init int __attribute__((unused)) m4kc_tlbp_war(void)
{
return (current_cpu_data.processor_id & 0xffff00) ==
(PRID_COMP_MIPS | PRID_IMP_4KC);
@@ -140,7 +140,7 @@ struct insn {
| (e) << RE_SH \
| (f) << FUNC_SH)
-static struct insn insn_table[] __initdata = {
+static __initdata struct insn insn_table[] = {
{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
@@ -193,7 +193,7 @@ static struct insn insn_table[] __initdata = {
#undef M
-static u32 __init build_rs(u32 arg)
+static __init u32 build_rs(u32 arg)
{
if (arg & ~RS_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -201,7 +201,7 @@ static u32 __init build_rs(u32 arg)
return (arg & RS_MASK) << RS_SH;
}
-static u32 __init build_rt(u32 arg)
+static __init u32 build_rt(u32 arg)
{
if (arg & ~RT_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -209,7 +209,7 @@ static u32 __init build_rt(u32 arg)
return (arg & RT_MASK) << RT_SH;
}
-static u32 __init build_rd(u32 arg)
+static __init u32 build_rd(u32 arg)
{
if (arg & ~RD_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -217,7 +217,7 @@ static u32 __init build_rd(u32 arg)
return (arg & RD_MASK) << RD_SH;
}
-static u32 __init build_re(u32 arg)
+static __init u32 build_re(u32 arg)
{
if (arg & ~RE_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -225,7 +225,7 @@ static u32 __init build_re(u32 arg)
return (arg & RE_MASK) << RE_SH;
}
-static u32 __init build_simm(s32 arg)
+static __init u32 build_simm(s32 arg)
{
if (arg > 0x7fff || arg < -0x8000)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -233,7 +233,7 @@ static u32 __init build_simm(s32 arg)
return arg & 0xffff;
}
-static u32 __init build_uimm(u32 arg)
+static __init u32 build_uimm(u32 arg)
{
if (arg & ~IMM_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -241,7 +241,7 @@ static u32 __init build_uimm(u32 arg)
return arg & IMM_MASK;
}
-static u32 __init build_bimm(s32 arg)
+static __init u32 build_bimm(s32 arg)
{
if (arg > 0x1ffff || arg < -0x20000)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -252,7 +252,7 @@ static u32 __init build_bimm(s32 arg)
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
}
-static u32 __init build_jimm(u32 arg)
+static __init u32 build_jimm(u32 arg)
{
if (arg & ~((JIMM_MASK) << 2))
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -260,7 +260,7 @@ static u32 __init build_jimm(u32 arg)
return (arg >> 2) & JIMM_MASK;
}
-static u32 __init build_func(u32 arg)
+static __init u32 build_func(u32 arg)
{
if (arg & ~FUNC_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -268,7 +268,7 @@ static u32 __init build_func(u32 arg)
return arg & FUNC_MASK;
}
-static u32 __init build_set(u32 arg)
+static __init u32 build_set(u32 arg)
{
if (arg & ~SET_MASK)
printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -315,69 +315,69 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
}
#define I_u1u2u3(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b, unsigned int c) \
{ \
build_insn(buf, insn##op, a, b, c); \
}
#define I_u2u1u3(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b, unsigned int c) \
{ \
build_insn(buf, insn##op, b, a, c); \
}
#define I_u3u1u2(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b, unsigned int c) \
{ \
build_insn(buf, insn##op, b, c, a); \
}
#define I_u1u2s3(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b, signed int c) \
{ \
build_insn(buf, insn##op, a, b, c); \
}
#define I_u2s3u1(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
signed int b, unsigned int c) \
{ \
build_insn(buf, insn##op, c, a, b); \
}
#define I_u2u1s3(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b, signed int c) \
{ \
build_insn(buf, insn##op, b, a, c); \
}
#define I_u1u2(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
unsigned int b) \
{ \
build_insn(buf, insn##op, a, b); \
}
#define I_u1s2(op) \
- static inline void i##op(u32 **buf, unsigned int a, \
+ static inline void __init i##op(u32 **buf, unsigned int a, \
signed int b) \
{ \
build_insn(buf, insn##op, a, b); \
}
#define I_u1(op) \
- static inline void i##op(u32 **buf, unsigned int a) \
+ static inline void __init i##op(u32 **buf, unsigned int a) \
{ \
build_insn(buf, insn##op, a); \
}
#define I_0(op) \
- static inline void i##op(u32 **buf) \
+ static inline void __init i##op(u32 **buf) \
{ \
build_insn(buf, insn##op); \
}
@@ -457,7 +457,7 @@ struct label {
enum label_id lab;
};
-static void __init build_label(struct label **lab, u32 *addr,
+static __init void build_label(struct label **lab, u32 *addr,
enum label_id l)
{
(*lab)->addr = addr;
@@ -526,34 +526,34 @@ L_LA(_r3000_write_probe_fail)
#define i_ehb(buf) i_sll(buf, 0, 0, 3)
#ifdef CONFIG_64BIT
-static int __init __maybe_unused in_compat_space_p(long addr)
+static __init int __maybe_unused in_compat_space_p(long addr)
{
/* Is this address in 32bit compat space? */
return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
}
-static int __init __maybe_unused rel_highest(long val)
+static __init int __maybe_unused rel_highest(long val)
{
return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
}
-static int __init __maybe_unused rel_higher(long val)
+static __init int __maybe_unused rel_higher(long val)
{
return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
}
#endif
-static int __init rel_hi(long val)
+static __init int rel_hi(long val)
{
return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
}
-static int __init rel_lo(long val)
+static __init int rel_lo(long val)
{
return ((val & 0xffff) ^ 0x8000) - 0x8000;
}
-static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
{
#ifdef CONFIG_64BIT
if (!in_compat_space_p(addr)) {
@@ -571,7 +571,7 @@ static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
i_lui(buf, rs, rel_hi(addr));
}
-static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs,
+static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs,
long addr)
{
i_LA_mostly(buf, rs, addr);
@@ -589,7 +589,7 @@ struct reloc {
enum label_id lab;
};
-static void __init r_mips_pc16(struct reloc **rel, u32 *addr,
+static __init void r_mips_pc16(struct reloc **rel, u32 *addr,
enum label_id l)
{
(*rel)->addr = addr;
@@ -614,7 +614,7 @@ static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
}
}
-static void __init resolve_relocs(struct reloc *rel, struct label *lab)
+static __init void resolve_relocs(struct reloc *rel, struct label *lab)
{
struct label *l;
@@ -624,7 +624,7 @@ static void __init resolve_relocs(struct reloc *rel, struct label *lab)
__resolve_relocs(rel, l);
}
-static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
+static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end,
long off)
{
for (; rel->lab != label_invalid; rel++)
@@ -632,7 +632,7 @@ static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
rel->addr += off;
}
-static void __init move_labels(struct label *lab, u32 *first, u32 *end,
+static __init void move_labels(struct label *lab, u32 *first, u32 *end,
long off)
{
for (; lab->lab != label_invalid; lab++)
@@ -640,7 +640,7 @@ static void __init move_labels(struct label *lab, u32 *first, u32 *end,
lab->addr += off;
}
-static void __init copy_handler(struct reloc *rel, struct label *lab,
+static __init void copy_handler(struct reloc *rel, struct label *lab,
u32 *first, u32 *end, u32 *target)
{
long off = (long)(target - first);
@@ -651,7 +651,7 @@ static void __init copy_handler(struct reloc *rel, struct label *lab,
move_labels(lab, first, end, off);
}
-static int __init __maybe_unused insn_has_bdelay(struct reloc *rel,
+static __init int __maybe_unused insn_has_bdelay(struct reloc *rel,
u32 *addr)
{
for (; rel->lab != label_invalid; rel++) {
@@ -743,11 +743,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
* We deliberately chose a buffer size of 128, so we won't scribble
* over anything important on overflow before we panic.
*/
-static u32 tlb_handler[128] __initdata;
+static __initdata u32 tlb_handler[128];
/* simply assume worst case size for labels and relocs */
-static struct label labels[128] __initdata;
-static struct reloc relocs[128] __initdata;
+static __initdata struct label labels[128];
+static __initdata struct reloc relocs[128];
/*
* The R3000 TLB handler is simple.
@@ -801,7 +801,7 @@ static void __init build_r3000_tlb_refill_handler(void)
* other one.To keep things simple, we first assume linear space,
* then we relocate it to the final handler layout as needed.
*/
-static u32 final_handler[64] __initdata;
+static __initdata u32 final_handler[64];
/*
* Hazards
@@ -825,7 +825,7 @@ static u32 final_handler[64] __initdata;
*
* As if we MIPS hackers wouldn't know how to nop pipelines happy ...
*/
-static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
+static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
{
switch (current_cpu_type()) {
/* Found by experiment: R4600 v2.0 needs this, too. */
@@ -849,7 +849,7 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
*/
enum tlb_write_entry { tlb_random, tlb_indexed };
-static void __init build_tlb_write_entry(u32 **p, struct label **l,
+static __init void build_tlb_write_entry(u32 **p, struct label **l,
struct reloc **r,
enum tlb_write_entry wmode)
{
@@ -993,7 +993,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pmd entry.
*/
-static void __init
+static __init void
build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
unsigned int tmp, unsigned int ptr)
{
@@ -1054,7 +1054,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
* BVADDR is the faulting address, PTR is scratch.
* PTR will hold the pgd for vmalloc.
*/
-static void __init
+static __init void
build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
unsigned int bvaddr, unsigned int ptr)
{
@@ -1118,7 +1118,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pgd entry.
*/
-static void __init __maybe_unused
+static __init void __maybe_unused
build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
{
long pgdc = (long)pgd_current;
@@ -1153,7 +1153,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
#endif /* !CONFIG_64BIT */
-static void __init build_adjust_context(u32 **p, unsigned int ctx)
+static __init void build_adjust_context(u32 **p, unsigned int ctx)
{
unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12;
unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1);
@@ -1179,7 +1179,7 @@ static void __init build_adjust_context(u32 **p, unsigned int ctx)
i_andi(p, ctx, ctx, mask);
}
-static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
+static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
{
/*
* Bug workaround for the Nevada. It seems as if under certain
@@ -1204,7 +1204,7 @@ static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
i_ADDU(p, ptr, ptr, tmp); /* add in offset */
}
-static void __init build_update_entries(u32 **p, unsigned int tmp,
+static __init void build_update_entries(u32 **p, unsigned int tmp,
unsigned int ptep)
{
/*
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 89b911e83c0..8f3db32fac8 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
return tsize;
}
-int of_device_uevent(struct device *dev,
- char **envp, int num_envp, char *buffer, int buffer_size)
+int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct of_device *ofdev;
const char *compat;
- int i = 0, length = 0, seen = 0, cplen, sl;
+ int 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))
+ if (add_uevent_var(env, "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))
+ if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
return -ENOMEM;
/* Since the compatible field can contain pretty much anything
@@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev,
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))
+ if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
return -ENOMEM;
sl = strlen (compat) + 1;
@@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev,
seen++;
}
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "OF_COMPATIBLE_N=%d", seen))
+ if (add_uevent_var(env, "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="))
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
-
- sl = of_device_get_modalias(ofdev, &buffer[length-1],
- buffer_size-length);
- if (sl >= (buffer_size-length))
+ sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
+ sizeof(env->buf) - env->buflen);
+ if (sl >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
-
- length += sl;
-
- envp[i] = NULL;
+ env->buflen += sl;
return 0;
}
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index cb22a3557c4..19a5656001c 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
}
-static int vio_hotplug(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
struct device_node *dn;
const char *cp;
- int length;
-
- if (!num_envp)
- return -ENOMEM;
dn = dev->archdata.of_node;
if (!dn)
return -ENODEV;
- cp = of_get_property(dn, "compatible", &length);
+ cp = of_get_property(dn, "compatible", NULL);
if (!cp)
return -ENODEV;
- envp[0] = buffer;
- length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
- vio_dev->type, cp);
- if ((buffer_size - length) <= 0)
- return -ENOMEM;
- envp[1] = NULL;
+ add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
return 0;
}
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index 0caa3d955c3..65b7ae42623 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -18,6 +18,8 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/of.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
@@ -156,18 +158,6 @@ static void __init lite5200_setup_arch(void)
of_node_put(np);
}
#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_start)
- ROOT_DEV = Root_RAM0;
- else
-#endif
-#ifdef CONFIG_ROOT_NFS
- ROOT_DEV = Root_NFS;
-#else
- ROOT_DEV = Root_HDA1;
-#endif
-
}
/*
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 1245b2f517b..095988f13bf 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -77,12 +77,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
{
pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
- dcr_write(msic->dcr_host, msic->dcr_host.base + dcr_n, val);
-}
-
-static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
-{
- return dcr_read(msic->dcr_host, msic->dcr_host.base + dcr_n);
+ dcr_write(msic->dcr_host, dcr_n, val);
}
static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
@@ -91,7 +86,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
u32 write_offset, msi;
int idx;
- write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+ write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
/* write_offset doesn't wrap properly, so we have to mask it */
@@ -306,7 +301,7 @@ static int axon_msi_notify_reboot(struct notifier_block *nb,
list_for_each_entry(msic, &axon_msic_list, list) {
pr_debug("axon_msi: disabling %s\n",
msic->irq_host->of_node->full_name);
- tmp = msic_dcr_read(msic, MSIC_CTRL_REG);
+ tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
}
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index 901236fa0f0..5123e9d4164 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -107,8 +107,6 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
}
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
/* if DEBUG is enabled set_pmode() measures the latency
* of a transition */
policy->cpuinfo.transition_latency = 25000;
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
index 3ae083851b0..1cfb8b0c8fe 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -195,8 +195,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
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);
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 1fe35dab0e9..c04abcc28a7 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -410,7 +410,6 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -ENODEV;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = cur_freq;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 00f50298c34..4dfb4bc242b 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -357,7 +357,6 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
/* secondary CPUs are tied to the primary one by the
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 4bb634a17e4..190ff4b59a5 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -437,18 +437,12 @@ static void ps3_system_bus_shutdown(struct device *_dev)
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}
-static int ps3_system_bus_uevent(struct device *_dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
{
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
- int i = 0, length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "MODALIAS=ps3:%d",
- dev->match_id))
+ if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
return -ENOMEM;
-
- envp[i] = NULL;
return 0;
}
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 4d3ba63bba7..5eaf3e3f4b8 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -117,7 +117,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
transfered = 0;
bio_for_each_segment(vec, bio, idx) {
if (unlikely(phys_mem + vec->bv_len > phys_end)) {
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
rc = -ERANGE;
break;
}
@@ -131,7 +131,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
phys_mem += vec->bv_len;
transfered += vec->bv_len;
}
- bio_endio(bio, transfered, 0);
+ bio_endio(bio, 0);
return rc;
}
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index ab11c0b2902..427027c7ea0 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -126,13 +126,13 @@ dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
}
EXPORT_SYMBOL_GPL(dcr_map);
-void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c)
+void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
{
dcr_host_t h = host;
if (h.token == NULL)
return;
- h.token += dcr_n * h.stride;
+ h.token += host.base * h.stride;
iounmap(h.token);
h.token = NULL;
}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 893e65439e8..e47938899a9 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -156,7 +156,7 @@ static inline u32 _mpic_read(enum mpic_reg_type type,
switch(type) {
#ifdef CONFIG_PPC_DCR
case mpic_access_dcr:
- return dcr_read(rb->dhost, rb->dhost.base + reg);
+ return dcr_read(rb->dhost, reg);
#endif
case mpic_access_mmio_be:
return in_be32(rb->base + (reg >> 2));
@@ -173,7 +173,7 @@ static inline void _mpic_write(enum mpic_reg_type type,
switch(type) {
#ifdef CONFIG_PPC_DCR
case mpic_access_dcr:
- return dcr_write(rb->dhost, rb->dhost.base + reg, value);
+ return dcr_write(rb->dhost, reg, value);
#endif
case mpic_access_mmio_be:
return out_be32(rb->base + (reg >> 2), value);
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 62391fb1f61..ac61cf43a7d 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -547,8 +547,7 @@ static void __cpuinit appldata_online_cpu(int cpu)
spin_unlock(&appldata_timer_lock);
}
-static void
-appldata_offline_cpu(int cpu)
+static void __cpuinit appldata_offline_cpu(int cpu)
{
del_virt_timer(&per_cpu(appldata_timer, cpu));
if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -560,9 +559,9 @@ appldata_offline_cpu(int cpu)
spin_unlock(&appldata_timer_lock);
}
-static int __cpuinit
-appldata_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+ unsigned long action,
+ void *hcpu)
{
switch (action) {
case CPU_ONLINE:
@@ -608,63 +607,15 @@ static int __init appldata_init(void)
register_hotcpu_notifier(&appldata_nb);
appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
-#ifdef MODULE
- appldata_dir_table[0].de->owner = THIS_MODULE;
- appldata_table[0].de->owner = THIS_MODULE;
- appldata_table[1].de->owner = THIS_MODULE;
-#endif
P_DEBUG("Base interface initialized.\n");
return 0;
}
-/*
- * appldata_exit()
- *
- * stop timer, unregister /proc entries
- */
-static void __exit appldata_exit(void)
-{
- struct list_head *lh;
- struct appldata_ops *ops;
- int rc, i;
+__initcall(appldata_init);
- P_DEBUG("Unloading module ...\n");
- /*
- * ops list should be empty, but just in case something went wrong...
- */
- spin_lock(&appldata_ops_lock);
- list_for_each(lh, &appldata_ops_list) {
- ops = list_entry(lh, struct appldata_ops, list);
- rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
- (unsigned long) ops->data, ops->size,
- ops->mod_lvl);
- if (rc != 0) {
- P_ERROR("STOP DIAG 0xDC for %s failed, "
- "return code: %d\n", ops->name, rc);
- }
- }
- spin_unlock(&appldata_ops_lock);
-
- for_each_online_cpu(i)
- appldata_offline_cpu(i);
-
- appldata_timer_active = 0;
-
- unregister_sysctl_table(appldata_sysctl_header);
-
- destroy_workqueue(appldata_wq);
- P_DEBUG("... module unloaded!\n");
-}
/**************************** init / exit <END> ******************************/
-
-module_init(appldata_init);
-module_exit(appldata_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerald Schaefer");
-MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
-
EXPORT_SYMBOL_GPL(appldata_register_ops);
EXPORT_SYMBOL_GPL(appldata_unregister_ops);
EXPORT_SYMBOL_GPL(appldata_diag);
diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c
index d1c76fe10f2..f4932c22ebe 100644
--- a/arch/s390/kernel/audit.c
+++ b/arch/s390/kernel/audit.c
@@ -2,6 +2,7 @@
#include <linux/types.h>
#include <linux/audit.h>
#include <asm/unistd.h>
+#include "audit.h"
static unsigned dir_class[] = {
#include <asm-generic/audit_dir_write.h>
@@ -40,7 +41,6 @@ int audit_classify_arch(int arch)
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_COMPAT
- extern int s390_classify_syscall(unsigned);
if (abi == AUDIT_ARCH_S390)
return s390_classify_syscall(syscall);
#endif
@@ -61,11 +61,6 @@ int audit_classify_syscall(int abi, unsigned syscall)
static int __init audit_classes_init(void)
{
#ifdef CONFIG_COMPAT
- extern __u32 s390_dir_class[];
- extern __u32 s390_write_class[];
- extern __u32 s390_read_class[];
- extern __u32 s390_chattr_class[];
- extern __u32 s390_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h
new file mode 100644
index 00000000000..12b56f4b5a7
--- /dev/null
+++ b/arch/s390/kernel/audit.h
@@ -0,0 +1,15 @@
+#ifndef __ARCH_S390_KERNEL_AUDIT_H
+#define __ARCH_S390_KERNEL_AUDIT_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_COMPAT
+extern int s390_classify_syscall(unsigned);
+extern __u32 s390_dir_class[];
+extern __u32 s390_write_class[];
+extern __u32 s390_read_class[];
+extern __u32 s390_chattr_class[];
+extern __u32 s390_signal_class[];
+#endif /* CONFIG_COMPAT */
+
+#endif /* __ARCH_S390_KERNEL_AUDIT_H */
diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c
index 0569f5126e4..d6487bf879e 100644
--- a/arch/s390/kernel/compat_audit.c
+++ b/arch/s390/kernel/compat_audit.c
@@ -1,5 +1,6 @@
#undef __s390x__
#include <asm/unistd.h>
+#include "audit.h"
unsigned s390_dir_class[] = {
#include <asm-generic/audit_dir_write.h>
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 6c89f30c8e3..d8c1131e081 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/cpcmd.c
*
* S390 version
- * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 1999,2007
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Christian Borntraeger (cborntra@de.ibm.com),
*/
@@ -21,6 +21,49 @@
static DEFINE_SPINLOCK(cpcmd_lock);
static char cpcmd_buf[241];
+static int diag8_noresponse(int cmdlen)
+{
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = cmdlen;
+
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %1,%0,0x8\n"
+ " sam64\n"
+#endif /* CONFIG_64BIT */
+ : "+d" (reg3) : "d" (reg2) : "cc");
+ return reg3;
+}
+
+static int diag8_response(int cmdlen, char *response, int *rlen)
+{
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = (addr_t) response;
+ register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+ register unsigned long reg5 asm ("5") = *rlen;
+
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %2,%0,0x8\n"
+ " brc 8,1f\n"
+ " ar %1,%4\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %2,%0,0x8\n"
+ " sam64\n"
+ " brc 8,1f\n"
+ " agr %1,%4\n"
+#endif /* CONFIG_64BIT */
+ "1:\n"
+ : "+d" (reg4), "+d" (reg5)
+ : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
+ *rlen = reg5;
+ return reg4;
+}
+
/*
* __cpcmd has some restrictions over cpcmd
* - the response buffer must reside below 2GB (if any)
@@ -28,59 +71,27 @@ static char cpcmd_buf[241];
*/
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{
- unsigned cmdlen;
- int return_code, return_len;
+ int cmdlen;
+ int rc;
+ int response_len;
cmdlen = strlen(cmd);
BUG_ON(cmdlen > 240);
memcpy(cpcmd_buf, cmd, cmdlen);
ASCEBC(cpcmd_buf, cmdlen);
- if (response != NULL && rlen > 0) {
- register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
- register unsigned long reg3 asm ("3") = (addr_t) response;
- register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
- register unsigned long reg5 asm ("5") = rlen;
-
+ if (response) {
memset(response, 0, rlen);
- asm volatile(
-#ifndef CONFIG_64BIT
- " diag %2,%0,0x8\n"
- " brc 8,1f\n"
- " ar %1,%4\n"
-#else /* CONFIG_64BIT */
- " sam31\n"
- " diag %2,%0,0x8\n"
- " sam64\n"
- " brc 8,1f\n"
- " agr %1,%4\n"
-#endif /* CONFIG_64BIT */
- "1:\n"
- : "+d" (reg4), "+d" (reg5)
- : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
- return_code = (int) reg4;
- return_len = (int) reg5;
- EBCASC(response, rlen);
+ response_len = rlen;
+ rc = diag8_response(cmdlen, response, &rlen);
+ EBCASC(response, response_len);
} else {
- register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
- register unsigned long reg3 asm ("3") = cmdlen;
- return_len = 0;
- asm volatile(
-#ifndef CONFIG_64BIT
- " diag %1,%0,0x8\n"
-#else /* CONFIG_64BIT */
- " sam31\n"
- " diag %1,%0,0x8\n"
- " sam64\n"
-#endif /* CONFIG_64BIT */
- : "+d" (reg3) : "d" (reg2) : "cc");
- return_code = (int) reg3;
+ rc = diag8_noresponse(cmdlen);
}
- if (response_code != NULL)
- *response_code = return_code;
- return return_len;
+ if (response_code)
+ *response_code = rc;
+ return rlen;
}
-
EXPORT_SYMBOL(__cpcmd);
int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -109,5 +120,4 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
}
return len;
}
-
EXPORT_SYMBOL(cpcmd);
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 50d2235df73..c14a336f630 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1162,6 +1162,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
unsigned int value;
char separator;
char *ptr;
+ int i;
ptr = buffer;
insn = find_insn(code);
@@ -1169,7 +1170,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
ptr += sprintf(ptr, "%.5s\t", insn->name);
/* Extract the operands. */
separator = 0;
- for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
+ for (ops = formats[insn->format] + 1, i = 0;
+ *ops != 0 && i < 6; ops++, i++) {
operand = operands + *ops;
value = extract_operand(code, operand);
if ((operand->flags & OPERAND_INDEX) && value == 0)
@@ -1241,7 +1243,6 @@ void show_code(struct pt_regs *regs)
}
/* Find a starting point for the disassembly. */
while (start < 32) {
- hops = 0;
for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
if (!find_insn(code + start + i))
break;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index f3bceb16532..139ca153d5c 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -68,9 +68,15 @@ STACK_SIZE = 1 << STACK_SHIFT
l %r1,BASED(.Ltrace_irq_off)
basr %r14,%r1
.endm
+
+ .macro LOCKDEP_SYS_EXIT
+ l %r1,BASED(.Llockdep_sys_exit)
+ basr %r14,%r1
+ .endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
+#define LOCKDEP_SYS_EXIT
#endif
/*
@@ -260,6 +266,7 @@ sysc_return:
bno BASED(sysc_leave)
tm __TI_flags+3(%r9),_TIF_WORK_SVC
bnz BASED(sysc_work) # there is work to do (signals etc.)
+ LOCKDEP_SYS_EXIT
sysc_leave:
RESTORE_ALL __LC_RETURN_PSW,1
@@ -283,6 +290,7 @@ sysc_work:
bo BASED(sysc_restart)
tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
bo BASED(sysc_singlestep)
+ LOCKDEP_SYS_EXIT
b BASED(sysc_leave)
#
@@ -572,6 +580,7 @@ io_return:
#endif
tm __TI_flags+3(%r9),_TIF_WORK_INT
bnz BASED(io_work) # there is work to do (signals etc.)
+ LOCKDEP_SYS_EXIT
io_leave:
RESTORE_ALL __LC_RETURN_PSW,0
io_done:
@@ -618,6 +627,7 @@ io_work_loop:
bo BASED(io_reschedule)
tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
bnz BASED(io_sigpending)
+ LOCKDEP_SYS_EXIT
b BASED(io_leave)
#
@@ -1040,6 +1050,8 @@ cleanup_io_leave_insn:
.Ltrace_irq_on: .long trace_hardirqs_on
.Ltrace_irq_off:
.long trace_hardirqs_off
+.Llockdep_sys_exit:
+ .long lockdep_sys_exit
#endif
.Lcritical_start:
.long __critical_start + 0x80000000
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 9c0d5cc8269..05e26d1fdf4 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -66,9 +66,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
.macro TRACE_IRQS_OFF
brasl %r14,trace_hardirqs_off
.endm
+
+ .macro LOCKDEP_SYS_EXIT
+ brasl %r14,lockdep_sys_exit
+ .endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
+#define LOCKDEP_SYS_EXIT
#endif
.macro STORE_TIMER lc_offset
@@ -255,6 +260,7 @@ sysc_return:
jno sysc_leave
tm __TI_flags+7(%r9),_TIF_WORK_SVC
jnz sysc_work # there is work to do (signals etc.)
+ LOCKDEP_SYS_EXIT
sysc_leave:
RESTORE_ALL __LC_RETURN_PSW,1
@@ -278,6 +284,7 @@ sysc_work:
jo sysc_restart
tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
jo sysc_singlestep
+ LOCKDEP_SYS_EXIT
j sysc_leave
#
@@ -558,6 +565,7 @@ io_return:
#endif
tm __TI_flags+7(%r9),_TIF_WORK_INT
jnz io_work # there is work to do (signals etc.)
+ LOCKDEP_SYS_EXIT
io_leave:
RESTORE_ALL __LC_RETURN_PSW,0
io_done:
@@ -605,6 +613,7 @@ io_work_loop:
jo io_reschedule
tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
jnz io_sigpending
+ LOCKDEP_SYS_EXIT
j io_leave
#
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 8b8f136d9cc..66b51901c87 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -735,10 +735,10 @@ void do_reipl(void)
case REIPL_METHOD_CCW_VM:
reipl_get_ascii_loadparm(loadparm);
if (strlen(loadparm) == 0)
- sprintf(buf, "IPL %X",
+ sprintf(buf, "IPL %X CLEAR",
reipl_block_ccw->ipl_info.ccw.devno);
else
- sprintf(buf, "IPL %X LOADPARM '%s'",
+ sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
reipl_block_ccw->ipl_info.ccw.devno, loadparm);
__cpcmd(buf, NULL, 0, NULL);
break;
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index b4622a3889b..849120e3e28 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -2,6 +2,7 @@
* Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
+#include <asm/page.h>
#include <asm-generic/vmlinux.lds.h>
#ifndef CONFIG_64BIT
@@ -18,121 +19,142 @@ jiffies = jiffies_64;
SECTIONS
{
- . = 0x00000000;
- _text = .; /* Text and read-only data */
- .text : {
- *(.text.head)
+ . = 0x00000000;
+ .text : {
+ _text = .; /* Text and read-only data */
+ *(.text.head)
TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.fixup)
- *(.gnu.warning)
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
} = 0x0700
- _etext = .; /* End of text section */
+ _etext = .; /* End of text section */
- RODATA
+ RODATA
#ifdef CONFIG_SHARED_KERNEL
- . = ALIGN(1048576); /* VM shared segments are 1MB aligned */
+ . = ALIGN(0x100000); /* VM shared segments are 1MB aligned */
#endif
- . = ALIGN(4096);
- _eshared = .; /* End of shareable data */
-
- . = ALIGN(16); /* Exception table */
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
- NOTES
-
- BUG_TABLE
-
- .data : { /* Data */
- DATA_DATA
- CONSTRUCTORS
- }
-
- . = ALIGN(4096);
- __nosave_begin = .;
- .data_nosave : { *(.data.nosave) }
- . = ALIGN(4096);
- __nosave_end = .;
-
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
- . = ALIGN(256);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
- . = ALIGN(256);
- .data.read_mostly : { *(.data.read_mostly) }
- _edata = .; /* End of data section */
-
- . = ALIGN(8192); /* init_task */
- .data.init_task : { *(.data.init_task) }
-
- /* will be freed after init */
- . = ALIGN(4096); /* Init code and data */
- __init_begin = .;
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
- /*
- * .exit.text is discarded at runtime, not link time,
- * to deal with references from __bug_table
- */
- .exit.text : { *(.exit.text) }
-
- .init.data : { *(.init.data) }
- . = ALIGN(256);
- __setup_start = .;
- .init.setup : { *(.init.setup) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : {
- INITCALLS
- }
- __initcall_end = .;
- __con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
- __con_initcall_end = .;
- SECURITY_INIT
+ . = ALIGN(PAGE_SIZE);
+ _eshared = .; /* End of shareable data */
+
+ . = ALIGN(16); /* Exception table */
+ __ex_table : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
+
+ NOTES
+ BUG_TABLE
+
+ .data : { /* Data */
+ DATA_DATA
+ CONSTRUCTORS
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .data_nosave : {
+ __nosave_begin = .;
+ *(.data.nosave)
+ }
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
+
+ . = ALIGN(PAGE_SIZE);
+ .data.page_aligned : {
+ *(.data.idt)
+ }
+
+ . = ALIGN(0x100);
+ .data.cacheline_aligned : {
+ *(.data.cacheline_aligned)
+ }
+
+ . = ALIGN(0x100);
+ .data.read_mostly : {
+ *(.data.read_mostly)
+ }
+ _edata = .; /* End of data section */
+
+ . = ALIGN(2 * PAGE_SIZE); /* init_task */
+ .data.init_task : {
+ *(.data.init_task)
+ }
+
+ /* will be freed after init */
+ . = ALIGN(PAGE_SIZE); /* Init code and data */
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
+ /*
+ * .exit.text is discarded at runtime, not link time,
+ * to deal with references from __bug_table
+ */
+ .exit.text : {
+ *(.exit.text)
+ }
+
+ .init.data : {
+ *(.init.data)
+ }
+ . = ALIGN(0x100);
+ .init.setup : {
+ __setup_start = .;
+ *(.init.setup)
+ __setup_end = .;
+ }
+ .initcall.init : {
+ __initcall_start = .;
+ INITCALLS
+ __initcall_end = .;
+ }
+
+ .con_initcall.init : {
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+ __con_initcall_end = .;
+ }
+ SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(256);
- __initramfs_start = .;
- .init.ramfs : { *(.init.initramfs) }
- . = ALIGN(2);
- __initramfs_end = .;
+ . = ALIGN(0x100);
+ .init.ramfs : {
+ __initramfs_start = .;
+ *(.init.ramfs)
+ . = ALIGN(2);
+ __initramfs_end = .;
+ }
#endif
- PERCPU(4096)
- . = ALIGN(4096);
- __init_end = .;
- /* freed after init ends here */
-
- __bss_start = .; /* BSS */
- .bss : { *(.bss) }
- . = ALIGN(2);
- __bss_stop = .;
-
- _end = . ;
-
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exit.data) *(.exitcall.exit)
- }
-
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
+
+ PERCPU(PAGE_SIZE)
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .; /* freed after init ends here */
+
+ /* BSS */
+ .bss : {
+ __bss_start = .;
+ *(.bss)
+ . = ALIGN(2);
+ __bss_stop = .;
+ }
+
+ _end = . ;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ *(.exit.data)
+ *(.exitcall.exit)
+ }
+
+ /* Debugging sections. */
+ STABS_DEBUG
+ DWARF_DEBUG
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 54055194e9a..4c1ac341ec8 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -468,7 +468,7 @@ typedef struct {
__u64 refselmk;
__u64 refcmpmk;
__u64 reserved;
-} __attribute__ ((packed)) pfault_refbk_t;
+} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
int pfault_init(void)
{
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 54878f07cf0..44982c1dfa2 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -118,7 +118,7 @@ endchoice
config SH_FPU
bool "FPU support"
- depends on CPU_SH4
+ depends on CPU_HAS_FPU
default y
help
Selecting this option will enable support for SH processors that
@@ -178,12 +178,6 @@ config CPU_HAS_INTEVT
config CPU_HAS_MASKREG_IRQ
bool
-config CPU_HAS_INTC_IRQ
- bool
-
-config CPU_HAS_INTC2_IRQ
- bool
-
config CPU_HAS_IPR_IRQ
bool
@@ -205,6 +199,9 @@ config CPU_HAS_PTEA
config CPU_HAS_DSP
bool
+config CPU_HAS_FPU
+ bool
+
endmenu
menu "Board support"
@@ -258,7 +255,6 @@ config SH_7780_SOLUTION_ENGINE
bool "SolutionEngine7780"
select SOLUTION_ENGINE
select SYS_SUPPORTS_PCI
- select CPU_HAS_INTC2_IRQ
depends on CPU_SUBTYPE_SH7780
help
Select 7780 SolutionEngine if configuring for a Renesas SH7780
@@ -309,7 +305,7 @@ config SH_MPC1211
config SH_SH03
bool "Interface CTP/PCI-SH03"
- depends on CPU_SUBTYPE_SH7751 && BROKEN
+ depends on CPU_SUBTYPE_SH7751
select CPU_HAS_IPR_IRQ
select SYS_SUPPORTS_PCI
help
@@ -395,11 +391,22 @@ config SH_LBOX_RE2
help
Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2.
+config SH_X3PROTO
+ bool "SH-X3 Prototype board"
+ depends on CPU_SUBTYPE_SHX3
+
+config SH_MAGIC_PANEL_R2
+ bool "Magic Panel R2"
+ depends on CPU_SUBTYPE_SH7720
+ help
+ Select Magic Panel R2 if configuring for Magic Panel R2.
+
endmenu
source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
source "arch/sh/boards/renesas/r7780rp/Kconfig"
+source "arch/sh/boards/magicpanelr2/Kconfig"
menu "Timer and clock configuration"
@@ -563,10 +570,19 @@ config NR_CPUS
source "kernel/Kconfig.preempt"
-config NODES_SHIFT
- int
- default "1"
- depends on NEED_MULTIPLE_NODES
+config GUSA
+ def_bool y
+ depends on !SMP
+ help
+ This enables support for gUSA (general UserSpace Atomicity).
+ This is the default implementation for both UP and non-ll/sc
+ CPUs, and is used by the libc, amongst others.
+
+ For additional information, design information can be found
+ in <http://lc.linux.or.jp/lc2002/papers/niibe0919p.pdf>.
+
+ This should only be disabled for special cases where alternate
+ atomicity implementations exist.
endmenu
@@ -659,6 +675,17 @@ config SUPERHYWAY
tristate "SuperHyway Bus support"
depends on CPU_SUBTYPE_SH4_202
+config MAPLE
+ bool "Maple Bus support"
+ depends on SH_DREAMCAST
+ help
+ The Maple Bus is SEGA's serial communication bus for peripherals
+ on the Dreamcast. Without this bus support you won't be able to
+ get your Dreamcast keyboard etc to work, so most users
+ probably want to say 'Y' here, unless you are only using the
+ Dreamcast with a serial line terminal or a remote network
+ connection.
+
config CF_ENABLER
bool "Compact Flash Enabler support"
depends on SOLUTION_ENGINE || SH_SH03
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 52f6a99c8ec..b507b501f0c 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -28,13 +28,17 @@ config EARLY_SCIF_CONSOLE
serial I/O.
config EARLY_SCIF_CONSOLE_PORT
- hex "SCIF port for early console"
+ hex
depends on EARLY_SCIF_CONSOLE
default "0xffe00000" if CPU_SUBTYPE_SH7780
+ default "0xffea0000" if CPU_SUBTYPE_SH7785
default "0xfffe9800" if CPU_SUBTYPE_SH7206
default "0xf8420000" if CPU_SUBTYPE_SH7619
default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
+ default "0xa4430000" if CPU_SUBTYPE_SH7720
+ default "0xffc30000" if CPU_SUBTYPE_SHX3
default "0xffe80000" if CPU_SH4
+ default "0x00000000"
config EARLY_PRINTK
bool "Early printk support"
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 97ac58682d0..a0a2083aad3 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -118,6 +118,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += renesas/systemh
machdir-$(CONFIG_SH_EDOSK7705) += renesas/edosk7705
machdir-$(CONFIG_SH_HIGHLANDER) += renesas/r7780rp
machdir-$(CONFIG_SH_7710VOIPGW) += renesas/sh7710voipgw
+machdir-$(CONFIG_SH_X3PROTO) += renesas/x3proto
machdir-$(CONFIG_SH_SH4202_MICRODEV) += superh/microdev
machdir-$(CONFIG_SH_LANDISK) += landisk
machdir-$(CONFIG_SH_TITAN) += titan
@@ -125,6 +126,7 @@ machdir-$(CONFIG_SH_SHMIN) += shmin
machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) += se/7206
machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) += se/7619
machdir-$(CONFIG_SH_LBOX_RE2) += lboxre2
+machdir-$(CONFIG_SH_MAGIC_PANEL_R2) += magicpanelr2
incdir-y := $(notdir $(machdir-y))
@@ -135,7 +137,7 @@ endif
# Companion chips
core-$(CONFIG_HD6446X_SERIES) += arch/sh/cchips/hd6446x/
-core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/
+core-$(CONFIG_MFD_SM501) += arch/sh/cchips/voyagergx/
cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2
cpuincdir-$(CONFIG_CPU_SH2A) := cpu-sh2a
diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c
index d1c1460c8a0..640ca2a74f1 100644
--- a/arch/sh/boards/hp6xx/hp6xx_apm.c
+++ b/arch/sh/boards/hp6xx/hp6xx_apm.c
@@ -20,9 +20,9 @@
#define APM_CRITICAL 10
#define APM_LOW 30
-#define HP680_BATTERY_MAX 875
-#define HP680_BATTERY_MIN 600
-#define HP680_BATTERY_AC_ON 900
+#define HP680_BATTERY_MAX 898
+#define HP680_BATTERY_MIN 486
+#define HP680_BATTERY_AC_ON 1023
#define MODNAME "hp6x0_apm"
@@ -65,7 +65,7 @@ static void hp6x0_apm_get_power_status(struct apm_power_info *info)
static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
{
- if (!apm_suspended)
+ if (!APM_DISABLED)
apm_queue_event(APM_USER_SUSPEND);
return IRQ_HANDLED;
@@ -91,7 +91,6 @@ static int __init hp6x0_apm_init(void)
static void __exit hp6x0_apm_exit(void)
{
free_irq(HP680_BTN_IRQ, 0);
- apm_get_info = NULL;
}
module_init(hp6x0_apm_init);
diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
index 7ae708930ba..2f414ac3c69 100644
--- a/arch/sh/boards/hp6xx/setup.c
+++ b/arch/sh/boards/hp6xx/setup.c
@@ -7,7 +7,7 @@
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
- * Setup code for an HP680 (internal peripherials only)
+ * Setup code for HP620/HP660/HP680/HP690 (internal peripherials only)
*/
#include <linux/types.h>
#include <linux/init.h>
@@ -19,7 +19,7 @@
#include <asm/cpu/dac.h>
#define SCPCR 0xa4000116
-#define SCPDR 0xa4000136
+#define SCPDR 0xa4000136
/* CF Slot */
static struct resource cf_ide_resources[] = {
@@ -34,7 +34,7 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
- .start = 93,
+ .start = 77,
.flags = IORESOURCE_IRQ,
},
};
@@ -46,10 +46,22 @@ static struct platform_device cf_ide_device = {
.resource = cf_ide_resources,
};
+static struct platform_device jornadakbd_device = {
+ .name = "jornada680_kbd",
+ .id = -1,
+};
+
static struct platform_device *hp6xx_devices[] __initdata = {
- &cf_ide_device,
+ &cf_ide_device,
+ &jornadakbd_device,
};
+static void __init hp6xx_init_irq(void)
+{
+ /* Gets touchscreen and powerbutton IRQ working */
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
static int __init hp6xx_devices_setup(void)
{
return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices));
@@ -61,11 +73,11 @@ static void __init hp6xx_setup(char **cmdline_p)
u16 v;
v = inw(HD64461_STBCR);
- v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
- HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
- HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
- HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
- HD64461_STBCR_SAFECKE_IST;
+ v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
+ HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+ HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
+ HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST|
+ HD64461_STBCR_SAFECKE_IST;
#ifndef CONFIG_HD64461_ENABLER
v |= HD64461_STBCR_SPC1ST;
#endif
@@ -101,6 +113,9 @@ device_initcall(hp6xx_devices_setup);
static struct sh_machine_vector mv_hp6xx __initmv = {
.mv_name = "hp6xx",
.mv_setup = hp6xx_setup,
- .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
+ /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
+ .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
.mv_irq_demux = hd64461_irq_demux,
+ /* Enable IRQ0 -> IRQ3 in IRQ_MODE */
+ .mv_init_irq = hp6xx_init_irq,
};
diff --git a/arch/sh/boards/magicpanelr2/Kconfig b/arch/sh/boards/magicpanelr2/Kconfig
new file mode 100644
index 00000000000..b0abddc3e84
--- /dev/null
+++ b/arch/sh/boards/magicpanelr2/Kconfig
@@ -0,0 +1,13 @@
+if SH_MAGIC_PANEL_R2
+
+menu "Magic Panel R2 options"
+
+config SH_MAGIC_PANEL_R2_VERSION
+ int SH_MAGIC_PANEL_R2_VERSION
+ default "3"
+ help
+ Set the version of the Magic Panel R2
+
+endmenu
+
+endif
diff --git a/arch/sh/boards/magicpanelr2/Makefile b/arch/sh/boards/magicpanelr2/Makefile
new file mode 100644
index 00000000000..7a6d586b907
--- /dev/null
+++ b/arch/sh/boards/magicpanelr2/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Magic Panel specific parts
+#
+
+obj-y := setup.o \ No newline at end of file
diff --git a/arch/sh/boards/magicpanelr2/setup.c b/arch/sh/boards/magicpanelr2/setup.c
new file mode 100644
index 00000000000..f3b8b07ea5d
--- /dev/null
+++ b/arch/sh/boards/magicpanelr2/setup.c
@@ -0,0 +1,394 @@
+/*
+ * linux/arch/sh/boards/magicpanel/setup.c
+ *
+ * Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ * Magic Panel Release 2 board setup
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/map.h>
+#include <asm/magicpanelr2.h>
+#include <asm/heartbeat.h>
+
+#define LAN9115_READY (ctrl_inl(0xA8000084UL) & 0x00000001UL)
+
+/* Prefer cmdline over RedBoot */
+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
+
+/* Wait until reset finished. Timeout is 100ms. */
+static int __init ethernet_reset_finished(void)
+{
+ int i;
+
+ if (LAN9115_READY)
+ return 1;
+
+ for (i = 0; i < 10; ++i) {
+ mdelay(10);
+ if (LAN9115_READY)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void __init reset_ethernet(void)
+{
+ /* PMDR: LAN_RESET=on */
+ CLRBITS_OUTB(0x10, PORT_PMDR);
+
+ udelay(200);
+
+ /* PMDR: LAN_RESET=off */
+ SETBITS_OUTB(0x10, PORT_PMDR);
+}
+
+static void __init setup_chip_select(void)
+{
+ /* CS2: LAN (0x08000000 - 0x0bffffff) */
+ /* no idle cycles, normal space, 8 bit data bus */
+ ctrl_outl(0x36db0400, CS2BCR);
+ /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+ ctrl_outl(0x000003c0, CS2WCR);
+
+ /* CS4: CAN1 (0xb0000000 - 0xb3ffffff) */
+ /* no idle cycles, normal space, 8 bit data bus */
+ ctrl_outl(0x00000200, CS4BCR);
+ /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+ ctrl_outl(0x00100981, CS4WCR);
+
+ /* CS5a: CAN2 (0xb4000000 - 0xb5ffffff) */
+ /* no idle cycles, normal space, 8 bit data bus */
+ ctrl_outl(0x00000200, CS5ABCR);
+ /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+ ctrl_outl(0x00100981, CS5AWCR);
+
+ /* CS5b: CAN3 (0xb6000000 - 0xb7ffffff) */
+ /* no idle cycles, normal space, 8 bit data bus */
+ ctrl_outl(0x00000200, CS5BBCR);
+ /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+ ctrl_outl(0x00100981, CS5BWCR);
+
+ /* CS6a: Rotary (0xb8000000 - 0xb9ffffff) */
+ /* no idle cycles, normal space, 8 bit data bus */
+ ctrl_outl(0x00000200, CS6ABCR);
+ /* (SW:1.5 WR:3 HW:1.5), no ext. wait */
+ ctrl_outl(0x001009C1, CS6AWCR);
+}
+
+static void __init setup_port_multiplexing(void)
+{
+ /* A7 GPO(LED8); A6 GPO(LED7); A5 GPO(LED6); A4 GPO(LED5);
+ * A3 GPO(LED4); A2 GPO(LED3); A1 GPO(LED2); A0 GPO(LED1);
+ */
+ ctrl_outw(0x5555, PORT_PACR); /* 01 01 01 01 01 01 01 01 */
+
+ /* B7 GPO(RST4); B6 GPO(RST3); B5 GPO(RST2); B4 GPO(RST1);
+ * B3 GPO(PB3); B2 GPO(PB2); B1 GPO(PB1); B0 GPO(PB0);
+ */
+ ctrl_outw(0x5555, PORT_PBCR); /* 01 01 01 01 01 01 01 01 */
+
+ /* C7 GPO(PC7); C6 GPO(PC6); C5 GPO(PC5); C4 GPO(PC4);
+ * C3 LCD_DATA3; C2 LCD_DATA2; C1 LCD_DATA1; C0 LCD_DATA0;
+ */
+ ctrl_outw(0x5500, PORT_PCCR); /* 01 01 01 01 00 00 00 00 */
+
+ /* D7 GPO(PD7); D6 GPO(PD6); D5 GPO(PD5); D4 GPO(PD4);
+ * D3 GPO(PD3); D2 GPO(PD2); D1 GPO(PD1); D0 GPO(PD0);
+ */
+ ctrl_outw(0x5555, PORT_PDCR); /* 01 01 01 01 01 01 01 01 */
+
+ /* E7 (x); E6 GPI(nu); E5 GPI(nu); E4 LCD_M_DISP;
+ * E3 LCD_CL1; E2 LCD_CL2; E1 LCD_DON; E0 LCD_FLM;
+ */
+ ctrl_outw(0x3C00, PORT_PECR); /* 00 11 11 00 00 00 00 00 */
+
+ /* F7 (x); F6 DA1(VLCD); F5 DA0(nc); F4 AN3;
+ * F3 AN2(MID_AD); F2 AN1(EARTH_AD); F1 AN0(TEMP); F0 GPI+(nc);
+ */
+ ctrl_outw(0x0002, PORT_PFCR); /* 00 00 00 00 00 00 00 10 */
+
+ /* G7 (x); G6 IRQ5(TOUCH_BUSY); G5 IRQ4(TOUCH_IRQ); G4 GPI(KEY2);
+ * G3 GPI(KEY1); G2 GPO(LED11); G1 GPO(LED10); G0 GPO(LED9);
+ */
+ ctrl_outw(0x03D5, PORT_PGCR); /* 00 00 00 11 11 01 01 01 */
+
+ /* H7 (x); H6 /RAS(BRAS); H5 /CAS(BCAS); H4 CKE(BCKE);
+ * H3 GPO(EARTH_OFF); H2 GPO(EARTH_TEST); H1 USB2_PWR; H0 USB1_PWR;
+ */
+ ctrl_outw(0x0050, PORT_PHCR); /* 00 00 00 00 01 01 00 00 */
+
+ /* J7 (x); J6 AUDCK; J5 ASEBRKAK; J4 AUDATA3;
+ * J3 AUDATA2; J2 AUDATA1; J1 AUDATA0; J0 AUDSYNC;
+ */
+ ctrl_outw(0x0000, PORT_PJCR); /* 00 00 00 00 00 00 00 00 */
+
+ /* K7 (x); K6 (x); K5 (x); K4 (x);
+ * K3 PINT7(/PWR2); K2 PINT6(/PWR1); K1 PINT5(nu); K0 PINT4(FLASH_READY)
+ */
+ ctrl_outw(0x00FF, PORT_PKCR); /* 00 00 00 00 11 11 11 11 */
+
+ /* L7 TRST; L6 TMS; L5 TDO; L4 TDI;
+ * L3 TCK; L2 (x); L1 (x); L0 (x);
+ */
+ ctrl_outw(0x0000, PORT_PLCR); /* 00 00 00 00 00 00 00 00 */
+
+ /* M7 GPO(CURRENT_SINK); M6 GPO(PWR_SWITCH); M5 GPO(LAN_SPEED);
+ * M4 GPO(LAN_RESET); M3 GPO(BUZZER); M2 GPO(LCD_BL);
+ * M1 CS5B(CAN3_CS); M0 GPI+(nc);
+ */
+ ctrl_outw(0x5552, PORT_PMCR); /* 01 01 01 01 01 01 00 10 */
+
+ /* CURRENT_SINK=off, PWR_SWITCH=off, LAN_SPEED=100MBit,
+ * LAN_RESET=off, BUZZER=off, LCD_BL=off
+ */
+#if CONFIG_SH_MAGIC_PANEL_R2_VERSION == 2
+ ctrl_outb(0x30, PORT_PMDR);
+#elif CONFIG_SH_MAGIC_PANEL_R2_VERSION == 3
+ ctrl_outb(0xF0, PORT_PMDR);
+#else
+#error Unknown revision of PLATFORM_MP_R2
+#endif
+
+ /* P7 (x); P6 (x); P5 (x);
+ * P4 GPO(nu); P3 IRQ3(LAN_IRQ); P2 IRQ2(CAN3_IRQ);
+ * P1 IRQ1(CAN2_IRQ); P0 IRQ0(CAN1_IRQ)
+ */
+ ctrl_outw(0x0100, PORT_PPCR); /* 00 00 00 01 00 00 00 00 */
+ ctrl_outb(0x10, PORT_PPDR);
+
+ /* R7 A25; R6 A24; R5 A23; R4 A22;
+ * R3 A21; R2 A20; R1 A19; R0 A0;
+ */
+ ctrl_outw(0x0000, PORT_PRCR); /* 00 00 00 00 00 00 00 00 */
+
+ /* S7 (x); S6 (x); S5 (x); S4 GPO(EEPROM_CS2);
+ * S3 GPO(EEPROM_CS1); S2 SIOF0_TXD; S1 SIOF0_RXD; S0 SIOF0_SCK;
+ */
+ ctrl_outw(0x0140, PORT_PSCR); /* 00 00 00 01 01 00 00 00 */
+
+ /* T7 (x); T6 (x); T5 (x); T4 COM1_CTS;
+ * T3 COM1_RTS; T2 COM1_TXD; T1 COM1_RXD; T0 GPO(WDOG)
+ */
+ ctrl_outw(0x0001, PORT_PTCR); /* 00 00 00 00 00 00 00 01 */
+
+ /* U7 (x); U6 (x); U5 (x); U4 GPI+(/AC_FAULT);
+ * U3 GPO(TOUCH_CS); U2 TOUCH_TXD; U1 TOUCH_RXD; U0 TOUCH_SCK;
+ */
+ ctrl_outw(0x0240, PORT_PUCR); /* 00 00 00 10 01 00 00 00 */
+
+ /* V7 (x); V6 (x); V5 (x); V4 GPO(MID2);
+ * V3 GPO(MID1); V2 CARD_TxD; V1 CARD_RxD; V0 GPI+(/BAT_FAULT);
+ */
+ ctrl_outw(0x0142, PORT_PVCR); /* 00 00 00 01 01 00 00 10 */
+}
+
+static void __init mpr2_setup(char **cmdline_p)
+{
+ __set_io_port_base(0xa0000000);
+
+ /* set Pin Select Register A:
+ * /PCC_CD1, /PCC_CD2, PCC_BVD1, PCC_BVD2,
+ * /IOIS16, IRQ4, IRQ5, USB1d_SUSPEND
+ */
+ ctrl_outw(0xAABC, PORT_PSELA);
+ /* set Pin Select Register B:
+ * /SCIF0_RTS, /SCIF0_CTS, LCD_VCPWC,
+ * LCD_VEPWC, IIC_SDA, IIC_SCL, Reserved
+ */
+ ctrl_outw(0x3C00, PORT_PSELB);
+ /* set Pin Select Register C:
+ * SIOF1_SCK, SIOF1_RxD, SCIF1_RxD, SCIF1_TxD, Reserved
+ */
+ ctrl_outw(0x0000, PORT_PSELC);
+ /* set Pin Select Register D: Reserved, SIOF1_TxD, Reserved, SIOF1_MCLK,
+ * Reserved, SIOF1_SYNC, Reserved, SCIF1_SCK, Reserved
+ */
+ ctrl_outw(0x0000, PORT_PSELD);
+ /* set USB TxRx Control: Reserved, DRV, Reserved, USB_TRANS, USB_SEL */
+ ctrl_outw(0x0101, PORT_UTRCTL);
+ /* set USB Clock Control: USSCS, USSTB, Reserved (HighByte always A5) */
+ ctrl_outw(0xA5C0, PORT_UCLKCR_W);
+
+ setup_chip_select();
+
+ setup_port_multiplexing();
+
+ reset_ethernet();
+
+ printk(KERN_INFO "Magic Panel Release 2 A.%i\n",
+ CONFIG_SH_MAGIC_PANEL_R2_VERSION);
+
+ if (ethernet_reset_finished() == 0)
+ printk(KERN_WARNING "Ethernet not ready\n");
+}
+
+static struct resource smc911x_resources[] = {
+ [0] = {
+ .start = 0xa8000000,
+ .end = 0xabffffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 35,
+ .end = 35,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc911x_device = {
+ .name = "smc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc911x_resources),
+ .resource = smc911x_resources,
+};
+
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = PA_LED,
+ .end = PA_LED,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct heartbeat_data heartbeat_data = {
+ .flags = HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = &heartbeat_data,
+ },
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+static struct mtd_partition *parsed_partitions;
+
+static struct mtd_partition mpr2_partitions[] = {
+ /* Reserved for bootloader, read-only */
+ {
+ .name = "Bootloader",
+ .offset = 0x00000000UL,
+ .size = MPR2_MTD_BOOTLOADER_SIZE,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ /* Reserved for kernel image */
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MPR2_MTD_KERNEL_SIZE,
+ },
+ /* Rest is used for Flash FS */
+ {
+ .name = "Flash_FS",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct physmap_flash_data flash_data = {
+ .width = 2,
+};
+
+static struct resource flash_resource = {
+ .start = 0x00000000,
+ .end = 0x2000000UL,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+ .name = "physmap-flash",
+ .id = -1,
+ .resource = &flash_resource,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &flash_data,
+ },
+};
+
+static struct mtd_info *flash_mtd;
+
+static struct map_info mpr2_flash_map = {
+ .name = "Magic Panel R2 Flash",
+ .size = 0x2000000UL,
+ .bankwidth = 2,
+};
+
+static void __init set_mtd_partitions(void)
+{
+ int nr_parts = 0;
+
+ simple_map_init(&mpr2_flash_map);
+ flash_mtd = do_map_probe("cfi_probe", &mpr2_flash_map);
+ nr_parts = parse_mtd_partitions(flash_mtd, probes,
+ &parsed_partitions, 0);
+ /* If there is no partition table, used the hard coded table */
+ if (nr_parts <= 0) {
+ flash_data.parts = mpr2_partitions;
+ flash_data.nr_parts = ARRAY_SIZE(mpr2_partitions);
+ } else {
+ flash_data.nr_parts = nr_parts;
+ flash_data.parts = parsed_partitions;
+ }
+}
+
+/*
+ * Add all resources to the platform_device
+ */
+
+static struct platform_device *mpr2_devices[] __initdata = {
+ &heartbeat_device,
+ &smc911x_device,
+ &flash_device,
+};
+
+
+static int __init mpr2_devices_setup(void)
+{
+ set_mtd_partitions();
+ return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices));
+}
+device_initcall(mpr2_devices_setup);
+
+/*
+ * Initialize IRQ setting
+ */
+static void __init init_mpr2_IRQ(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */
+
+ set_irq_type(32, IRQ_TYPE_LEVEL_LOW); /* IRQ0 CAN1 */
+ set_irq_type(33, IRQ_TYPE_LEVEL_LOW); /* IRQ1 CAN2 */
+ set_irq_type(34, IRQ_TYPE_LEVEL_LOW); /* IRQ2 CAN3 */
+ set_irq_type(35, IRQ_TYPE_LEVEL_LOW); /* IRQ3 SMSC9115 */
+ set_irq_type(36, IRQ_TYPE_EDGE_RISING); /* IRQ4 touchscreen */
+ set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
+
+ intc_set_priority(32, 13); /* IRQ0 CAN1 */
+ intc_set_priority(33, 13); /* IRQ0 CAN2 */
+ intc_set_priority(34, 13); /* IRQ0 CAN3 */
+ intc_set_priority(35, 6); /* IRQ3 SMSC9115 */
+}
+
+/*
+ * The Machine Vector
+ */
+
+static struct sh_machine_vector mv_mpr2 __initmv = {
+ .mv_name = "mpr2",
+ .mv_setup = mpr2_setup,
+ .mv_init_irq = init_mpr2_IRQ,
+};
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c
index 8ce03e00b0a..fede36361dc 100644
--- a/arch/sh/boards/mpc1211/setup.c
+++ b/arch/sh/boards/mpc1211/setup.c
@@ -285,7 +285,7 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no)
static struct resource heartbeat_resources[] = {
[0] = {
.start = 0xa2000000,
- .end = 0xa2000000 + 8 - 1,
+ .end = 0xa2000000,
.flags = IORESOURCE_MEM,
},
};
diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
index b1d20afb4eb..dd26182fbf5 100644
--- a/arch/sh/boards/renesas/r7780rp/Makefile
+++ b/arch/sh/boards/renesas/r7780rp/Makefile
@@ -1,9 +1,10 @@
#
# Makefile for the R7780RP-1 specific parts of the kernel
#
-irqinit-y := irq-r7780rp.o
+irqinit-$(CONFIG_SH_R7780MP) := irq-r7780mp.o
irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o
-obj-y := setup.o irq.o $(irqinit-y)
+irqinit-$(CONFIG_SH_R7780RP) := irq-r7780rp.o irq.o
+obj-y := setup.o $(irqinit-y)
ifneq ($(CONFIG_SH_R7785RP),y)
obj-$(CONFIG_PUSH_SWITCH) += psw.o
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
new file mode 100644
index 00000000000..59b47fe061f
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
@@ -0,0 +1,61 @@
+/*
+ * Renesas Solutions Highlander R7780MP Support.
+ *
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/r7780rp.h>
+
+enum {
+ UNUSED = 0,
+
+ /* board specific interrupt sources */
+ AX88796, /* Ethernet controller */
+ CF, /* Compact Flash */
+ PSW, /* Push Switch */
+ EXT1, /* EXT1n IRQ */
+ EXT4, /* EXT4n IRQ */
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(CF, IRQ_CF),
+ INTC_IRQ(PSW, IRQ_PSW),
+ INTC_IRQ(AX88796, IRQ_AX88796),
+ INTC_IRQ(EXT1, IRQ_EXT1),
+ INTC_IRQ(EXT4, IRQ_EXT4),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xa4000000, 0, 16, /* IRLMSK */
+ { 0, 0, 0, 0, CF, 0, 0, 0,
+ 0, 0, 0, EXT4, 0, EXT1, PSW, AX88796 } },
+};
+
+static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+ 0, IRQ_CF, 0, 0,
+ 0, 0, 0, 0,
+ 0, IRQ_EXT4, 0, IRQ_EXT1,
+ 0, IRQ_AX88796, IRQ_PSW,
+};
+
+static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors,
+ NULL, NULL, mask_registers, NULL, NULL);
+
+unsigned char * __init highlander_init_irq_r7780mp(void)
+{
+ if ((ctrl_inw(0xa4000700) & 0xf000) == 0x2000) {
+ printk(KERN_INFO "Using r7780mp interrupt controller.\n");
+ register_intc_controller(&intc_desc);
+ return irl2irq;
+ }
+
+ return NULL;
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
index f5f358746c9..fa4a534cade 100644
--- a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
@@ -9,13 +9,15 @@
* for more details.
*/
#include <linux/init.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/r7780rp.h>
-void __init highlander_init_irq(void)
+unsigned char * __init highlander_init_irq_r7780rp(void)
{
int i;
for (i = 0; i < 15; i++)
make_r7780rp_irq(i);
+
+ return NULL;
}
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
index dd6ec4ce44d..b2c6a84673b 100644
--- a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
@@ -1,19 +1,55 @@
/*
- * Renesas Solutions Highlander R7780RP-1 Support.
+ * Renesas Solutions Highlander R7785RP Support.
*
* Copyright (C) 2002 Atom Create Engineering Co., Ltd.
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/io.h>
#include <asm/r7780rp.h>
-void __init highlander_init_irq(void)
+enum {
+ UNUSED = 0,
+
+ /* board specific interrupt sources */
+ AX88796, /* Ethernet controller */
+ CF, /* Compact Flash */
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(CF, IRQ_CF),
+ INTC_IRQ(AX88796, IRQ_AX88796),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xa4000010, 0, 16, /* IRLMCR1 */
+ { 0, 0, 0, 0, CF, AX88796, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 } },
+};
+
+static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+ 0, IRQ_CF, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, IRQ_AX88796, 0,
+ 0, 0, 0,
+};
+
+static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors,
+ NULL, NULL, mask_registers, NULL, NULL);
+
+unsigned char * __init highlander_init_irq_r7785rp(void)
{
+ if ((ctrl_inw(0xa4000158) & 0xf000) != 0x1000)
+ return NULL;
+
+ printk(KERN_INFO "Using r7785rp interrupt controller.\n");
+
ctrl_outw(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */
/* Setup the FPGA IRL */
@@ -24,6 +60,6 @@ void __init highlander_init_irq(void)
ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */
ctrl_outw(0x0000, PA_IRLPRF); /* FPGA IRLF */
- make_r7780rp_irq(1); /* CF card */
- make_r7780rp_irq(10); /* On-board ethernet */
+ register_intc_controller(&intc_desc);
+ return irl2irq;
}
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index adb529d01ba..afe9de73666 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -19,6 +19,7 @@
#include <asm/machvec.h>
#include <asm/r7780rp.h>
#include <asm/clock.h>
+#include <asm/heartbeat.h>
#include <asm/io.h>
static struct resource r8a66597_usb_host_resources[] = {
@@ -30,8 +31,8 @@ static struct resource r8a66597_usb_host_resources[] = {
},
[1] = {
.name = "r8a66597_hcd",
- .start = 11, /* irq number */
- .end = 11,
+ .start = IRQ_EXT1, /* irq number */
+ .end = IRQ_EXT1,
.flags = IORESOURCE_IRQ,
},
};
@@ -56,8 +57,8 @@ static struct resource m66592_usb_peripheral_resources[] = {
},
[1] = {
.name = "m66592_udc",
- .start = 9, /* irq number */
- .end = 9,
+ .start = IRQ_EXT4, /* irq number */
+ .end = IRQ_EXT4,
.flags = IORESOURCE_IRQ,
},
};
@@ -85,11 +86,7 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
-#ifdef CONFIG_SH_R7780RP
- .start = 4,
-#else
- .start = 1,
-#endif
+ .start = IRQ_CF,
.flags = IORESOURCE_IRQ,
},
};
@@ -108,16 +105,23 @@ static struct platform_device cf_ide_device = {
},
};
-static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 };
-
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_OBLED,
- .end = PA_OBLED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_OBLED,
.flags = IORESOURCE_MEM,
},
};
+#ifndef CONFIG_SH_R7785RP
+static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 };
+
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+};
+#endif
+
static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
@@ -125,7 +129,7 @@ static struct platform_device heartbeat_device = {
/* R7785RP has a slightly more sensible FPGA.. */
#ifndef CONFIG_SH_R7785RP
.dev = {
- .platform_data = heartbeat_bit_pos,
+ .platform_data = &heartbeat_data,
},
#endif
.num_resources = ARRAY_SIZE(heartbeat_resources),
@@ -217,12 +221,50 @@ static void __init highlander_setup(char **cmdline_p)
pm_power_off = r7780rp_power_off;
}
+static unsigned char irl2irq[HL_NR_IRL];
+
+int highlander_irq_demux(int irq)
+{
+ if (irq >= HL_NR_IRL || !irl2irq[irq])
+ return irq;
+
+ return irl2irq[irq];
+}
+
+void __init highlander_init_irq(void)
+{
+ unsigned char *ucp = NULL;
+
+ do {
+#ifdef CONFIG_SH_R7780MP
+ ucp = highlander_init_irq_r7780mp();
+ if (ucp)
+ break;
+#endif
+#ifdef CONFIG_SH_R7785RP
+ ucp = highlander_init_irq_r7785rp();
+ if (ucp)
+ break;
+#endif
+#ifdef CONFIG_SH_R7780RP
+ highlander_init_irq_r7780rp();
+ ucp = irl2irq;
+ break;
+#endif
+ } while (0);
+
+ if (ucp) {
+ plat_irq_setup_pins(IRQ_MODE_IRL3210);
+ memcpy(irl2irq, ucp, HL_NR_IRL);
+ }
+}
+
/*
* The Machine Vector
*/
static struct sh_machine_vector mv_highlander __initmv = {
.mv_name = "Highlander",
- .mv_nr_irqs = 109,
.mv_setup = highlander_setup,
.mv_init_irq = highlander_init_irq,
+ .mv_irq_demux = highlander_irq_demux,
};
diff --git a/arch/sh/boards/renesas/rts7751r2d/Kconfig b/arch/sh/boards/renesas/rts7751r2d/Kconfig
index 7780d1fb13f..8122a9667fc 100644
--- a/arch/sh/boards/renesas/rts7751r2d/Kconfig
+++ b/arch/sh/boards/renesas/rts7751r2d/Kconfig
@@ -1,11 +1,22 @@
if SH_RTS7751R2D
-menu "RTS7751R2D options"
+menu "RTS7751R2D Board Revision"
-config RTS7751R2D_REV11
- bool "RTS7751R2D Rev. 1.1 board support"
+config RTS7751R2D_PLUS
+ bool "R2D-PLUS"
help
- Selecting this option will support version rev. 1.1.
+ Selecting this option will configure the kernel for R2D-PLUS.
+
+ R2D-PLUS is the smaller of the two R2D board versions, equipped
+ with a single PCI slot.
+
+config RTS7751R2D_1
+ bool "R2D-1"
+ help
+ Selecting this option will configure the kernel for R2D-1.
+
+ R2D-1 is the larger of the two R2D board versions, equipped
+ with two PCI slots.
endmenu
endif
diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
index 0bae9041ace..7cc2813adfe 100644
--- a/arch/sh/boards/renesas/rts7751r2d/irq.c
+++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
@@ -1,84 +1,159 @@
/*
* linux/arch/sh/boards/renesas/rts7751r2d/irq.c
*
+ * Copyright (C) 2007 Magnus Damm
* Copyright (C) 2000 Kazumoto Kojima
*
- * Renesas Technology Sales RTS7751R2D Support.
+ * Renesas Technology Sales RTS7751R2D Support, R2D-PLUS and R2D-1.
*
* Modified for RTS7751R2D by
* Atom Create Engineering Co., Ltd. 2002.
*/
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <asm/voyagergx.h>
#include <asm/rts7751r2d.h>
-#if defined(CONFIG_RTS7751R2D_REV11)
-static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
-#else
-static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
-#endif
+#define R2D_NR_IRL 13
-extern int voyagergx_irq_demux(int irq);
-extern void setup_voyagergx_irq(void);
+enum {
+ UNUSED = 0,
-static void enable_rts7751r2d_irq(unsigned int irq)
-{
- /* Set priority in IPR back to original value */
- ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
-}
+ /* board specific interrupt sources (R2D-1 and R2D-PLUS) */
+ EXT, /* EXT_INT0-3 */
+ RTC_T, RTC_A, /* Real Time Clock */
+ AX88796, /* Ethernet controller (R2D-1 board) */
+ KEY, /* Key input (R2D-PLUS board) */
+ SDCARD, /* SD Card */
+ CF_CD, CF_IDE, /* CF Card Detect + CF IDE */
+ SM501, /* SM501 aka Voyager */
+ PCI_INTD_RTL8139, /* Ethernet controller */
+ PCI_INTC_PCI1520, /* Cardbus/PCMCIA bridge */
+ PCI_INTB_RTL8139, /* Ethernet controller with HUB (R2D-PLUS board) */
+ PCI_INTB_SLOT, /* PCI Slot 3.3v (R2D-1 board) */
+ PCI_INTA_SLOT, /* PCI Slot 3.3v */
+ TP, /* Touch Panel */
+};
-static void disable_rts7751r2d_irq(unsigned int irq)
-{
- /* Set the priority in IPR to 0 */
- ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
- IRLCNTR1);
-}
+#ifdef CONFIG_RTS7751R2D_1
+
+/* Vectors for R2D-1 */
+static struct intc_vect vectors_r2d_1[] __initdata = {
+ INTC_IRQ(EXT, IRQ_EXT),
+ INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
+ INTC_IRQ(AX88796, IRQ_AX88796), INTC_IRQ(SDCARD, IRQ_SDCARD),
+ INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE), /* ng */
+ INTC_IRQ(SM501, IRQ_VOYAGER),
+ INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
+ INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
+ INTC_IRQ(PCI_INTB_SLOT, IRQ_PCI_INTB),
+ INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
+ INTC_IRQ(TP, IRQ_TP),
+};
+
+/* IRLMSK mask register layout for R2D-1 */
+static struct intc_mask_reg mask_registers_r2d_1[] __initdata = {
+ { 0xa4000000, 0, 16, /* IRLMSK */
+ { TP, PCI_INTA_SLOT, PCI_INTB_SLOT,
+ PCI_INTC_PCI1520, PCI_INTD_RTL8139,
+ SM501, CF_IDE, CF_CD, SDCARD, AX88796,
+ RTC_A, RTC_T, 0, 0, 0, EXT } },
+};
+
+/* IRLn to IRQ table for R2D-1 */
+static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = {
+ IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
+ IRQ_VOYAGER, IRQ_AX88796, IRQ_RTC_A, IRQ_RTC_T,
+ IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
+ IRQ_TP,
+};
+
+static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1,
+ NULL, NULL, mask_registers_r2d_1, NULL, NULL);
+
+#endif /* CONFIG_RTS7751R2D_1 */
+
+#ifdef CONFIG_RTS7751R2D_PLUS
+
+/* Vectors for R2D-PLUS */
+static struct intc_vect vectors_r2d_plus[] __initdata = {
+ INTC_IRQ(EXT, IRQ_EXT),
+ INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
+ INTC_IRQ(KEY, IRQ_KEY), INTC_IRQ(SDCARD, IRQ_SDCARD),
+ INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE),
+ INTC_IRQ(SM501, IRQ_VOYAGER),
+ INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
+ INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
+ INTC_IRQ(PCI_INTB_RTL8139, IRQ_PCI_INTB),
+ INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
+ INTC_IRQ(TP, IRQ_TP),
+};
+
+/* IRLMSK mask register layout for R2D-PLUS */
+static struct intc_mask_reg mask_registers_r2d_plus[] __initdata = {
+ { 0xa4000000, 0, 16, /* IRLMSK */
+ { TP, PCI_INTA_SLOT, PCI_INTB_RTL8139,
+ PCI_INTC_PCI1520, PCI_INTD_RTL8139,
+ SM501, CF_IDE, CF_CD, SDCARD, KEY,
+ RTC_A, RTC_T, 0, 0, 0, EXT } },
+};
+
+/* IRLn to IRQ table for R2D-PLUS */
+static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = {
+ IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
+ IRQ_VOYAGER, IRQ_KEY, IRQ_RTC_A, IRQ_RTC_T,
+ IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
+ IRQ_TP,
+};
+
+static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus,
+ NULL, NULL, mask_registers_r2d_plus, NULL, NULL);
+
+#endif /* CONFIG_RTS7751R2D_PLUS */
+
+static unsigned char irl2irq[R2D_NR_IRL];
int rts7751r2d_irq_demux(int irq)
{
- return voyagergx_irq_demux(irq);
-}
+ if (irq >= R2D_NR_IRL || !irl2irq[irq])
+ return irq;
-static struct irq_chip rts7751r2d_irq_chip __read_mostly = {
- .name = "rts7751r2d",
- .mask = disable_rts7751r2d_irq,
- .unmask = enable_rts7751r2d_irq,
- .mask_ack = disable_rts7751r2d_irq,
-};
+ return irl2irq[irq];
+}
/*
* Initialize IRQ setting
*/
void __init init_rts7751r2d_IRQ(void)
{
- int i;
-
- /* IRL0=KEY Input
- * IRL1=Ethernet
- * IRL2=CF Card
- * IRL3=CF Card Insert
- * IRL4=PCMCIA
- * IRL5=VOYAGER
- * IRL6=RTC Alarm
- * IRL7=RTC Timer
- * IRL8=SD Card
- * IRL9=PCI Slot #1
- * IRL10=PCI Slot #2
- * IRL11=Extention #0
- * IRL12=Extention #1
- * IRL13=Extention #2
- * IRL14=Extention #3
- */
-
- for (i=0; i<15; i++) {
- disable_irq_nosync(i);
- set_irq_chip_and_handler_name(i, &rts7751r2d_irq_chip,
- handle_level_irq, "level");
- enable_rts7751r2d_irq(i);
+ struct intc_desc *d;
+
+ switch (ctrl_inw(PA_VERREG) & 0xf0) {
+#ifdef CONFIG_RTS7751R2D_PLUS
+ case 0x10:
+ printk(KERN_INFO "Using R2D-PLUS interrupt controller.\n");
+ d = &intc_desc_r2d_plus;
+ memcpy(irl2irq, irl2irq_r2d_plus, R2D_NR_IRL);
+ break;
+#endif
+#ifdef CONFIG_RTS7751R2D_1
+ case 0x00: /* according to manual */
+ case 0x30: /* in reality */
+ printk(KERN_INFO "Using R2D-1 interrupt controller.\n");
+ d = &intc_desc_r2d_1;
+ memcpy(irl2irq, irl2irq_r2d_1, R2D_NR_IRL);
+ break;
+#endif
+ default:
+ printk(KERN_INFO "Unknown R2D interrupt controller 0x%04x\n",
+ ctrl_inw(PA_VERREG));
+ return;
}
+ register_intc_controller(d);
+#ifdef CONFIG_MFD_SM501
setup_voyagergx_irq();
+#endif
}
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 6f7029d3324..37f2c0b447f 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -45,20 +45,16 @@ static void __init voyagergx_serial_init(void)
static struct resource cf_ide_resources[] = {
[0] = {
.start = PA_AREA5_IO + 0x1000,
- .end = PA_AREA5_IO + 0x1000 + 0x08 - 1,
+ .end = PA_AREA5_IO + 0x1000 + 0x10 - 0x2,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PA_AREA5_IO + 0x80c,
- .end = PA_AREA5_IO + 0x80c + 0x16 - 1,
+ .end = PA_AREA5_IO + 0x80c,
.flags = IORESOURCE_MEM,
},
[2] = {
-#ifdef CONFIG_RTS7751R2D_REV11
- .start = 1,
-#else
- .start = 2,
-#endif
+ .start = IRQ_CF_IDE,
.flags = IORESOURCE_IRQ,
},
};
@@ -77,12 +73,28 @@ static struct platform_device cf_ide_device = {
},
};
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = PA_OUTPORT,
+ .end = PA_OUTPORT,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+#ifdef CONFIG_MFD_SM501
static struct plat_serial8250_port uart_platform_data[] = {
{
.membase = (void __iomem *)VOYAGER_UART_BASE,
.mapbase = VOYAGER_UART_BASE,
.iotype = UPIO_MEM,
- .irq = VOYAGER_UART0_IRQ,
+ .irq = IRQ_SM501_U0,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
.regshift = 2,
.uartclk = (9600 * 16),
@@ -98,21 +110,6 @@ static struct platform_device uart_device = {
},
};
-static struct resource heartbeat_resources[] = {
- [0] = {
- .start = PA_OUTPORT,
- .end = PA_OUTPORT + 8 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device heartbeat_device = {
- .name = "heartbeat",
- .id = -1,
- .num_resources = ARRAY_SIZE(heartbeat_resources),
- .resource = heartbeat_resources,
-};
-
static struct resource sm501_resources[] = {
[0] = {
.start = 0x10000000,
@@ -125,7 +122,7 @@ static struct resource sm501_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
- .start = 32,
+ .start = IRQ_SM501_CV,
.flags = IORESOURCE_IRQ,
},
};
@@ -137,22 +134,19 @@ static struct platform_device sm501_device = {
.resource = sm501_resources,
};
+#endif /* CONFIG_MFD_SM501 */
+
static struct platform_device *rts7751r2d_devices[] __initdata = {
+#ifdef CONFIG_MFD_SM501
&uart_device,
- &heartbeat_device,
&sm501_device,
+#endif
+ &cf_ide_device,
+ &heartbeat_device,
};
static int __init rts7751r2d_devices_setup(void)
{
- int ret;
-
- if (ctrl_inw(PA_BVERREG) == 0x10) { /* only working on R2D-PLUS */
- ret = platform_device_register(&cf_ide_device);
- if (ret)
- return ret;
- }
-
return platform_add_devices(rts7751r2d_devices,
ARRAY_SIZE(rts7751r2d_devices));
}
@@ -163,6 +157,34 @@ static void rts7751r2d_power_off(void)
ctrl_outw(0x0001, PA_POWOFF);
}
+static inline unsigned char is_ide_ioaddr(unsigned long addr)
+{
+ return ((cf_ide_resources[0].start <= addr &&
+ addr <= cf_ide_resources[0].end) ||
+ (cf_ide_resources[1].start <= addr &&
+ addr <= cf_ide_resources[1].end));
+}
+
+void rts7751r2d_writeb(u8 b, void __iomem *addr)
+{
+ unsigned long tmp = (unsigned long __force)addr;
+
+ if (is_ide_ioaddr(tmp))
+ ctrl_outw((u16)b, tmp);
+ else
+ ctrl_outb(b, tmp);
+}
+
+u8 rts7751r2d_readb(void __iomem *addr)
+{
+ unsigned long tmp = (unsigned long __force)addr;
+
+ if (is_ide_ioaddr(tmp))
+ return ctrl_inw(tmp) & 0xff;
+ else
+ return ctrl_inb(tmp);
+}
+
/*
* Initialize the board
*/
@@ -187,12 +209,11 @@ static void __init rts7751r2d_setup(char **cmdline_p)
static struct sh_machine_vector mv_rts7751r2d __initmv = {
.mv_name = "RTS7751R2D",
.mv_setup = rts7751r2d_setup,
- .mv_nr_irqs = 72,
-
.mv_init_irq = init_rts7751r2d_IRQ,
.mv_irq_demux = rts7751r2d_irq_demux,
-
-#ifdef CONFIG_USB_SM501
+ .mv_writeb = rts7751r2d_writeb,
+ .mv_readb = rts7751r2d_readb,
+#if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD)
.mv_consistent_alloc = voyagergx_consistent_alloc,
.mv_consistent_free = voyagergx_consistent_free,
#endif
diff --git a/arch/sh/boards/renesas/x3proto/Makefile b/arch/sh/boards/renesas/x3proto/Makefile
new file mode 100644
index 00000000000..983e4551fec
--- /dev/null
+++ b/arch/sh/boards/renesas/x3proto/Makefile
@@ -0,0 +1 @@
+obj-y += setup.o ilsel.o
diff --git a/arch/sh/boards/renesas/x3proto/ilsel.c b/arch/sh/boards/renesas/x3proto/ilsel.c
new file mode 100644
index 00000000000..6d4454fef97
--- /dev/null
+++ b/arch/sh/boards/renesas/x3proto/ilsel.c
@@ -0,0 +1,151 @@
+/*
+ * arch/sh/boards/renesas/x3proto/ilsel.c
+ *
+ * Helper routines for SH-X3 proto board ILSEL.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <linux/io.h>
+#include <asm/ilsel.h>
+
+/*
+ * ILSEL is split across:
+ *
+ * ILSEL0 - 0xb8100004 [ Levels 1 - 4 ]
+ * ILSEL1 - 0xb8100006 [ Levels 5 - 8 ]
+ * ILSEL2 - 0xb8100008 [ Levels 9 - 12 ]
+ * ILSEL3 - 0xb810000a [ Levels 13 - 15 ]
+ *
+ * With each level being relative to an ilsel_source_t.
+ */
+#define ILSEL_BASE 0xb8100004
+#define ILSEL_LEVELS 15
+
+/*
+ * ILSEL level map, in descending order from the highest level down.
+ *
+ * Supported levels are 1 - 15 spread across ILSEL0 - ILSEL4, mapping
+ * directly to IRLs. As the IRQs are numbered in reverse order relative
+ * to the interrupt level, the level map is carefully managed to ensure a
+ * 1:1 mapping between the bit position and the IRQ number.
+ *
+ * This careful constructions allows ilsel_enable*() to be referenced
+ * directly for hooking up an ILSEL set and getting back an IRQ which can
+ * subsequently be used for internal accounting in the (optional) disable
+ * path.
+ */
+static unsigned long ilsel_level_map;
+
+static inline unsigned int ilsel_offset(unsigned int bit)
+{
+ return ILSEL_LEVELS - bit - 1;
+}
+
+static inline unsigned long mk_ilsel_addr(unsigned int bit)
+{
+ return ILSEL_BASE + ((ilsel_offset(bit) >> 1) & ~0x1);
+}
+
+static inline unsigned int mk_ilsel_shift(unsigned int bit)
+{
+ return (ilsel_offset(bit) & 0x3) << 2;
+}
+
+static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
+{
+ unsigned int tmp, shift;
+ unsigned long addr;
+
+ addr = mk_ilsel_addr(bit);
+ shift = mk_ilsel_shift(bit);
+
+ pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n",
+ __FUNCTION__, bit, addr, shift, set);
+
+ tmp = ctrl_inw(addr);
+ tmp &= ~(0xf << shift);
+ tmp |= set << shift;
+ ctrl_outw(tmp, addr);
+}
+
+/**
+ * ilsel_enable - Enable an ILSEL set.
+ * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
+ *
+ * Enables a given non-aliased ILSEL source (<= ILSEL_KEY) at the highest
+ * available interrupt level. Callers should take care to order callsites
+ * noting descending interrupt levels. Aliasing FPGA and external board
+ * IRQs need to use ilsel_enable_fixed().
+ *
+ * The return value is an IRQ number that can later be taken down with
+ * ilsel_disable().
+ */
+int ilsel_enable(ilsel_source_t set)
+{
+ unsigned int bit;
+
+ /* Aliased sources must use ilsel_enable_fixed() */
+ BUG_ON(set > ILSEL_KEY);
+
+ do {
+ bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
+ } while (test_and_set_bit(bit, &ilsel_level_map));
+
+ __ilsel_enable(set, bit);
+
+ return bit;
+}
+EXPORT_SYMBOL_GPL(ilsel_enable);
+
+/**
+ * ilsel_enable_fixed - Enable an ILSEL set at a fixed interrupt level
+ * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
+ * @level: Interrupt level (1 - 15)
+ *
+ * Enables a given ILSEL source at a fixed interrupt level. Necessary
+ * both for level reservation as well as for aliased sources that only
+ * exist on special ILSEL#s.
+ *
+ * Returns an IRQ number (as ilsel_enable()).
+ */
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level)
+{
+ unsigned int bit = ilsel_offset(level - 1);
+
+ if (test_and_set_bit(bit, &ilsel_level_map))
+ return -EBUSY;
+
+ __ilsel_enable(set, bit);
+
+ return bit;
+}
+EXPORT_SYMBOL_GPL(ilsel_enable_fixed);
+
+/**
+ * ilsel_disable - Disable an ILSEL set
+ * @irq: Bit position for ILSEL set value (retval from enable routines)
+ *
+ * Disable a previously enabled ILSEL set.
+ */
+void ilsel_disable(unsigned int irq)
+{
+ unsigned long addr;
+ unsigned int tmp;
+
+ addr = mk_ilsel_addr(irq);
+
+ tmp = ctrl_inw(addr);
+ tmp &= ~(0xf << mk_ilsel_shift(irq));
+ ctrl_outw(tmp, addr);
+
+ clear_bit(irq, &ilsel_level_map);
+}
+EXPORT_SYMBOL_GPL(ilsel_disable);
diff --git a/arch/sh/boards/renesas/x3proto/setup.c b/arch/sh/boards/renesas/x3proto/setup.c
new file mode 100644
index 00000000000..abc5b6d418f
--- /dev/null
+++ b/arch/sh/boards/renesas/x3proto/setup.c
@@ -0,0 +1,136 @@
+/*
+ * arch/sh/boards/renesas/x3proto/setup.c
+ *
+ * Renesas SH-X3 Prototype Board Support.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/ilsel.h>
+
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = 0xb8140020,
+ .end = 0xb8140020,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x18000300,
+ .end = 0x18000300 + 0x10 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* Filled in by ilsel */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .resource = smc91x_resources,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+ [0] = {
+ .name = "r8a66597_hcd",
+ .start = 0x18040000,
+ .end = 0x18080000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "r8a66597_hcd",
+ /* Filled in by ilsel */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+ .name = "r8a66597_hcd",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
+ .resource = r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+ [0] = {
+ .name = "m66592_udc",
+ .start = 0x18080000,
+ .end = 0x180c0000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "m66592_udc",
+ /* Filled in by ilsel */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+ .name = "m66592_udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(m66592_usb_peripheral_resources),
+ .resource = m66592_usb_peripheral_resources,
+};
+
+static struct platform_device *x3proto_devices[] __initdata = {
+ &heartbeat_device,
+ &smc91x_device,
+ &r8a66597_usb_host_device,
+ &m66592_usb_peripheral_device,
+};
+
+static int __init x3proto_devices_setup(void)
+{
+ r8a66597_usb_host_resources[1].start =
+ r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
+
+ m66592_usb_peripheral_resources[1].start =
+ m66592_usb_peripheral_resources[1].end = ilsel_enable(ILSEL_USBP_I);
+
+ smc91x_resources[1].start =
+ smc91x_resources[1].end = ilsel_enable(ILSEL_LAN);
+
+ return platform_add_devices(x3proto_devices,
+ ARRAY_SIZE(x3proto_devices));
+}
+device_initcall(x3proto_devices_setup);
+
+static void __init x3proto_init_irq(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+ /* Set ICR0.LVLMODE */
+ ctrl_outl(ctrl_inl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
+static struct sh_machine_vector mv_x3proto __initmv = {
+ .mv_name = "x3proto",
+ .mv_init_irq = x3proto_init_irq,
+};
diff --git a/arch/sh/boards/se/7206/io.c b/arch/sh/boards/se/7206/io.c
index b557273e0cb..1308e618e04 100644
--- a/arch/sh/boards/se/7206/io.c
+++ b/arch/sh/boards/se/7206/io.c
@@ -26,22 +26,24 @@ static inline void delay(void)
static inline volatile __u16 *
port2adr(unsigned int port)
{
- if (port >= 0x2000)
+ if (port >= 0x2000 && port < 0x2020)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
- else if (port >= 0x300 || port < 0x310)
+ else if (port >= 0x300 && port < 0x310)
return (volatile __u16 *) (PA_SMSC + (port - 0x300));
+
+ return (volatile __u16 *)port;
}
unsigned char se7206_inb(unsigned long port)
{
- return (*port2adr(port))&0xff;
+ return (*port2adr(port)) & 0xff;
}
unsigned char se7206_inb_p(unsigned long port)
{
unsigned long v;
- v = (*port2adr(port))&0xff;
+ v = (*port2adr(port)) & 0xff;
delay();
return v;
}
@@ -51,12 +53,6 @@ unsigned short se7206_inw(unsigned long port)
return *port2adr(port);;
}
-unsigned int se7206_inl(unsigned long port)
-{
- maybebadio(port);
- return 0;
-}
-
void se7206_outb(unsigned char value, unsigned long port)
{
*(port2adr(port)) = value;
@@ -73,11 +69,6 @@ void se7206_outw(unsigned short value, unsigned long port)
*port2adr(port) = value;
}
-void se7206_outl(unsigned int value, unsigned long port)
-{
- maybebadio(port);
-}
-
void se7206_insb(unsigned long port, void *addr, unsigned long count)
{
volatile __u16 *p = port2adr(port);
@@ -95,11 +86,6 @@ void se7206_insw(unsigned long port, void *addr, unsigned long count)
*ap++ = *p;
}
-void se7206_insl(unsigned long port, void *addr, unsigned long count)
-{
- maybebadio(port);
-}
-
void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
{
volatile __u16 *p = port2adr(port);
@@ -116,8 +102,3 @@ void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
while (count--)
*p = *ap++;
}
-
-void se7206_outsl(unsigned long port, const void *addr, unsigned long count)
-{
- maybebadio(port);
-}
diff --git a/arch/sh/boards/se/7206/setup.c b/arch/sh/boards/se/7206/setup.c
index a074b62505e..5b3ee089d91 100644
--- a/arch/sh/boards/se/7206/setup.c
+++ b/arch/sh/boards/se/7206/setup.c
@@ -6,14 +6,13 @@
* Copyright (C) 2007 Paul Mundt
*
* Hitachi 7206 SolutionEngine Support.
- *
*/
-
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/se7206.h>
#include <asm/io.h>
#include <asm/machvec.h>
+#include <asm/heartbeat.h>
static struct resource smc91x_resources[] = {
[0] = {
@@ -37,10 +36,16 @@ static struct platform_device smc91x_device = {
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+ .regsize = 32,
+};
+
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
@@ -49,7 +54,7 @@ static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
.dev = {
- .platform_data = heartbeat_bit_pos,
+ .platform_data = &heartbeat_data,
},
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
@@ -75,24 +80,18 @@ static struct sh_machine_vector mv_se __initmv = {
.mv_nr_irqs = 256,
.mv_inb = se7206_inb,
.mv_inw = se7206_inw,
- .mv_inl = se7206_inl,
.mv_outb = se7206_outb,
.mv_outw = se7206_outw,
- .mv_outl = se7206_outl,
.mv_inb_p = se7206_inb_p,
.mv_inw_p = se7206_inw,
- .mv_inl_p = se7206_inl,
.mv_outb_p = se7206_outb_p,
.mv_outw_p = se7206_outw,
- .mv_outl_p = se7206_outl,
.mv_insb = se7206_insb,
.mv_insw = se7206_insw,
- .mv_insl = se7206_insl,
.mv_outsb = se7206_outsb,
.mv_outsw = se7206_outsw,
- .mv_outsl = se7206_outsl,
.mv_init_irq = init_se7206_IRQ,
};
diff --git a/arch/sh/boards/se/7343/irq.c b/arch/sh/boards/se/7343/irq.c
index 360153ecc55..763f6deba81 100644
--- a/arch/sh/boards/se/7343/irq.c
+++ b/arch/sh/boards/se/7343/irq.c
@@ -99,8 +99,11 @@ shmse_irq_demux(int irq)
*
* We configure IRQ5 as a cascade IRQ.
*/
-static struct irqaction irq5 = { no_action, 0, CPU_MASK_NONE, "IRQ5-cascade",
- NULL, NULL};
+static struct irqaction irq5 = {
+ .handler = no_action,
+ .mask = CPU_MASK_NONE,
+ .name = "IRQ5-cascade",
+};
static struct ipr_data se7343_irq5_ipr_map[] = {
{ IRQ5_IRQ, IRQ5_IPR_ADDR+2, IRQ5_IPR_POS, IRQ5_PRIORITY },
diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c
index 8fec155e2ff..c9431b3a051 100644
--- a/arch/sh/boards/se/7343/setup.c
+++ b/arch/sh/boards/se/7343/setup.c
@@ -33,7 +33,7 @@ static struct platform_device smc91x_device = {
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + 8 - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
index 2962da148f3..d07a3368f54 100644
--- a/arch/sh/boards/se/770x/setup.c
+++ b/arch/sh/boards/se/770x/setup.c
@@ -12,6 +12,7 @@
#include <asm/se.h>
#include <asm/io.h>
#include <asm/smc37c93x.h>
+#include <asm/heartbeat.h>
void init_se_IRQ(void);
@@ -90,10 +91,15 @@ static struct platform_device cf_ide_device = {
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+};
+
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
@@ -102,7 +108,7 @@ static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
.dev = {
- .platform_data = heartbeat_bit_pos,
+ .platform_data = &heartbeat_data,
},
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
index 495fc7e2b60..03b63457e17 100644
--- a/arch/sh/boards/se/7722/setup.c
+++ b/arch/sh/boards/se/7722/setup.c
@@ -18,12 +18,10 @@
#include <asm/io.h>
/* Heartbeat */
-static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
@@ -31,9 +29,6 @@ static struct resource heartbeat_resources[] = {
static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
- .dev = {
- .platform_data = heartbeat_bit_pos,
- },
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
};
@@ -109,7 +104,7 @@ static void __init se7722_setup(char **cmdline_p)
ctrl_outl(0x00051001, MSTPCR0);
ctrl_outl(0x00000000, MSTPCR1);
/* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */
- ctrl_outl(0xffffbfC0, MSTPCR2);
+ ctrl_outl(0xffffbfC0, MSTPCR2);
ctrl_outw(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */
ctrl_outw(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index 7873d07e40c..deefbfd9259 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -13,13 +13,19 @@
#include <asm/machvec.h>
#include <asm/se7751.h>
#include <asm/io.h>
+#include <asm/heartbeat.h>
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+};
+
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
@@ -28,14 +34,13 @@ static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
.dev = {
- .platform_data = heartbeat_bit_pos,
+ .platform_data = &heartbeat_data,
},
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
};
static struct platform_device *se7751_devices[] __initdata = {
- &smc91x_device,
&heartbeat_device,
};
diff --git a/arch/sh/boards/se/7780/irq.c b/arch/sh/boards/se/7780/irq.c
index 87491474600..6bd70da6bb4 100644
--- a/arch/sh/boards/se/7780/irq.c
+++ b/arch/sh/boards/se/7780/irq.c
@@ -16,32 +16,6 @@
#include <asm/io.h>
#include <asm/se7780.h>
-static struct intc2_data intc2_irq_table[] = {
- { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */
- { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */
- { 6, 0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */
- { 8, 0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */
- { 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */
- { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */
- { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */
- { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */
- { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */
- { 0 , 0, 24, 0, 24, 3 }, /* SM501 */
-};
-
-static struct intc2_desc intc2_irq_desc __read_mostly = {
- .prio_base = 0, /* N/A */
- .msk_base = 0xffd00044,
- .mskclr_base = 0xffd00064,
-
- .intc2_data = intc2_irq_table,
- .nr_irqs = ARRAY_SIZE(intc2_irq_table),
-
- .chip = {
- .name = "INTC2-se7780",
- },
-};
-
/*
* Initialize IRQ setting
*/
@@ -68,5 +42,5 @@ void __init init_se7780_IRQ(void)
/* FPGA + 0x0A */
ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
- register_intc2_controller(&intc2_irq_desc);
+ plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-7 */
}
diff --git a/arch/sh/boards/se/7780/setup.c b/arch/sh/boards/se/7780/setup.c
index 723f2fd4d55..76e53b26a80 100644
--- a/arch/sh/boards/se/7780/setup.c
+++ b/arch/sh/boards/se/7780/setup.c
@@ -16,12 +16,10 @@
#include <asm/io.h>
/* Heartbeat */
-static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_LED,
- .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .end = PA_LED,
.flags = IORESOURCE_MEM,
},
};
@@ -29,9 +27,6 @@ static struct resource heartbeat_resources[] = {
static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
- .dev = {
- .platform_data = heartbeat_bit_pos,
- },
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
};
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
index 9c031a8c0a1..934ac4f1c48 100644
--- a/arch/sh/boards/sh03/setup.c
+++ b/arch/sh/boards/sh03/setup.c
@@ -15,33 +15,9 @@
#include <asm/sh03/sh03.h>
#include <asm/addrspace.h>
-static struct ipr_data ipr_irq_table[] = {
- { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
- { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
- { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
- { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
-};
-
-static unsigned long ipr_offsets[] = {
- INTC_IPRD,
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh03",
- },
-};
-
static void __init init_sh03_IRQ(void)
{
- ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
- register_ipr_controller(&ipr_irq_desc);
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
}
extern void *cf_io_base;
@@ -68,7 +44,7 @@ static void __init sh03_setup(char **cmdline_p)
static struct resource heartbeat_resources[] = {
[0] = {
.start = 0xa0800000,
- .end = 0xa0800000 + 8 - 1,
+ .end = 0xa0800000,
.flags = IORESOURCE_MEM,
},
};
diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c
index dfd124509f4..16e5dae8ecf 100644
--- a/arch/sh/boards/shmin/setup.c
+++ b/arch/sh/boards/shmin/setup.c
@@ -14,36 +14,12 @@
#define PFC_PHCR 0xa400010eUL
#define INTC_ICR1 0xa4000010UL
-#define INTC_IPRC 0xa4000016UL
-
-static struct ipr_data ipr_irq_table[] = {
- { 32, 0, 0, 0 },
- { 33, 0, 4, 0 },
- { 34, 0, 8, 8 },
- { 35, 0, 12, 0 },
-};
-
-static unsigned long ipr_offsets[] = {
- INTC_IPRC,
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-shmin",
- },
-};
static void __init init_shmin_irq(void)
{
ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ
ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active.
- register_ipr_controller(&ipr_irq_desc);
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
}
static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
index 84271d85a8d..2b594f60000 100644
--- a/arch/sh/boards/snapgear/setup.c
+++ b/arch/sh/boards/snapgear/setup.c
@@ -68,37 +68,11 @@ module_init(eraseconfig_init);
* IRL3 = crypto
*/
-static struct ipr_data ipr_irq_table[] = {
- { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
- { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
- { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
- { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
-};
-
-static unsigned long ipr_offsets[] = {
- INTC_IPRD,
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-snapgear",
- },
-};
-
static void __init init_snapgear_IRQ(void)
{
- /* enable individual interrupt mode for externals */
- ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
-
printk("Setup SnapGear IRQ/IPR ...\n");
-
- register_ipr_controller(&ipr_irq_desc);
+ /* enable individual interrupt mode for externals */
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
}
/*
diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c
index 606d25a4b87..5de3b2ad71a 100644
--- a/arch/sh/boards/titan/setup.c
+++ b/arch/sh/boards/titan/setup.c
@@ -12,38 +12,10 @@
#include <asm/titan.h>
#include <asm/io.h>
-static struct ipr_data ipr_irq_table[] = {
- /* IRQ, IPR idx, shift, prio */
- { TITAN_IRQ_WAN, 3, 12, 8 }, /* eth0 (WAN) */
- { TITAN_IRQ_LAN, 3, 8, 8 }, /* eth1 (LAN) */
- { TITAN_IRQ_MPCIA, 3, 4, 8 }, /* mPCI A (top) */
- { TITAN_IRQ_USB, 3, 0, 8 }, /* mPCI B (bottom), USB */
-};
-
-static unsigned long ipr_offsets[] = { /* stolen from setup-sh7750.c */
- 0xffd00004UL, /* 0: IPRA */
- 0xffd00008UL, /* 1: IPRB */
- 0xffd0000cUL, /* 2: IPRC */
- 0xffd00010UL, /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-titan",
- },
-};
static void __init init_titan_irq(void)
{
/* enable individual interrupt mode for externals */
- ipr_irq_enable_irlm();
- /* register ipr irqs */
- register_ipr_controller(&ipr_irq_desc);
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
}
static struct sh_machine_vector mv_titan __initmv = {
diff --git a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig
index 2e516e9a6ed..7892361eedc 100644
--- a/arch/sh/cchips/Kconfig
+++ b/arch/sh/cchips/Kconfig
@@ -1,18 +1,5 @@
menu "Companion Chips"
-config VOYAGERGX
- bool "VoyagerGX chip support"
- depends on SH_RTS7751R2D
- help
- Selecting this option will support Silicon Motion, Inc. SM501.
- Designed to complement needs for the embedded industry, it
- provides video and 2D capability. To reduce system cost a
- wide variety of include I/O is supported, including analog RGB
- and digital LCD Panel interface, 8-bit parallel interface, USB,
- UART, IrDA, Zoom Video, AC97 or I2S, SSP, PWM, and I2C. There
- are additional GPIO bits that can be used to interface to
- external as well.
-
config HD6446X_SERIES
bool
diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c
index 97f6512aa1b..f1a4a0763c5 100644
--- a/arch/sh/cchips/hd6446x/hd64461.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -14,6 +14,9 @@
#include <asm/irq.h>
#include <asm/hd64461.h>
+/* This belongs in cpu specific */
+#define INTC_ICR1 0xA4140010UL
+
static void disable_hd64461_irq(unsigned int irq)
{
unsigned short nimr;
@@ -121,10 +124,15 @@ int hd64461_irq_demux(int irq)
}
}
}
- return __irq_demux(irq);
+ return irq;
}
-static struct irqaction irq0 = { hd64461_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64461", NULL, NULL };
+static struct irqaction irq0 = {
+ .handler = hd64461_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "HD64461",
+};
int __init setup_hd64461(void)
{
@@ -143,6 +151,7 @@ int __init setup_hd64461(void)
#endif
outw(0xffff, HD64461_NIMR);
+ /* IRQ 80 -> 95 belongs to HD64461 */
for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
irq_desc[i].chip = &hd64461_irq_type;
}
diff --git a/arch/sh/cchips/hd6446x/hd64465/setup.c b/arch/sh/cchips/hd6446x/hd64465/setup.c
index d126e1f30de..5cef0db4018 100644
--- a/arch/sh/cchips/hd6446x/hd64465/setup.c
+++ b/arch/sh/cchips/hd6446x/hd64465/setup.c
@@ -147,7 +147,12 @@ int hd64465_irq_demux(int irq)
return irq;
}
-static struct irqaction irq0 = { hd64465_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64465", NULL, NULL};
+static struct irqaction irq0 = {
+ .handler = hd64465_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "HD64465",
+};
static int __init setup_hd64465(void)
diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c
index d70e5c8461b..ade30387684 100644
--- a/arch/sh/cchips/voyagergx/irq.c
+++ b/arch/sh/cchips/voyagergx/irq.c
@@ -23,149 +23,79 @@
#include <asm/voyagergx.h>
#include <asm/rts7751r2d.h>
-static void disable_voyagergx_irq(unsigned int irq)
-{
- unsigned long val;
- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
-
- pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
- val = readl((void __iomem *)VOYAGER_INT_MASK);
- val &= ~mask;
- writel(val, (void __iomem *)VOYAGER_INT_MASK);
-}
-
-static void enable_voyagergx_irq(unsigned int irq)
-{
- unsigned long val;
- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
-
- pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
- val = readl((void __iomem *)VOYAGER_INT_MASK);
- val |= mask;
- writel(val, (void __iomem *)VOYAGER_INT_MASK);
-}
-
-static void mask_and_ack_voyagergx(unsigned int irq)
-{
- disable_voyagergx_irq(irq);
-}
-
-static void end_voyagergx_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_voyagergx_irq(irq);
-}
-
-static unsigned int startup_voyagergx_irq(unsigned int irq)
-{
- enable_voyagergx_irq(irq);
- return 0;
-}
-
-static void shutdown_voyagergx_irq(unsigned int irq)
-{
- disable_voyagergx_irq(irq);
-}
-
-static struct hw_interrupt_type voyagergx_irq_type = {
- .typename = "VOYAGERGX-IRQ",
- .startup = startup_voyagergx_irq,
- .shutdown = shutdown_voyagergx_irq,
- .enable = enable_voyagergx_irq,
- .disable = disable_voyagergx_irq,
- .ack = mask_and_ack_voyagergx,
- .end = end_voyagergx_irq,
+enum {
+ UNUSED = 0,
+
+ /* voyager specific interrupt sources */
+ UP, G54, G53, G52, G51, G50, G49, G48,
+ I2C, PW, DMA, PCI, I2S, AC, US,
+ U1, U0, CV, MC, S1, S0,
+ UH, TWOD, ZD, PV, CI,
};
-static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
-{
- printk(KERN_INFO
- "VoyagerGX: spurious interrupt, status: 0x%x\n",
- (unsigned int)readl((void __iomem *)INT_STATUS));
- return IRQ_HANDLED;
-}
-
-static struct {
- int (*func)(int, void *);
- void *dev;
-} voyagergx_demux[VOYAGER_IRQ_NUM];
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54),
+ INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52),
+ INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50),
+ INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48),
+ INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW),
+ INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI),
+ INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC),
+ INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1),
+ INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV),
+ INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1),
+ INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH),
+ INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD),
+ INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI),
+};
-void voyagergx_register_irq_demux(int irq,
- int (*demux)(int irq, void *dev), void *dev)
-{
- voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
- voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
-}
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { VOYAGER_INT_MASK, 0, 32, /* "Interrupt Mask", MMIO_base + 0x30 */
+ { UP, G54, G53, G52, G51, G50, G49, G48,
+ I2C, PW, 0, DMA, PCI, I2S, AC, US,
+ 0, 0, U1, U0, CV, MC, S1, S0,
+ 0, UH, 0, 0, TWOD, ZD, PV, CI } },
+};
-void voyagergx_unregister_irq_demux(int irq)
-{
- voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
-}
+static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors,
+ NULL, NULL, mask_registers, NULL, NULL);
+
+static unsigned int voyagergx_stat2irq[32] = {
+ IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D,
+ 0, 0, IRQ_SM501_UH, 0,
+ IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV,
+ IRQ_SM501_U0, IRQ_SM501_U1, 0, 0,
+ IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI,
+ IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C,
+ IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51,
+ IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP
+};
-int voyagergx_irq_demux(int irq)
+static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
{
-
- if (irq == IRQ_VOYAGER ) {
- unsigned long i = 0, bit __attribute__ ((unused));
- unsigned long val = readl((void __iomem *)INT_STATUS);
-
- if (val & (1 << 1))
- i = 1;
- else if (val & (1 << 2))
- i = 2;
- else if (val & (1 << 6))
- i = 6;
- else if (val & (1 << 10))
- i = 10;
- else if (val & (1 << 11))
- i = 11;
- else if (val & (1 << 12))
- i = 12;
- else if (val & (1 << 17))
- i = 17;
- else
- printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
- pr_debug("voyagergx_irq_demux %ld \n", i);
- if (i < VOYAGER_IRQ_NUM) {
- irq = VOYAGER_IRQ_BASE + i;
- if (voyagergx_demux[i].func != 0)
- irq = voyagergx_demux[i].func(irq,
- voyagergx_demux[i].dev);
+ unsigned long intv = ctrl_inl(INT_STATUS);
+ struct irq_desc *ext_desc;
+ unsigned int ext_irq;
+ unsigned int k = 0;
+
+ while (intv) {
+ ext_irq = voyagergx_stat2irq[k];
+ if (ext_irq && (intv & 1)) {
+ ext_desc = irq_desc + ext_irq;
+ handle_level_irq(ext_irq, ext_desc);
}
+ intv >>= 1;
+ k++;
}
- return irq;
}
-static struct irqaction irq0 = {
- .name = "voyagergx",
- .handler = voyagergx_interrupt,
- .flags = IRQF_DISABLED,
- .mask = CPU_MASK_NONE,
-};
-
void __init setup_voyagergx_irq(void)
{
- int i, flag;
-
- printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
- VOYAGER_BASE,
+ printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
IRQ_VOYAGER,
VOYAGER_IRQ_BASE,
VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
- for (i=0; i<VOYAGER_IRQ_NUM; i++) {
- flag = 0;
- switch (VOYAGER_IRQ_BASE + i) {
- case VOYAGER_USBH_IRQ:
- case VOYAGER_8051_IRQ:
- case VOYAGER_UART0_IRQ:
- case VOYAGER_UART1_IRQ:
- case VOYAGER_AC97_IRQ:
- flag = 1;
- }
- if (flag == 1)
- irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
- }
-
- setup_irq(IRQ_VOYAGER, &irq0);
+ register_intc_controller(&intc_desc);
+ set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
}
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
index 3fdd270eecf..57728788b75 100644
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Sat Jul 7 03:47:45 2007
+# Linux kernel version: 2.6.23-rc7
+# Fri Sep 21 15:46:27 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -18,30 +18,26 @@ CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
@@ -64,7 +60,6 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
@@ -74,24 +69,17 @@ CONFIG_SLAB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -112,7 +100,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_CPU_SH4=y
# CONFIG_CPU_SUBTYPE_SH7619 is not set
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -120,6 +107,7 @@ CONFIG_CPU_SH4=y
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
CONFIG_CPU_SUBTYPE_SH7091=y
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -134,7 +122,6 @@ CONFIG_CPU_SUBTYPE_SH7091=y
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
# CONFIG_CPU_SUBTYPE_SHX3 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
@@ -177,7 +164,9 @@ CONFIG_NR_QUICK=2
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
#
# Processor features
@@ -185,12 +174,11 @@ CONFIG_NR_QUICK=2
CONFIG_CPU_LITTLE_ENDIAN=y
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
CONFIG_SH_STORE_QUEUES=y
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
+CONFIG_CPU_HAS_FPU=y
#
# Board support
@@ -270,6 +258,7 @@ CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
#
# Bus options
#
+CONFIG_MAPLE=y
CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
@@ -368,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -380,27 +370,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
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
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
@@ -411,14 +384,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -426,12 +396,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
#
@@ -444,26 +411,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
@@ -472,10 +429,6 @@ CONFIG_MII=y
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
@@ -520,15 +473,7 @@ CONFIG_8139TOO=y
# 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
#
@@ -536,6 +481,7 @@ CONFIG_8139TOO=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -606,10 +552,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -631,10 +573,6 @@ CONFIG_HW_RANDOM=y
# CONFIG_APPLICOM is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
@@ -644,11 +582,8 @@ CONFIG_DEVPORT=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
#
@@ -673,6 +608,7 @@ CONFIG_DEVPORT=y
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
@@ -699,7 +635,6 @@ CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
CONFIG_FB_PVR2=y
-# CONFIG_FB_EPSON1355 is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
@@ -725,6 +660,7 @@ CONFIG_FB_PVR2=y
#
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
@@ -749,16 +685,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -773,32 +703,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
# CONFIG_USB_GADGET is not set
# 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
#
@@ -815,6 +721,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
# File systems
#
# CONFIG_EXT2_FS is not set
@@ -890,7 +801,6 @@ CONFIG_RAMFS=y
# 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
@@ -935,10 +845,6 @@ CONFIG_ENABLE_MUST_CHECK=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -949,6 +855,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig
index b931d9b2d57..756d38dc2f7 100644
--- a/arch/sh/configs/hp6xx_defconfig
+++ b/arch/sh/configs/hp6xx_defconfig
@@ -1,37 +1,47 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct 3 11:10:06 2006
+# Linux kernel version: 2.6.23-rc4
+# Tue Sep 11 19:42:44 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
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 is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_IKCONFIG is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_USER_NS is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
CONFIG_UID16=y
@@ -44,27 +54,25 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
# CONFIG_MODULES 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
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -82,55 +90,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-CONFIG_SH_HP6XX=y
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH3=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
CONFIG_CPU_SUBTYPE_SH7709=y
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -139,66 +109,78 @@ CONFIG_CPU_SUBTYPE_SH7709=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
-CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_START=0x0d000000
CONFIG_MEMORY_SIZE=0x00400000
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
# CONFIG_SH_FPU_EMU is not set
-# CONFIG_SH_DSP is not set
CONFIG_SH_ADC=y
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_PINT_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
#
-# Timer support
+# Board support
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_HP6XX=y
+
+#
+# Timer and clock configuration
#
CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
CONFIG_SH_PCLK_FREQ=22110000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
#
# CPU Frequency scaling
@@ -208,6 +190,7 @@ CONFIG_SH_PCLK_FREQ=22110000
#
# DMA support
#
+CONFIG_SH_DMA_API=y
CONFIG_SH_DMA=y
CONFIG_NR_ONCHIP_DMA_CHANNELS=4
# CONFIG_NR_DMA_CHANNELS_BOOL is not set
@@ -223,14 +206,21 @@ CONFIG_HD64461_IOBASE=0xb0000000
CONFIG_HD64461_ENABLER=y
#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
# Kernel features
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -240,14 +230,13 @@ CONFIG_PREEMPT_NONE=y
#
CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Bus options
#
CONFIG_ISA=y
-# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -266,14 +255,9 @@ CONFIG_PCMCIA_IOCTL=y
CONFIG_PCMCIA_PROBE=y
#
-# PCI Hotplug Support
-#
-
-#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
@@ -282,8 +266,9 @@ CONFIG_BINFMT_ELF=y
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-CONFIG_APM=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_APM_EMULATION=y
#
# Networking
@@ -301,109 +286,76 @@ CONFIG_APM=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
# CONFIG_PNP is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+CONFIG_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_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+CONFIG_PATA_PLATFORM=y
# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -411,19 +363,17 @@ CONFIG_IDE_GENERIC=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
CONFIG_INPUT_TSDEV=y
CONFIG_INPUT_TSDEV_SCREEN_X=240
CONFIG_INPUT_TSDEV_SCREEN_Y=320
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
@@ -436,9 +386,12 @@ CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_HP6XX=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
@@ -447,6 +400,7 @@ CONFIG_TOUCHSCREEN_HP600=y
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -476,46 +430,29 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
+CONFIG_LEGACY_PTY_COUNT=64
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
#
-# Ftape, the floppy tape device driver
-#
-
-#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_CARDMAN_4000 is not set
# CONFIG_CARDMAN_4040 is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -523,48 +460,55 @@ CONFIG_HW_RANDOM=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
#
-# Dallas's 1-wire bus
-#
-
-#
-# Hardware Monitoring support
-#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
+# Multifunction device drivers
#
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
+# CONFIG_DAB is not set
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_HP680=y
#
-# Graphics support
+# Display device support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_EPSON1355 is not set
+
+#
+# Frame buffer hardware drivers
+#
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_HIT=y
# CONFIG_FB_VIRTUAL is not set
@@ -575,6 +519,7 @@ CONFIG_FB_HIT=y
# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
@@ -587,79 +532,49 @@ CONFIG_FONT_PEARL_8x8=y
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
# CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE_DRIVER is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_SH_DAC_AUDIO=y
-CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
-
-#
-# 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_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
# CONFIG_MMC is not set
-
-#
-# LED devices
-#
# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
-# LED drivers
-#
-
-#
-# LED Triggers
+# 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
+# CONFIG_RTC_DRV_TEST is not set
#
-# InfiniBand support
+# SPI RTC drivers
#
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# Platform RTC drivers
#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
#
-# Real Time Clock
+# on-CPU RTC drivers
#
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_DRV_SH=y
#
# DMA Engine support
@@ -675,16 +590,23 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
@@ -705,7 +627,7 @@ CONFIG_DNOTIFY=y
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
@@ -755,7 +677,7 @@ 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_850=y
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
@@ -799,34 +721,73 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_UNWIND_INFO is not set
# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# 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_HW is not set
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig
new file mode 100644
index 00000000000..f8398a5f10e
--- /dev/null
+++ b/arch/sh/configs/magicpanelr2_defconfig
@@ -0,0 +1,925 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc2
+# Fri Aug 17 12:15:16 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+CONFIG_CPU_SUBTYPE_SH7720=y
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0C000000
+CONFIG_MEMORY_SIZE=0x03F00000
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+CONFIG_SH_ADC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_DSP=y
+
+#
+# Board support
+#
+CONFIG_SH_MAGIC_PANEL_R2=y
+
+#
+# Magic Panel R2 options
+#
+CONFIG_SH_MAGIC_PANEL_R2_VERSION=3
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=24000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA_API=y
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=6
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT 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
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0000000
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+# CONFIG_MTD_SOLUTIONENGINE is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+CONFIG_SMC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=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=48
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# 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
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_BIND34=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# 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=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_DEBUG_KOBJECT=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xa4430000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+CONFIG_SH_KGDB=y
+
+#
+# KGDB configuration options
+#
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+# CONFIG_KGDB_NMI is not set
+CONFIG_KGDB_SYSRQ=y
+
+#
+# Serial port setup
+#
+CONFIG_KGDB_DEFPORT=0
+CONFIG_KGDB_DEFBAUD=115200
+CONFIG_KGDB_DEFPARITY_N=y
+# CONFIG_KGDB_DEFPARITY_E is not set
+# CONFIG_KGDB_DEFPARITY_O is not set
+CONFIG_KGDB_DEFBITS_8=y
+# CONFIG_KGDB_DEFBITS_7 is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d1_defconfig
index b64f73b704d..2dc754e5b73 100644
--- a/arch/sh/configs/rts7751r2d_defconfig
+++ b/arch/sh/configs/rts7751r2d1_defconfig
@@ -1,46 +1,47 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc1
-# Thu Mar 1 16:42:40 2007
+# Linux kernel version: 2.6.23-rc2
+# Tue Aug 14 18:04:44 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
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_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -54,31 +55,29 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -96,61 +95,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-CONFIG_SH_RTS7751R2D=y
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH4=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
# CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -159,35 +113,30 @@ CONFIG_CPU_SH4=y
CONFIG_CPU_SUBTYPE_SH7751R=y
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -197,17 +146,19 @@ CONFIG_FLATMEM_MANUAL=y
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
#
# Processor features
@@ -215,7 +166,6 @@ CONFIG_ZONE_DMA_FLAG=0
CONFIG_CPU_LITTLE_ENDIAN=y
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
CONFIG_CPU_HAS_INTC_IRQ=y
@@ -223,17 +173,31 @@ CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
#
-# Timer support
+# Board support
#
-CONFIG_SH_TMU=y
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_LBOX_RE2 is not set
#
# RTS7751R2D options
#
-CONFIG_RTS7751R2D_REV11=y
+# CONFIG_RTS7751R2D_PLUS is not set
+CONFIG_RTS7751R2D_1=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=16
-# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=60000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
#
# CPU Frequency scaling
@@ -244,19 +208,15 @@ CONFIG_SH_PCLK_FREQ=60000000
# DMA support
#
# CONFIG_SH_DMA is not set
-# CONFIG_NR_ONCHIP_DMA_CHANNELS is not set
-# CONFIG_NR_DMA_CHANNELS_BOOL is not set
#
# Companion Chips
#
-CONFIG_VOYAGERGX=y
-# CONFIG_HD6446X_SERIES is not set
-CONFIG_HEARTBEAT=y
#
# Additional SuperH Device Drivers
#
+CONFIG_HEARTBEAT=y
# CONFIG_PUSH_SWITCH is not set
#
@@ -268,7 +228,7 @@ CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -289,15 +249,12 @@ CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
CONFIG_HOTPLUG_PCI=y
# CONFIG_HOTPLUG_PCI_FAKE is not set
# CONFIG_HOTPLUG_PCI_CPCI is not set
@@ -307,15 +264,9 @@ CONFIG_HOTPLUG_PCI=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -323,7 +274,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -360,20 +310,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# 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
@@ -399,8 +337,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -413,31 +360,10 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=m
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
@@ -449,19 +375,13 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
# CONFIG_IDE is not set
#
@@ -469,6 +389,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -490,6 +411,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -497,12 +419,8 @@ CONFIG_BLK_DEV_SD=y
# 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_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
@@ -512,7 +430,6 @@ CONFIG_BLK_DEV_SD=y
# 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
@@ -535,10 +452,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_AHCI is not set
@@ -561,6 +474,7 @@ CONFIG_ATA=y
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -593,10 +507,6 @@ CONFIG_ATA=y
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
CONFIG_PATA_PLATFORM=y
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
#
@@ -610,35 +520,18 @@ CONFIG_PATA_PLATFORM=y
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
@@ -647,10 +540,6 @@ CONFIG_MII=y
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
@@ -677,10 +566,7 @@ CONFIG_8139TOO=y
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
@@ -691,61 +577,26 @@ CONFIG_8139TOO=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
# 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_MLX4_CORE is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_NET_WIRELESS_RTNETLINK is not set
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2200 is not set
-CONFIG_HERMES=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
+# Wireless LAN
#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -756,15 +607,7 @@ CONFIG_NET_WIRELESS=y
# 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
#
@@ -772,6 +615,7 @@ CONFIG_NET_WIRELESS=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -788,6 +632,7 @@ CONFIG_INPUT=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -828,32 +673,15 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -861,21 +689,24 @@ CONFIG_HW_RANDOM=y
#
# 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_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 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_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -887,22 +718,31 @@ CONFIG_MFD_SM501=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
@@ -910,14 +750,13 @@ CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_TILEBLITTING is not set
#
-# Frambuffer hardware drivers
+# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
@@ -932,7 +771,10 @@ CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
CONFIG_FB_SM501=y
# CONFIG_FB_VIRTUAL is not set
@@ -941,14 +783,11 @@ CONFIG_FB_SM501=y
#
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
@@ -1048,35 +887,34 @@ CONFIG_SND_AC97_CODEC=m
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
CONFIG_SND_YMFPCI=m
+CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y
# CONFIG_SND_AC97_POWER_SAVE is not set
#
-# SoC audio support
+# SUPERH devices
+#
+
+#
+# System on Chip audio support
#
# CONFIG_SND_SOC is not set
#
+# SoC Audio support for SuperH
+#
+
+#
# Open Sound System
#
CONFIG_SOUND_PRIME=m
-# CONFIG_OBSOLETE_OSS is not set
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_ICH is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
CONFIG_AC97_BUS=m
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1090,37 +928,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
-
-#
-# LED devices
-#
# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1134,18 +944,28 @@ CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
#
-# RTC drivers
+# Platform RTC drivers
#
# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_SH=y
-# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_M48T59 is not set
# CONFIG_RTC_DRV_V3020 is not set
#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
# DMA Engine support
#
# CONFIG_DMA_ENGINE is not set
@@ -1159,12 +979,9 @@ CONFIG_RTC_DRV_SH=y
#
#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
#
+# CONFIG_UIO is not set
#
# File systems
@@ -1247,7 +1064,6 @@ CONFIG_RAMFS=y
# 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
@@ -1321,7 +1137,6 @@ CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_SH_STANDARD_BIOS is not set
CONFIG_EARLY_SCIF_CONSOLE=y
@@ -1334,10 +1149,6 @@ CONFIG_EARLY_PRINTK=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -1346,8 +1157,11 @@ CONFIG_EARLY_PRINTK=y
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig
new file mode 100644
index 00000000000..4ff5a752dcd
--- /dev/null
+++ b/arch/sh/configs/rts7751r2dplus_defconfig
@@ -0,0 +1,1167 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc2
+# Tue Aug 14 16:33:08 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Board support
+#
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_LBOX_RE2 is not set
+
+#
+# RTS7751R2D options
+#
+CONFIG_RTS7751R2D_PLUS=y
+# CONFIG_RTS7751R2D_1 is not set
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=60000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=serial"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=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
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# 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_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_PATA_PLATFORM=y
+# 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_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
+# 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
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+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_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=1
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 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_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 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=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+CONFIG_FB_SM501=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y
+# CONFIG_SND_AC97_POWER_SAVE is not set
+
+#
+# SUPERH devices
+#
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+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
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS 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_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig
index f2f2a3c9c32..0d0cda90827 100644
--- a/arch/sh/configs/se7206_defconfig
+++ b/arch/sh/configs/se7206_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Fri Jun 15 19:37:46 2007
+# Linux kernel version: 2.6.23-rc4
+# Thu Sep 13 16:40:16 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -17,25 +17,22 @@ CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
@@ -60,23 +57,17 @@ CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
# CONFIG_SLOB is not set
CONFIG_TINY_SHMEM=y
CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
# CONFIG_MODULES is not set
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -98,7 +89,6 @@ CONFIG_CPU_SH2=y
CONFIG_CPU_SH2A=y
# CONFIG_CPU_SUBTYPE_SH7619 is not set
CONFIG_CPU_SUBTYPE_SH7206=y
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -106,6 +96,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -119,7 +110,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
@@ -136,15 +127,16 @@ CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_MAX_ACTIVE_REGIONS=1
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
@@ -155,7 +147,9 @@ CONFIG_NR_QUICK=2
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
#
# Processor features
@@ -163,8 +157,6 @@ CONFIG_NR_QUICK=2
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_SH_FPU_EMU is not set
-# CONFIG_SH_DSP is not set
-CONFIG_CPU_HAS_IPR_IRQ=y
#
# Board support
@@ -185,12 +177,23 @@ CONFIG_SH_CLK_MD=6
#
# CPU Frequency scaling
#
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_SH_CPU_FREQ is not set
#
# DMA support
#
-# CONFIG_SH_DMA is not set
#
# Companion Chips
@@ -199,17 +202,17 @@ CONFIG_SH_CLK_MD=6
#
# Additional SuperH Device Drivers
#
-# CONFIG_HEARTBEAT is not set
+CONFIG_HEARTBEAT=y
# CONFIG_PUSH_SWITCH is not set
#
# Kernel features
#
-CONFIG_HZ_100=y
+# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
CONFIG_PREEMPT_NONE=y
@@ -221,11 +224,13 @@ CONFIG_PREEMPT_NONE=y
#
CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC3,115200 earlyprintk=serial ignore_loglevel"
#
# Bus options
#
+# CONFIG_CF_ENABLER is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
#
@@ -315,6 +320,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -325,11 +331,9 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
#
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
@@ -411,31 +415,16 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI 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=y
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_IDE is not set
#
@@ -443,27 +432,18 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
@@ -483,15 +463,7 @@ CONFIG_NETDEV_10000=y
# 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
#
@@ -499,6 +471,7 @@ CONFIG_NETDEV_10000=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -546,19 +519,11 @@ CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
@@ -567,11 +532,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
#
@@ -596,25 +558,21 @@ CONFIG_DAB=y
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -625,31 +583,7 @@ CONFIG_HID=y
#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
-
-#
-# LED devices
-#
# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
# CONFIG_RTC_CLASS is not set
#
@@ -666,6 +600,11 @@ CONFIG_HID=y
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
# File systems
#
# CONFIG_EXT2_FS is not set
@@ -736,7 +675,6 @@ CONFIG_RAMFS=y
# 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
@@ -752,12 +690,12 @@ CONFIG_MSDOS_PARTITION=y
#
# Distributed Lock Manager
#
-# CONFIG_DLM is not set
#
# Profiling support
#
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
#
# Kernel hacking
@@ -768,19 +706,41 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_SLUB_DEBUG_ON=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xfffe9800
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_4KSTACKS is not set
#
# Security options
#
# CONFIG_KEYS is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -791,6 +751,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_HAS_IOMEM=y
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
index 219bad558b1..a794c082709 100644
--- a/arch/sh/configs/shx3_defconfig
+++ b/arch/sh/configs/shx3_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Wed Jun 20 14:09:27 2007
+# Linux kernel version: 2.6.23-rc7
+# Fri Sep 21 19:07:30 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -13,32 +13,33 @@ CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_SYS_SUPPORTS_NUMA=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -63,34 +64,26 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
+# CONFIG_SLAB is not set
# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
+CONFIG_SLOB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -113,7 +106,6 @@ CONFIG_CPU_SH4A=y
CONFIG_CPU_SHX3=y
# CONFIG_CPU_SUBTYPE_SH7619 is not set
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -121,6 +113,7 @@ CONFIG_CPU_SHX3=y
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -135,7 +128,6 @@ CONFIG_CPU_SHX3=y
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
CONFIG_CPU_SUBTYPE_SHX3=y
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
@@ -148,12 +140,15 @@ CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
CONFIG_VSYSCALL=y
+# CONFIG_NUMA is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
-CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_MAX_ACTIVE_REGIONS=6
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_MEMORY_PROBE=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -163,12 +158,14 @@ CONFIG_HUGETLB_PAGE_SIZE_64K=y
# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
CONFIG_SPARSEMEM_STATIC=y
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
@@ -178,24 +175,25 @@ CONFIG_NR_QUICK=2
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_CACHE_WRITEBACK is not set
+# CONFIG_CACHE_WRITETHROUGH is not set
+CONFIG_CACHE_OFF=y
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
# CONFIG_CPU_BIG_ENDIAN is not set
-# CONFIG_SH_FPU is not set
-# CONFIG_SH_FPU_EMU is not set
-CONFIG_SH_DSP=y
+CONFIG_SH_FPU=y
CONFIG_SH_STORE_QUEUES=y
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
#
# Board support
#
+CONFIG_SH_X3PROTO=y
#
# Timer and clock configuration
@@ -204,13 +202,25 @@ CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=16
CONFIG_SH_PCLK_FREQ=50000000
CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
+# CONFIG_NO_HZ is not set
CONFIG_HIGH_RES_TIMERS=y
#
# CPU Frequency scaling
#
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_SH_CPU_FREQ=y
#
# DMA support
@@ -237,6 +247,7 @@ CONFIG_HZ_250=y
CONFIG_HZ=250
CONFIG_KEXEC=y
# CONFIG_CRASH_DUMP is not set
+# CONFIG_SMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
@@ -249,7 +260,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
# CONFIG_UBC_WAKEUP is not set
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/nfs nfsroot=192.168.1.1:/exports/devel/rfs/mobiler noaliencache earlyprintk=bios ignore_loglevel"
+CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=bios ignore_loglevel"
#
# Bus options
@@ -265,12 +276,106 @@ CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/n
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
#
# Networking
#
-# CONFIG_NET is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+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=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -285,37 +390,21 @@ 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
# 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=y
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_IDE is not set
#
@@ -323,6 +412,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -351,73 +441,54 @@ CONFIG_SCSI_WAIT_SCAN=m
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_DEBUG is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
CONFIG_PATA_PLATFORM=y
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
# CONFIG_PHONE is not set
#
# Input device support
#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT is not set
#
# Hardware I/O ports
#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
@@ -442,19 +513,18 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
#
-# IPMI
+# Watchdog Device Drivers
#
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SH_WDT is not set
+# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
@@ -463,11 +533,8 @@ CONFIG_HW_RANDOM=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
#
@@ -479,6 +546,7 @@ CONFIG_HW_RANDOM=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
# CONFIG_DAB is not set
#
@@ -491,24 +559,18 @@ CONFIG_HW_RANDOM=y
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
-# CONFIG_HID is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -517,68 +579,32 @@ CONFIG_HW_RANDOM=y
#
# USB Gadget Support
#
-# CONFIG_USB_GADGET is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_M66592=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_MMC is not set
-
-#
-# LED devices
-#
# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# I2C RTC drivers
-#
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform 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_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
-CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_CLASS is not set
#
# DMA Engine support
@@ -594,6 +620,11 @@ CONFIG_RTC_DRV_SH=y
#
#
+# Userspace I/O
+#
+CONFIG_UIO=m
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -612,6 +643,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -667,6 +699,17 @@ CONFIG_RAMFS=y
# CONFIG_UFS_FS is not set
#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
@@ -678,6 +721,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
CONFIG_PROFILING=y
@@ -687,31 +735,28 @@ CONFIG_PROFILING=y
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_TIME is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
-CONFIG_LOCKDEP=y
-CONFIG_DEBUG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
@@ -735,10 +780,6 @@ CONFIG_DEBUG_STACK_USAGE=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -749,6 +790,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index ee711431e50..4e711a0c3da 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -12,6 +12,7 @@ config SH_DMA
config NR_ONCHIP_DMA_CHANNELS
int
depends on SH_DMA
+ default "6" if CPU_SUBTYPE_SH7720
default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
default "12" if CPU_SUBTYPE_SH7780
default "4"
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index 06ed0609a95..958bac1c585 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -24,13 +24,19 @@ static int dmte_irq_map[] = {
DMTE1_IRQ,
DMTE2_IRQ,
DMTE3_IRQ,
-#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
defined(CONFIG_CPU_SUBTYPE_SH7780)
DMTE4_IRQ,
DMTE5_IRQ,
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780)
DMTE6_IRQ,
- DMTE7_IRQ,
+ DMTE7_IRQ,
#endif
};
@@ -196,7 +202,8 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)
return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan);
}
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780)
#define dmaor_read_reg() ctrl_inw(DMAOR)
#define dmaor_write_reg(data) ctrl_outw(data, DMAOR)
#else
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index 10c1828c9ff..b76a14f12ce 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -24,24 +24,44 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/io.h>
+#include <asm/heartbeat.h>
#define DRV_NAME "heartbeat"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.1"
-struct heartbeat_data {
- void __iomem *base;
- unsigned char bit_pos[8];
- struct timer_list timer;
-};
+static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
+ unsigned bit, unsigned int inverted)
+{
+ unsigned int new;
+
+ new = (1 << hd->bit_pos[bit]);
+ if (inverted)
+ new = ~new;
+
+ switch (hd->regsize) {
+ case 32:
+ iowrite32(new, hd->base);
+ break;
+ case 16:
+ iowrite16(new, hd->base);
+ break;
+ default:
+ iowrite8(new, hd->base);
+ break;
+ }
+}
static void heartbeat_timer(unsigned long data)
{
struct heartbeat_data *hd = (struct heartbeat_data *)data;
static unsigned bit = 0, up = 1;
- ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base);
+ heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
+
bit += up;
- if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1))
+ if ((bit == 0) || (bit == (hd->nr_bits)-1))
up = -up;
mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
@@ -64,21 +84,31 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
return -EINVAL;
}
- hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
- if (unlikely(!hd))
- return -ENOMEM;
-
if (pdev->dev.platform_data) {
- memcpy(hd->bit_pos, pdev->dev.platform_data,
- ARRAY_SIZE(hd->bit_pos));
+ hd = pdev->dev.platform_data;
} else {
- int i;
+ hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
+ if (unlikely(!hd))
+ return -ENOMEM;
+ }
+
+ hd->base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (!unlikely(hd->base)) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+
+ if (!pdev->dev.platform_data)
+ kfree(hd);
+
+ return -ENXIO;
+ }
- for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++)
- hd->bit_pos[i] = i;
+ if (!hd->nr_bits) {
+ hd->bit_pos = default_bit_pos;
+ hd->nr_bits = ARRAY_SIZE(default_bit_pos);
}
- hd->base = (void __iomem *)(unsigned long)res->start;
+ if (!hd->regsize)
+ hd->regsize = 8; /* default access size */
setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
platform_set_drvdata(pdev, hd);
@@ -91,10 +121,12 @@ static int heartbeat_drv_remove(struct platform_device *pdev)
struct heartbeat_data *hd = platform_get_drvdata(pdev);
del_timer_sync(&hd->timer);
+ iounmap(hd->base);
platform_set_drvdata(pdev, NULL);
- kfree(hd);
+ if (!pdev->dev.platform_data)
+ kfree(hd);
return 0;
}
diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c
index 4a518d94804..ec8430c8d2d 100644
--- a/arch/sh/drivers/pci/ops-rts7751r2d.c
+++ b/arch/sh/drivers/pci/ops-rts7751r2d.c
@@ -19,10 +19,10 @@
#include "pci-sh4.h"
static u8 rts7751r2d_irq_tab[] __initdata = {
- IRQ_PCISLOT1,
- IRQ_PCISLOT2,
- IRQ_PCMCIA,
- IRQ_PCIETH,
+ IRQ_PCI_INTA,
+ IRQ_PCI_INTB,
+ IRQ_PCI_INTC,
+ IRQ_PCI_INTD,
};
int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index 5508e45d483..e516087fb43 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -79,19 +79,6 @@ static int __init sh7780_pci_init(void)
ctrl_outl(0xAAAA0000, INTC_ICR1);
/* INTPRI: priority=3(all) */
ctrl_outl(0x33333333, INTC_INTPRI);
- } else {
- /* INTC SH-4 Mode */
- ctrl_outl(0x00200000, INTC_ICR0);
- /* enable PCIINTA - PCIINTD */
- ctrl_outl(0x00078000, INTC_INT2MSKCR);
- /* disable IRL4-7 Interrupt */
- ctrl_outl(0x40000000, INTC_INTMSK1);
- /* disable IRL4-7 Interrupt */
- ctrl_outl(0x0000fffe, INTC_INTMSK2);
- /* enable IRL0-3 Interrupt */
- ctrl_outl(0x80000000, INTC_INTMSKCLR1);
- /* enable IRL0-3 Interrupt */
- ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
}
if ((ret = sh4_pci_check_direct()) != 0)
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 92807ffa8e2..b5f1e23ed57 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -83,6 +83,8 @@ static void propagate_rate(struct clk *clk)
continue;
if (likely(clkp->ops && clkp->ops->recalc))
clkp->ops->recalc(clkp);
+ if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
+ propagate_rate(clkp);
}
}
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 9172e97dc26..c217c4bf008 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -22,6 +22,7 @@
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/ubc.h>
+#include <asm/smp.h>
/*
* Generic wrapper for command line arguments to disable on-chip
@@ -143,12 +144,15 @@ static void __init cache_init(void)
flags &= ~CCR_CACHE_EMODE;
#endif
-#ifdef CONFIG_SH_WRITETHROUGH
- /* Turn on Write-through caching */
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+ /* Write-through */
flags |= CCR_CACHE_WT;
-#else
- /* .. or default to Write-back */
+#elif defined(CONFIG_CACHE_WRITEBACK)
+ /* Write-back */
flags |= CCR_CACHE_CB;
+#else
+ /* Off */
+ flags &= ~CCR_CACHE_ENABLE;
#endif
ctrl_outl(flags, CCR);
@@ -213,8 +217,11 @@ static void __init dsp_init(void)
* Each processor family is still responsible for doing its own probing
* and cache configuration in detect_cpu_and_cache_system().
*/
-asmlinkage void __init sh_cpu_init(void)
+
+asmlinkage void __cpuinit sh_cpu_init(void)
{
+ current_thread_info()->cpu = hard_smp_processor_id();
+
/* First, probe the CPU */
detect_cpu_and_cache_system();
@@ -224,9 +231,10 @@ asmlinkage void __init sh_cpu_init(void)
/* Init the cache */
cache_init();
- shm_align_mask = max_t(unsigned long,
- current_cpu_data.dcache.way_size - 1,
- PAGE_SIZE - 1);
+ if (raw_smp_processor_id() == 0)
+ shm_align_mask = max_t(unsigned long,
+ current_cpu_data.dcache.way_size - 1,
+ PAGE_SIZE - 1);
/* Disable the FPU */
if (fpu_disabled) {
@@ -265,6 +273,7 @@ asmlinkage void __init sh_cpu_init(void)
* like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
* we wake it up and hope that all is well.
*/
- ubc_wakeup();
+ if (raw_smp_processor_id() == 0)
+ ubc_wakeup();
speculative_execution_init();
}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 60bfc05cf35..8da8e178f09 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -1,9 +1,7 @@
#
# Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
#
-obj-y += imask.o
+obj-y += imask.o intc.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
-obj-$(CONFIG_CPU_HAS_INTC_IRQ) += intc.o
-obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 9345a7130e9..6ac018c15e0 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -20,145 +20,258 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+ ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h) (h & 0x1f)
+#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
+#define _INTC_FN(h) ((h >> 9) & 0xf)
+#define _INTC_MODE(h) ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
+
+struct intc_handle_int {
+ unsigned int irq;
+ unsigned long handle;
+};
+
+struct intc_desc_int {
+ unsigned long *reg;
+#ifdef CONFIG_SMP
+ unsigned long *smp;
+#endif
+ unsigned int nr_reg;
+ struct intc_handle_int *prio;
+ unsigned int nr_prio;
+ struct intc_handle_int *sense;
+ unsigned int nr_sense;
+ struct irq_chip chip;
+};
-#define _INTC_MK(fn, idx, bit, value) \
- ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
-#define _INTC_FN(h) (h >> 24)
-#define _INTC_VALUE(h) ((h >> 16) & 0xff)
-#define _INTC_IDX(h) ((h >> 8) & 0xff)
-#define _INTC_BIT(h) (h & 0xff)
+#ifdef CONFIG_SMP
+#define IS_SMP(x) x.smp
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
-#define _INTC_PTR(desc, member, data) \
- (desc->member + _INTC_IDX(data))
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
-static inline struct intc_desc *get_intc_desc(unsigned int irq)
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
{
struct irq_chip *chip = get_irq_chip(irq);
- return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+ return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
}
static inline unsigned int set_field(unsigned int value,
unsigned int field_value,
- unsigned int width,
- unsigned int shift)
+ unsigned int handle)
{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+
value &= ~(((1 << width) - 1) << shift);
value |= field_value << shift;
return value;
}
-static inline unsigned int set_prio_field(struct intc_desc *desc,
- unsigned int value,
- unsigned int priority,
- unsigned int data)
+static void write_8(unsigned long addr, unsigned long h, unsigned long data)
{
- unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
-
- return set_field(value, priority, width, _INTC_BIT(data));
+ ctrl_outb(set_field(0, data, h), addr);
}
-static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+static void write_16(unsigned long addr, unsigned long h, unsigned long data)
{
- unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-
- ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+ ctrl_outw(set_field(0, data, h), addr);
}
-static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+static void write_32(unsigned long addr, unsigned long h, unsigned long data)
{
- unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
- unsigned int prio = _INTC_VALUE(data);
-
- ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+ ctrl_outl(set_field(0, data, h), addr);
}
-static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
{
- unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-
- ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+ ctrl_outb(set_field(ctrl_inb(addr), data, h), addr);
}
-static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
{
- unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
- unsigned int prio = _INTC_VALUE(data);
-
- ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+ ctrl_outw(set_field(ctrl_inw(addr), data, h), addr);
}
-static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
{
- ctrl_outb(1 << _INTC_BIT(data),
- _INTC_PTR(desc, mask_regs, data)->set_reg);
+ ctrl_outl(set_field(ctrl_inl(addr), data, h), addr);
}
-static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
+
+static void (*intc_reg_fns[])(unsigned long addr,
+ unsigned long h,
+ unsigned long data) = {
+ [REG_FN_WRITE_BASE + 0] = write_8,
+ [REG_FN_WRITE_BASE + 1] = write_16,
+ [REG_FN_WRITE_BASE + 3] = write_32,
+ [REG_FN_MODIFY_BASE + 0] = modify_8,
+ [REG_FN_MODIFY_BASE + 1] = modify_16,
+ [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+ MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
+ MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
+ MODE_PRIO_REG, /* Priority value written to enable interrupt */
+ MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
+};
+
+static void intc_mode_field(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
{
- ctrl_outb(1 << _INTC_BIT(data),
- _INTC_PTR(desc, mask_regs, data)->clr_reg);
+ fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
}
-static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+static void intc_mode_zero(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
{
- ctrl_outl(1 << _INTC_BIT(data),
- _INTC_PTR(desc, mask_regs, data)->set_reg);
+ fn(addr, handle, 0);
}
-static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+static void intc_mode_prio(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
{
- ctrl_outl(1 << _INTC_BIT(data),
- _INTC_PTR(desc, mask_regs, data)->clr_reg);
+ fn(addr, handle, intc_prio_level[irq]);
}
-enum { REG_FN_ERROR=0,
- REG_FN_MASK_8, REG_FN_MASK_32,
- REG_FN_PRIO_16, REG_FN_PRIO_32 };
-
-static struct {
- void (*enable)(struct intc_desc *, unsigned int);
- void (*disable)(struct intc_desc *, unsigned int);
-} intc_reg_fns[] = {
- [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
- [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
- [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
- [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+static void (*intc_enable_fns[])(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_prio,
+ [MODE_PCLR_REG] = intc_mode_prio,
};
-static void intc_enable(unsigned int irq)
+static void (*intc_disable_fns[])(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_zero,
+ [MODE_MASK_REG] = intc_mode_field,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_zero,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
+
+static inline void _intc_enable(unsigned int irq, unsigned long handle)
{
- struct intc_desc *desc = get_intc_desc(irq);
- unsigned int data = (unsigned int) get_irq_chip_data(irq);
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+}
- intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+static void intc_enable(unsigned int irq)
+{
+ _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
}
static void intc_disable(unsigned int irq)
{
- struct intc_desc *desc = get_intc_desc(irq);
- unsigned int data = (unsigned int) get_irq_chip_data(irq);
-
- intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = (unsigned long) get_irq_chip_data(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
}
-static void set_sense_16(struct intc_desc *desc, unsigned int data)
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+ unsigned int nr_hp,
+ unsigned int irq)
{
- unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
- unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
- unsigned int bit = _INTC_BIT(data);
- unsigned int value = _INTC_VALUE(data);
+ int i;
+
+ /* this doesn't scale well, but...
+ *
+ * this function should only be used for cerain uncommon
+ * operations such as intc_set_priority() and intc_set_sense()
+ * and in those rare cases performance doesn't matter that much.
+ * keeping the memory footprint low is more important.
+ *
+ * one rather simple way to speed this up and still keep the
+ * memory footprint down is to make sure the array is sorted
+ * and then perform a bisect to lookup the irq.
+ */
- ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+ for (i = 0; i < nr_hp; i++) {
+ if ((hp + i)->irq != irq)
+ continue;
+
+ return hp + i;
+ }
+
+ return NULL;
}
-static void set_sense_32(struct intc_desc *desc, unsigned int data)
+int intc_set_priority(unsigned int irq, unsigned int prio)
{
- unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
- unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
- unsigned int bit = _INTC_BIT(data);
- unsigned int value = _INTC_VALUE(data);
+ struct intc_desc_int *d = get_intc_desc(irq);
+ struct intc_handle_int *ihp;
+
+ if (!intc_prio_level[irq] || prio <= 1)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+ if (ihp) {
+ if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+ return -EINVAL;
- ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+ intc_prio_level[irq] = prio;
+
+ /*
+ * only set secondary masking method directly
+ * primary masking method is using intc_prio_level[irq]
+ * priority level will be set during next enable()
+ */
+
+ if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+ _intc_enable(irq, ihp->handle);
+ }
+ return 0;
}
#define VALID(x) (x | 0x80)
@@ -172,79 +285,38 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
static int intc_set_sense(unsigned int irq, unsigned int type)
{
- struct intc_desc *desc = get_intc_desc(irq);
+ struct intc_desc_int *d = get_intc_desc(irq);
unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
- unsigned int i, j, data, bit;
- intc_enum enum_id = 0;
-
- for (i = 0; i < desc->nr_vectors; i++) {
- struct intc_vect *vect = desc->vectors + i;
-
- if (evt2irq(vect->vect) != irq)
- continue;
+ struct intc_handle_int *ihp;
+ unsigned long addr;
- enum_id = vect->enum_id;
- break;
- }
-
- if (!enum_id || !value)
+ if (!value)
return -EINVAL;
- value ^= VALID(0);
-
- for (i = 0; i < desc->nr_sense_regs; i++) {
- struct intc_sense_reg *sr = desc->sense_regs + i;
-
- for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
- if (sr->enum_ids[j] != enum_id)
- continue;
-
- bit = sr->reg_width - ((j + 1) * sr->field_width);
- data = _INTC_MK(0, i, bit, value);
-
- switch(sr->reg_width) {
- case 16:
- set_sense_16(desc, data);
- break;
- case 32:
- set_sense_32(desc, data);
- break;
- }
-
- return 0;
- }
+ ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+ if (ihp) {
+ addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+ intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
}
-
- return -EINVAL;
+ return 0;
}
-static unsigned int __init intc_find_mask_handler(unsigned int width)
+static unsigned int __init intc_get_reg(struct intc_desc_int *d,
+ unsigned long address)
{
- switch (width) {
- case 8:
- return REG_FN_MASK_8;
- case 32:
- return REG_FN_MASK_32;
- }
+ unsigned int k;
- BUG();
- return REG_FN_ERROR;
-}
-
-static unsigned int __init intc_find_prio_handler(unsigned int width)
-{
- switch (width) {
- case 16:
- return REG_FN_PRIO_16;
- case 32:
- return REG_FN_PRIO_32;
+ for (k = 0; k < d->nr_reg; k++) {
+ if (d->reg[k] == address)
+ return k;
}
BUG();
- return REG_FN_ERROR;
+ return 0;
}
-static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+ intc_enum enum_id)
{
struct intc_group *g = desc->groups;
unsigned int i, j;
@@ -289,10 +361,12 @@ static unsigned int __init intc_prio_value(struct intc_desc *desc,
}
static unsigned int __init intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
intc_enum enum_id, int do_grps)
{
struct intc_mask_reg *mr = desc->mask_regs;
- unsigned int i, j, fn;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
mr = desc->mask_regs + i;
@@ -301,25 +375,46 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
if (mr->enum_ids[j] != enum_id)
continue;
- fn = intc_find_mask_handler(mr->reg_width);
- if (fn == REG_FN_ERROR)
- return 0;
+ if (mr->set_reg && mr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_DUAL_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->set_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ if (mr->set_reg) {
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+ } else {
+ mode = MODE_MASK_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->clr_reg;
+ }
+ }
- return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
}
}
if (do_grps)
- return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+ return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
return 0;
}
static unsigned int __init intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
intc_enum enum_id, int do_grps)
{
struct intc_prio_reg *pr = desc->prio_regs;
- unsigned int i, j, fn, bit, prio;
+ unsigned int i, j, fn, mode, bit;
+ unsigned long reg_e, reg_d;
for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
pr = desc->prio_regs + i;
@@ -328,28 +423,72 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
if (pr->enum_ids[j] != enum_id)
continue;
- fn = intc_find_prio_handler(pr->reg_width);
- if (fn == REG_FN_ERROR)
- return 0;
+ if (pr->set_reg && pr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_PCLR_REG;
+ reg_e = pr->set_reg;
+ reg_d = pr->clr_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_PRIO_REG;
+ if (!pr->set_reg)
+ BUG();
+ reg_e = pr->set_reg;
+ reg_d = pr->set_reg;
+ }
- prio = intc_prio_value(desc, enum_id, 1);
+ fn += (pr->reg_width >> 3) - 1;
bit = pr->reg_width - ((j + 1) * pr->field_width);
BUG_ON(bit < 0);
- return _INTC_MK(fn, i, bit, prio);
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ pr->field_width, bit);
}
}
if (do_grps)
- return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+ return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
return 0;
}
-static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+static unsigned int __init intc_sense_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_sense_reg *sr = desc->sense_regs;
+ unsigned int i, j, fn, bit;
+
+ for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
+ sr = desc->sense_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+ if (sr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ fn += (sr->reg_width >> 3) - 1;
+ bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+ BUG_ON(bit < 0);
+
+ return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+ 0, sr->field_width, bit);
+ }
+ }
+
+ return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
unsigned int irq)
{
+ struct intc_handle_int *hp;
unsigned int data[2], primary;
/* Prefer single interrupt source bitmap over other combinations:
@@ -359,15 +498,15 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
* 4. priority, multiple interrupt sources (groups)
*/
- data[0] = intc_mask_data(desc, enum_id, 0);
- data[1] = intc_prio_data(desc, enum_id, 0);
+ data[0] = intc_mask_data(desc, d, enum_id, 0);
+ data[1] = intc_prio_data(desc, d, enum_id, 0);
primary = 0;
if (!data[0] && data[1])
primary = 1;
- data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
- data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+ data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
+ data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
if (!data[primary])
primary ^= 1;
@@ -375,31 +514,118 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
BUG_ON(!data[primary]); /* must have primary masking method */
disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &desc->chip,
+ set_irq_chip_and_handler_name(irq, &d->chip,
handle_level_irq, "level");
set_irq_chip_data(irq, (void *)data[primary]);
+ /* record the desired priority level */
+ intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1);
+
/* enable secondary masking method if present */
if (data[!primary])
- intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
- data[!primary]);
+ _intc_enable(irq, data[!primary]);
+
+ /* add irq to d->prio list if priority is available */
+ if (data[1]) {
+ hp = d->prio + d->nr_prio;
+ hp->irq = irq;
+ hp->handle = data[1];
+
+ if (primary) {
+ /*
+ * only secondary priority should access registers, so
+ * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+ */
+
+ hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+ hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+ }
+ d->nr_prio++;
+ }
+
+ /* add irq to d->sense list if sense is available */
+ data[0] = intc_sense_data(desc, d, enum_id);
+ if (data[0]) {
+ (d->sense + d->nr_sense)->irq = irq;
+ (d->sense + d->nr_sense)->handle = data[0];
+ d->nr_sense++;
+ }
/* irq should be disabled by default */
- desc->chip.mask(irq);
+ d->chip.mask(irq);
}
+static unsigned int __init save_reg(struct intc_desc_int *d,
+ unsigned int cnt,
+ unsigned long value,
+ unsigned int smp)
+{
+ if (value) {
+ d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+ d->smp[cnt] = smp;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+
void __init register_intc_controller(struct intc_desc *desc)
{
- unsigned int i;
+ unsigned int i, k, smp;
+ struct intc_desc_int *d;
+
+ d = alloc_bootmem(sizeof(*d));
+
+ d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
+ d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
+ d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
+
+ d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
+#ifdef CONFIG_SMP
+ d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
+#endif
+ k = 0;
+
+ if (desc->mask_regs) {
+ for (i = 0; i < desc->nr_mask_regs; i++) {
+ smp = IS_SMP(desc->mask_regs[i]);
+ k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (desc->prio_regs) {
+ d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
+
+ for (i = 0; i < desc->nr_prio_regs; i++) {
+ smp = IS_SMP(desc->prio_regs[i]);
+ k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (desc->sense_regs) {
+ d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
+
+ for (i = 0; i < desc->nr_sense_regs; i++) {
+ k += save_reg(d, k, desc->sense_regs[i].reg, 0);
+ }
+ }
+
+ BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
- desc->chip.mask = intc_disable;
- desc->chip.unmask = intc_enable;
- desc->chip.mask_ack = intc_disable;
- desc->chip.set_type = intc_set_sense;
+ d->chip.name = desc->name;
+ d->chip.mask = intc_disable;
+ d->chip.unmask = intc_enable;
+ d->chip.mask_ack = intc_disable;
+ d->chip.set_type = intc_set_sense;
for (i = 0; i < desc->nr_vectors; i++) {
struct intc_vect *vect = desc->vectors + i;
- intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+ intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
}
}
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
deleted file mode 100644
index cc5221390e0..00000000000
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Interrupt handling for INTC2-based IRQ.
- *
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * These are the "new Hitachi style" interrupts, as present on the
- * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
- */
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <asm/smp.h>
-
-static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
-{
- struct irq_chip *chip = get_irq_chip(irq);
- return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
-}
-
-static void disable_intc2_irq(unsigned int irq)
-{
- struct intc2_data *p = get_irq_chip_data(irq);
- struct intc2_desc *d = get_intc2_desc(irq);
-
- ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset +
- (hard_smp_processor_id() * 4));
-}
-
-static void enable_intc2_irq(unsigned int irq)
-{
- struct intc2_data *p = get_irq_chip_data(irq);
- struct intc2_desc *d = get_intc2_desc(irq);
-
- ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset +
- (hard_smp_processor_id() * 4));
-}
-
-/*
- * Setup an INTC2 style interrupt.
- * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
- * allowing the use of the numbers straight out of the datasheet.
- * For example:
- * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
- * would be: ^ ^ ^ ^
- * | | | |
- * { 84, 0, 16, 0, 13 },
- *
- * in the intc2_data table.
- */
-void register_intc2_controller(struct intc2_desc *desc)
-{
- int i;
-
- desc->chip.mask = disable_intc2_irq;
- desc->chip.unmask = enable_intc2_irq;
- desc->chip.mask_ack = disable_intc2_irq;
-
- for (i = 0; i < desc->nr_irqs; i++) {
- unsigned long ipr, flags;
- struct intc2_data *p = desc->intc2_data + i;
-
- disable_irq_nosync(p->irq);
-
- if (desc->prio_base) {
- /* Set the priority level */
- local_irq_save(flags);
-
- ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
- ipr &= ~(0xf << p->ipr_shift);
- ipr |= p->priority << p->ipr_shift;
- ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
-
- local_irq_restore(flags);
- }
-
- set_irq_chip_and_handler_name(p->irq, &desc->chip,
- handle_level_irq, "level");
- set_irq_chip_data(p->irq, p);
-
- disable_intc2_irq(p->irq);
- }
-}
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
index abbf17427e5..5916d9096b9 100644
--- a/arch/sh/kernel/cpu/sh2/probe.c
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -10,26 +10,25 @@
* for more details.
*/
#include <linux/init.h>
-#include <linux/smp.h>
#include <asm/processor.h>
#include <asm/cache.h>
int __init detect_cpu_and_cache_system(void)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7619)
- current_cpu_data.type = CPU_SH7619;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.dcache.way_incr = (1<<12);
- current_cpu_data.dcache.sets = 256;
- current_cpu_data.dcache.entry_shift = 4;
- current_cpu_data.dcache.linesz = L1_CACHE_BYTES;
- current_cpu_data.dcache.flags = 0;
+ boot_cpu_data.type = CPU_SH7619;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.dcache.way_incr = (1<<12);
+ boot_cpu_data.dcache.sets = 256;
+ boot_cpu_data.dcache.entry_shift = 4;
+ boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.dcache.flags = 0;
#endif
/*
* SH-2 doesn't have separate caches
*/
- current_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
- current_cpu_data.icache = current_cpu_data.dcache;
+ boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+ boot_cpu_data.icache = boot_cpu_data.dcache;
return 0;
}
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index a979b981e6a..ec6adc3f306 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -12,6 +12,61 @@
#include <linux/serial.h>
#include <asm/sci.h>
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ WDT, EDMAC, CMT0, CMT1,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+ HIF_HIFI, HIF_HIFBI,
+ DMAC0, DMAC1, DMAC2, DMAC3,
+ SIOF,
+
+ /* interrupt groups */
+ SCIF0, SCIF1, SCIF2,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+ INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+ INTC_IRQ(IRQ4, 80), INTC_IRQ(IRQ5, 81),
+ INTC_IRQ(IRQ6, 82), INTC_IRQ(IRQ7, 83),
+ INTC_IRQ(WDT, 84), INTC_IRQ(EDMAC, 85),
+ INTC_IRQ(CMT0, 86), INTC_IRQ(CMT1, 87),
+ INTC_IRQ(SCIF0_ERI, 88), INTC_IRQ(SCIF0_RXI, 89),
+ INTC_IRQ(SCIF0_BRI, 90), INTC_IRQ(SCIF0_TXI, 91),
+ INTC_IRQ(SCIF1_ERI, 92), INTC_IRQ(SCIF1_RXI, 93),
+ INTC_IRQ(SCIF1_BRI, 94), INTC_IRQ(SCIF1_TXI, 95),
+ INTC_IRQ(SCIF2_ERI, 96), INTC_IRQ(SCIF2_RXI, 97),
+ INTC_IRQ(SCIF2_BRI, 98), INTC_IRQ(SCIF2_TXI, 99),
+ INTC_IRQ(HIF_HIFI, 100), INTC_IRQ(HIF_HIFBI, 101),
+ INTC_IRQ(DMAC0, 104), INTC_IRQ(DMAC1, 105),
+ INTC_IRQ(DMAC2, 106), INTC_IRQ(DMAC3, 107),
+ INTC_IRQ(SIOF, 108),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xf8140006, 0, 16, 4, /* IPRA */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xf8140008, 0, 16, 4, /* IPRB */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xf8080000, 0, 16, 4, /* IPRC */ { WDT, EDMAC, CMT0, CMT1 } },
+ { 0xf8080002, 0, 16, 4, /* IPRD */ { SCIF0, SCIF1, SCIF2 } },
+ { 0xf8080004, 0, 16, 4, /* IPRE */ { HIF_HIFI, HIF_HIFBI } },
+ { 0xf8080006, 0, 16, 4, /* IPRF */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+ { 0xf8080008, 0, 16, 4, /* IPRG */ { SIOF } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups,
+ NULL, NULL, prio_registers, NULL);
+
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xf8400000,
@@ -52,43 +107,7 @@ static int __init sh7619_devices_setup(void)
}
__initcall(sh7619_devices_setup);
-static struct ipr_data ipr_irq_table[] = {
- { 86, 0, 4, 2 }, /* CMI0 */
- { 88, 1, 12, 3 }, /* SCIF0_ERI */
- { 89, 1, 12, 3 }, /* SCIF0_RXI */
- { 90, 1, 12, 3 }, /* SCIF0_BRI */
- { 91, 1, 12, 3 }, /* SCIF0_TXI */
- { 92, 1, 8, 3 }, /* SCIF1_ERI */
- { 93, 1, 8, 3 }, /* SCIF1_RXI */
- { 94, 1, 8, 3 }, /* SCIF1_BRI */
- { 95, 1, 8, 3 }, /* SCIF1_TXI */
- { 96, 1, 4, 3 }, /* SCIF2_ERI */
- { 97, 1, 4, 3 }, /* SCIF2_RXI */
- { 98, 1, 4, 3 }, /* SCIF2_BRI */
- { 99, 1, 4, 3 }, /* SCIF2_TXI */
-};
-
-static unsigned long ipr_offsets[] = {
- 0xf8080000, /* IPRC */
- 0xf8080002, /* IPRD */
- 0xf8080004, /* IPRE */
- 0xf8080006, /* IPRF */
- 0xf8080008, /* IPRG */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7619",
- },
-};
-
void __init plat_irq_setup(void)
{
- register_ipr_controller(&ipr_irq_desc);
+ register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index f455c350978..6d02465704b 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -17,15 +17,15 @@
int __init detect_cpu_and_cache_system(void)
{
/* Just SH7206 for now .. */
- current_cpu_data.type = CPU_SH7206;
- current_cpu_data.flags |= CPU_HAS_OP32;
+ boot_cpu_data.type = CPU_SH7206;
+ boot_cpu_data.flags |= CPU_HAS_OP32;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.dcache.way_incr = (1 << 11);
- current_cpu_data.dcache.sets = 128;
- current_cpu_data.dcache.entry_shift = 4;
- current_cpu_data.dcache.linesz = L1_CACHE_BYTES;
- current_cpu_data.dcache.flags = 0;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.dcache.way_incr = (1 << 11);
+ boot_cpu_data.dcache.sets = 128;
+ boot_cpu_data.dcache.entry_shift = 4;
+ boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.dcache.flags = 0;
/*
* The icache is the same as the dcache as far as this setup is
@@ -33,7 +33,7 @@ int __init detect_cpu_and_cache_system(void)
* lacks the U bit that the dcache has, none of this has any bearing
* on the cache info.
*/
- current_cpu_data.icache = current_cpu_data.dcache;
+ boot_cpu_data.icache = boot_cpu_data.dcache;
return 0;
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index deab1650016..bd745aa8722 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -12,27 +12,184 @@
#include <linux/serial.h>
#include <asm/sci.h>
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+ ADC_ADI0, ADC_ADI1,
+ DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
+ DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
+ DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
+ DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
+ CMT0, CMT1, BSC, WDT,
+ MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
+ MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
+ MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
+ MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
+ MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
+ MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
+ MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
+ POE2_OEI1, POE2_OEI2,
+ MTU2S_TGI3A, MTU2S_TGI3B, MTU2S_TGI3C, MTU2S_TGI3D, MTU2S_TCI3V,
+ MTU2S_TGI4A, MTU2S_TGI4B, MTU2S_TGI4C, MTU2S_TGI4D, MTU2S_TCI4V,
+ MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W,
+ POE2_OEI3,
+ IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI,
+ SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+ SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+ SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+ SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+
+ /* interrupt groups */
+ PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+ MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S,
+ IIC3, SCIF0, SCIF1, SCIF2, SCIF3,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+ INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+ INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+ INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+ INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+ INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+ INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+ INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+ INTC_IRQ(ADC_ADI0, 92), INTC_IRQ(ADC_ADI1, 96),
+ INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
+ INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
+ INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
+ INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
+ INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
+ INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
+ INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
+ INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
+ INTC_IRQ(CMT0, 140), INTC_IRQ(CMT1, 144),
+ INTC_IRQ(BSC, 148), INTC_IRQ(WDT, 152),
+ INTC_IRQ(MTU2_TGI0A, 156), INTC_IRQ(MTU2_TGI0B, 157),
+ INTC_IRQ(MTU2_TGI0C, 158), INTC_IRQ(MTU2_TGI0D, 159),
+ INTC_IRQ(MTU2_TCI0V, 160),
+ INTC_IRQ(MTU2_TGI0E, 161), INTC_IRQ(MTU2_TGI0F, 162),
+ INTC_IRQ(MTU2_TGI1A, 164), INTC_IRQ(MTU2_TGI1B, 165),
+ INTC_IRQ(MTU2_TCI1V, 168), INTC_IRQ(MTU2_TCI1U, 169),
+ INTC_IRQ(MTU2_TGI2A, 172), INTC_IRQ(MTU2_TGI2B, 173),
+ INTC_IRQ(MTU2_TCI2V, 176), INTC_IRQ(MTU2_TCI2U, 177),
+ INTC_IRQ(MTU2_TGI3A, 180), INTC_IRQ(MTU2_TGI3B, 181),
+ INTC_IRQ(MTU2_TGI3C, 182), INTC_IRQ(MTU2_TGI3D, 183),
+ INTC_IRQ(MTU2_TCI3V, 184),
+ INTC_IRQ(MTU2_TGI4A, 188), INTC_IRQ(MTU2_TGI4B, 189),
+ INTC_IRQ(MTU2_TGI4C, 190), INTC_IRQ(MTU2_TGI4D, 191),
+ INTC_IRQ(MTU2_TCI4V, 192),
+ INTC_IRQ(MTU2_TGI5U, 196), INTC_IRQ(MTU2_TGI5V, 197),
+ INTC_IRQ(MTU2_TGI5W, 198),
+ INTC_IRQ(POE2_OEI1, 200), INTC_IRQ(POE2_OEI2, 201),
+ INTC_IRQ(MTU2S_TGI3A, 204), INTC_IRQ(MTU2S_TGI3B, 205),
+ INTC_IRQ(MTU2S_TGI3C, 206), INTC_IRQ(MTU2S_TGI3D, 207),
+ INTC_IRQ(MTU2S_TCI3V, 208),
+ INTC_IRQ(MTU2S_TGI4A, 212), INTC_IRQ(MTU2S_TGI4B, 213),
+ INTC_IRQ(MTU2S_TGI4C, 214), INTC_IRQ(MTU2S_TGI4D, 215),
+ INTC_IRQ(MTU2S_TCI4V, 216),
+ INTC_IRQ(MTU2S_TGI5U, 220), INTC_IRQ(MTU2S_TGI5V, 221),
+ INTC_IRQ(MTU2S_TGI5W, 222),
+ INTC_IRQ(POE2_OEI3, 224),
+ INTC_IRQ(IIC3_STPI, 228), INTC_IRQ(IIC3_NAKI, 229),
+ INTC_IRQ(IIC3_RXI, 230), INTC_IRQ(IIC3_TXI, 231),
+ INTC_IRQ(IIC3_TEI, 232),
+ INTC_IRQ(SCIF0_BRI, 240), INTC_IRQ(SCIF0_ERI, 241),
+ INTC_IRQ(SCIF0_RXI, 242), INTC_IRQ(SCIF0_TXI, 243),
+ INTC_IRQ(SCIF1_BRI, 244), INTC_IRQ(SCIF1_ERI, 245),
+ INTC_IRQ(SCIF1_RXI, 246), INTC_IRQ(SCIF1_TXI, 247),
+ INTC_IRQ(SCIF2_BRI, 248), INTC_IRQ(SCIF2_ERI, 249),
+ INTC_IRQ(SCIF2_RXI, 250), INTC_IRQ(SCIF2_TXI, 251),
+ INTC_IRQ(SCIF3_BRI, 252), INTC_IRQ(SCIF3_ERI, 253),
+ INTC_IRQ(SCIF3_RXI, 254), INTC_IRQ(SCIF3_TXI, 255),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+ PINT4, PINT5, PINT6, PINT7),
+ INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
+ INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
+ INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
+ INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
+ INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
+ INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
+ INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
+ INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
+ INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
+ INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
+ INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
+ INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
+ INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
+ INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
+ INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
+ INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
+ INTC_GROUP(MTU5, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
+ INTC_GROUP(POE2_12, POE2_OEI1, POE2_OEI2),
+ INTC_GROUP(MTU3S_ABCD, MTU2S_TGI3A, MTU2S_TGI3B,
+ MTU2S_TGI3C, MTU2S_TGI3D),
+ INTC_GROUP(MTU4S_ABCD, MTU2S_TGI4A, MTU2S_TGI4B,
+ MTU2S_TGI4C, MTU2S_TGI4D),
+ INTC_GROUP(MTU5S, MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W),
+ INTC_GROUP(IIC3, IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI),
+ INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+ INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI0, ADC_ADI1 } },
+ { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+ { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
+ { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { CMT0, CMT1, BSC, WDT } },
+ { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { MTU0_ABCD, MTU0_VEF,
+ MTU1_AB, MTU1_VU } },
+ { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU2_TCI3V } },
+ { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU4_ABCD, MTU2_TCI4V,
+ MTU5, POE2_12 } },
+ { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU3S_ABCD, MTU2S_TCI3V,
+ MTU4S_ABCD, MTU2S_TCI4V } },
+ { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU5S, POE2_OEI3, IIC3, 0 } },
+ { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfffe0808, 0, 16, /* PINTER */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups,
+ NULL, mask_registers, prio_registers, NULL);
+
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xfffe8000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 241, 242, 243, 240},
+ .irqs = { 241, 242, 243, 240 },
}, {
.mapbase = 0xfffe8800,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 247, 244, 245, 246},
+ .irqs = { 245, 246, 247, 244 },
}, {
.mapbase = 0xfffe9000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 249, 250, 251, 248},
+ .irqs = { 249, 250, 251, 248 },
}, {
.mapbase = 0xfffe9800,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 253, 254, 255, 252},
+ .irqs = { 253, 254, 255, 252 },
}, {
.flags = 0,
}
@@ -57,57 +214,7 @@ static int __init sh7206_devices_setup(void)
}
__initcall(sh7206_devices_setup);
-static struct ipr_data ipr_irq_table[] = {
- { 140, 7, 12, 2 }, /* CMI0 */
- { 164, 8, 4, 2 }, /* MTU2_TGI1A */
- { 240, 13, 12, 3 }, /* SCIF0_BRI */
- { 241, 13, 12, 3 }, /* SCIF0_ERI */
- { 242, 13, 12, 3 }, /* SCIF0_RXI */
- { 243, 13, 12, 3 }, /* SCIF0_TXI */
- { 244, 13, 8, 3 }, /* SCIF1_BRI */
- { 245, 13, 8, 3 }, /* SCIF1_ERI */
- { 246, 13, 8, 3 }, /* SCIF1_RXI */
- { 247, 13, 8, 3 }, /* SCIF1_TXI */
- { 248, 13, 4, 3 }, /* SCIF2_BRI */
- { 249, 13, 4, 3 }, /* SCIF2_ERI */
- { 250, 13, 4, 3 }, /* SCIF2_RXI */
- { 251, 13, 4, 3 }, /* SCIF2_TXI */
- { 252, 13, 0, 3 }, /* SCIF3_BRI */
- { 253, 13, 0, 3 }, /* SCIF3_ERI */
- { 254, 13, 0, 3 }, /* SCIF3_RXI */
- { 255, 13, 0, 3 }, /* SCIF3_TXI */
-};
-
-static unsigned long ipr_offsets[] = {
- 0xfffe0818, /* IPR01 */
- 0xfffe081a, /* IPR02 */
- 0, /* unused */
- 0, /* unused */
- 0xfffe0820, /* IPR05 */
- 0xfffe0c00, /* IPR06 */
- 0xfffe0c02, /* IPR07 */
- 0xfffe0c04, /* IPR08 */
- 0xfffe0c06, /* IPR09 */
- 0xfffe0c08, /* IPR10 */
- 0xfffe0c0a, /* IPR11 */
- 0xfffe0c0c, /* IPR12 */
- 0xfffe0c0e, /* IPR13 */
- 0xfffe0c10, /* IPR14 */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7206",
- },
-};
-
void __init plat_irq_setup(void)
{
- register_ipr_controller(&ipr_irq_desc);
+ register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 55b750763f6..646eb693361 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -6,12 +6,13 @@ obj-y := ex.o probe.o entry.o
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7720) += setup-sh7720.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
@@ -19,5 +20,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7710.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7720) := clock-sh7710.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 647623b22ed..bf579e061e0 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -50,44 +50,47 @@ int __init detect_cpu_and_cache_system(void)
back_to_P1();
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.dcache.entry_shift = 4;
- current_cpu_data.dcache.linesz = L1_CACHE_BYTES;
- current_cpu_data.dcache.flags = 0;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.dcache.entry_shift = 4;
+ boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.dcache.flags = 0;
/*
* 7709A/7729 has 16K cache (256-entry), while 7702 has only
* 2K(direct) 7702 is not supported (yet)
*/
if (data0 == data1 && data2 == data3) { /* Shadow */
- current_cpu_data.dcache.way_incr = (1 << 11);
- current_cpu_data.dcache.entry_mask = 0x7f0;
- current_cpu_data.dcache.sets = 128;
- current_cpu_data.type = CPU_SH7708;
+ boot_cpu_data.dcache.way_incr = (1 << 11);
+ boot_cpu_data.dcache.entry_mask = 0x7f0;
+ boot_cpu_data.dcache.sets = 128;
+ boot_cpu_data.type = CPU_SH7708;
- current_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC;
+ boot_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC;
} else { /* 7709A or 7729 */
- current_cpu_data.dcache.way_incr = (1 << 12);
- current_cpu_data.dcache.entry_mask = 0xff0;
- current_cpu_data.dcache.sets = 256;
- current_cpu_data.type = CPU_SH7729;
+ boot_cpu_data.dcache.way_incr = (1 << 12);
+ boot_cpu_data.dcache.entry_mask = 0xff0;
+ boot_cpu_data.dcache.sets = 256;
+ boot_cpu_data.type = CPU_SH7729;
#if defined(CONFIG_CPU_SUBTYPE_SH7706)
- current_cpu_data.type = CPU_SH7706;
+ boot_cpu_data.type = CPU_SH7706;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7710)
- current_cpu_data.type = CPU_SH7710;
+ boot_cpu_data.type = CPU_SH7710;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7712)
- current_cpu_data.type = CPU_SH7712;
+ boot_cpu_data.type = CPU_SH7712;
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+ boot_cpu_data.type = CPU_SH7720;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
- current_cpu_data.type = CPU_SH7705;
+ boot_cpu_data.type = CPU_SH7705;
#if defined(CONFIG_SH7705_CACHE_32KB)
- current_cpu_data.dcache.way_incr = (1 << 13);
- current_cpu_data.dcache.entry_mask = 0x1ff0;
- current_cpu_data.dcache.sets = 512;
+ boot_cpu_data.dcache.way_incr = (1 << 13);
+ boot_cpu_data.dcache.entry_mask = 0x1ff0;
+ boot_cpu_data.dcache.sets = 512;
ctrl_outl(CCR_CACHE_32KB, CCR3);
#else
ctrl_outl(CCR_CACHE_16KB, CCR3);
@@ -98,9 +101,8 @@ int __init detect_cpu_and_cache_system(void)
/*
* SH-3 doesn't have separate caches
*/
- current_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
- current_cpu_data.icache = current_cpu_data.dcache;
+ boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+ boot_cpu_data.icache = boot_cpu_data.dcache;
return 0;
}
-
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index ebd9d06d8bd..f6c65f2659e 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -1,7 +1,7 @@
/*
* SH7705 Setup
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006, 2007 Paul Mundt
* Copyright (C) 2007 Nobuhiro Iwamatsu
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -10,8 +10,90 @@
*/
#include <linux/platform_device.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/serial.h>
#include <asm/sci.h>
+#include <asm/rtc.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+ PINT07, PINT815,
+ DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+ ADC_ADI,
+ USB_USI0, USB_USI1,
+ TPU0, TPU1, TPU2, TPU3,
+ TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT,
+ REF_RCMI,
+
+ /* interrupt groups */
+ RTC, TMU2, DMAC, USB, SCIF2, SCIF0,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+ INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
+ INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+ INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+ INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+ INTC_VECT(SCIF0_TXI, 0x8e0),
+ INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
+ INTC_VECT(SCIF2_TXI, 0x960),
+ INTC_VECT(ADC_ADI, 0x980),
+ INTC_VECT(USB_USI0, 0xa20), INTC_VECT(USB_USI1, 0xa40),
+ INTC_VECT(TPU0, 0xc00), INTC_VECT(TPU1, 0xc20),
+ INTC_VECT(TPU3, 0xc80), INTC_VECT(TPU1, 0xca0),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(REF_RCMI, 0x580),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+ INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+ INTC_GROUP(USB, USB_USI0, USB_USI1),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(DMAC, 7),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(SCIF0, 3),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
+ { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+ { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, IRQ5, IRQ4 } },
+ { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, SCIF0, SCIF2, ADC_ADI } },
+ { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, 0, USB } },
+ { 0xa4080002, 0, 16, 4, /* IPRG */ { TPU0, TPU1 } },
+ { 0xa4080004, 0, 16, 4, /* IPRH */ { TPU2, TPU3 } },
+
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups,
+ priorities, NULL, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+ INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7705-irq", vectors_irq, NULL,
+ priorities, NULL, prio_registers, NULL);
static struct plat_sci_port sci_platform_data[] = {
{
@@ -37,8 +119,43 @@ static struct platform_device sci_device = {
},
};
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xfffffec0,
+ .end = 0xfffffec0 + 0x1e,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+ .capabilities = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+ .dev = {
+ .platform_data = &rtc_info,
+ },
+};
+
static struct platform_device *sh7705_devices[] __initdata = {
&sci_device,
+ &rtc_device,
};
static int __init sh7705_devices_setup(void)
@@ -48,51 +165,16 @@ static int __init sh7705_devices_setup(void)
}
__initcall(sh7705_devices_setup);
-static struct ipr_data ipr_irq_table[] = {
- /* IRQ, IPR-idx, shift, priority */
- { 16, 0, 12, 2 }, /* TMU0 TUNI*/
- { 17, 0, 8, 2 }, /* TMU1 TUNI */
- { 18, 0, 4, 2 }, /* TMU2 TUNI */
- { 27, 1, 12, 2 }, /* WDT ITI */
- { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
- { 21, 0, 0, 2 }, /* RTC PRI (period) */
- { 22, 0, 0, 2 }, /* RTC CUI (carry) */
- { 48, 4, 12, 7 }, /* DMAC DMTE0 */
- { 49, 4, 12, 7 }, /* DMAC DMTE1 */
- { 50, 4, 12, 7 }, /* DMAC DMTE2 */
- { 51, 4, 12, 7 }, /* DMAC DMTE3 */
- { 52, 4, 8, 3 }, /* SCIF0 ERI */
- { 53, 4, 8, 3 }, /* SCIF0 RXI */
- { 55, 4, 8, 3 }, /* SCIF0 TXI */
- { 56, 4, 4, 3 }, /* SCIF1 ERI */
- { 57, 4, 4, 3 }, /* SCIF1 RXI */
- { 59, 4, 4, 3 }, /* SCIF1 TXI */
-};
-
-static unsigned long ipr_offsets[] = {
- 0xFFFFFEE2, /* 0: IPRA */
- 0xFFFFFEE4, /* 1: IPRB */
- 0xA4000016, /* 2: IPRC */
- 0xA4000018, /* 3: IPRD */
- 0xA400001A, /* 4: IPRE */
- 0xA4080000, /* 5: IPRF */
- 0xA4080002, /* 6: IPRG */
- 0xA4080004, /* 7: IPRH */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7705",
- },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+ if (mode == IRQ_MODE_IRQ) {
+ register_intc_controller(&intc_desc_irq);
+ return;
+ }
+ BUG();
+}
void __init plat_irq_setup(void)
{
- register_ipr_controller(&ipr_irq_desc);
+ register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
deleted file mode 100644
index f933723911c..00000000000
--- a/arch/sh/kernel/cpu/sh3/setup-sh7708.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SH7708 Setup
- *
- * Copyright (C) 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/sci.h>
-
-static struct plat_sci_port sci_platform_data[] = {
- {
- .mapbase = 0xfffffe80,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCI,
- .irqs = { 23, 24, 25, 0 },
- }, {
- .flags = 0,
- }
-};
-
-static struct platform_device sci_device = {
- .name = "sh-sci",
- .id = -1,
- .dev = {
- .platform_data = sci_platform_data,
- },
-};
-
-static struct platform_device *sh7708_devices[] __initdata = {
- &sci_device,
-};
-
-static int __init sh7708_devices_setup(void)
-{
- return platform_add_devices(sh7708_devices,
- ARRAY_SIZE(sh7708_devices));
-}
-__initcall(sh7708_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
deleted file mode 100644
index 086f8e2545a..00000000000
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SH7707/SH7709 Setup
- *
- * Copyright (C) 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/sci.h>
-
-static struct resource rtc_resources[] = {
- [0] = {
- .start = 0xfffffec0,
- .end = 0xfffffec0 + 0x1e,
- .flags = IORESOURCE_IO,
- },
- [1] = {
- .start = 20,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = 21,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = 22,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct plat_sci_port sci_platform_data[] = {
- {
- .mapbase = 0xfffffe80,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCI,
- .irqs = { 23, 24, 25, 0 },
- }, {
- .mapbase = 0xa4000150,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 56, 57, 59, 58 },
- }, {
- .mapbase = 0xa4000140,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_IRDA,
- .irqs = { 52, 53, 55, 54 },
- }, {
- .flags = 0,
- }
-};
-
-static struct platform_device sci_device = {
- .name = "sh-sci",
- .id = -1,
- .dev = {
- .platform_data = sci_platform_data,
- },
-};
-
-static struct platform_device rtc_device = {
- .name = "sh-rtc",
- .id = -1,
- .num_resources = ARRAY_SIZE(rtc_resources),
- .resource = rtc_resources,
-};
-
-static struct platform_device *sh7709_devices[] __initdata = {
- &sci_device,
- &rtc_device,
-};
-
-static int __init sh7709_devices_setup(void)
-{
- return platform_add_devices(sh7709_devices,
- ARRAY_SIZE(sh7709_devices));
-}
-__initcall(sh7709_devices_setup);
-
-static struct ipr_data ipr_irq_table[] = {
- { 16, 0, 12, 2 }, /* TMU TUNI0 */
- { 17, 0, 8, 4 }, /* TMU TUNI1 */
- { 18, 0, 4, 1 }, /* TMU TUNI1 */
- { 19, 0, 4, 1 }, /* TMU TUNI1 */
- { 20, 0, 0, 2 }, /* RTC CUI */
- { 21, 0, 0, 2 }, /* RTC CUI */
- { 22, 0, 0, 2 }, /* RTC CUI */
-
- { 23, 1, 4, 3 }, /* SCI */
- { 24, 1, 4, 3 }, /* SCI */
- { 25, 1, 4, 3 }, /* SCI */
- { 26, 1, 4, 3 }, /* SCI */
- { 27, 1, 12, 3 }, /* WDT ITI */
-
- { 32, 2, 0, 1 }, /* IRQ 0 */
- { 33, 2, 4, 1 }, /* IRQ 1 */
- { 34, 2, 8, 1 }, /* IRQ 2 APM */
- { 35, 2, 12, 1 }, /* IRQ 3 TOUCHSCREEN */
-
- { 36, 3, 0, 1 }, /* IRQ 4 */
- { 37, 3, 4, 1 }, /* IRQ 5 */
-
- { 48, 4, 12, 7 }, /* DMA */
- { 49, 4, 12, 7 }, /* DMA */
- { 50, 4, 12, 7 }, /* DMA */
- { 51, 4, 12, 7 }, /* DMA */
-
- { 52, 4, 8, 3 }, /* IRDA */
- { 53, 4, 8, 3 }, /* IRDA */
- { 54, 4, 8, 3 }, /* IRDA */
- { 55, 4, 8, 3 }, /* IRDA */
-
- { 56, 4, 4, 3 }, /* SCIF */
- { 57, 4, 4, 3 }, /* SCIF */
- { 58, 4, 4, 3 }, /* SCIF */
- { 59, 4, 4, 3 }, /* SCIF */
-};
-
-static unsigned long ipr_offsets[] = {
- 0xfffffee2, /* 0: IPRA */
- 0xfffffee4, /* 1: IPRB */
- 0xa4000016, /* 2: IPRC */
- 0xa4000018, /* 3: IPRD */
- 0xa400001a, /* 4: IPRE */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7709",
- },
-};
-
-void __init plat_irq_setup(void)
-{
- register_ipr_controller(&ipr_irq_desc);
-}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
new file mode 100644
index 00000000000..60b04b1f945
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -0,0 +1,224 @@
+/*
+ * SH3 Setup code for SH7706, SH7707, SH7708, SH7709
+ *
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * Based on setup-sh7709.c
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+ PINT07, PINT815,
+ DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+ SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI,
+ ADC_ADI,
+ LCDC, PCC0, PCC1,
+ TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT,
+ REF_RCMI, REF_ROVI,
+
+ /* interrupt groups */
+ RTC, REF, TMU2, DMAC, SCI, SCIF2, SCIF0,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(SCI_ERI, 0x4e0), INTC_VECT(SCI_RXI, 0x500),
+ INTC_VECT(SCI_TXI, 0x520), INTC_VECT(SCI_TEI, 0x540),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(REF_RCMI, 0x580),
+ INTC_VECT(REF_ROVI, 0x5a0),
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+ INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+ INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+ INTC_VECT(ADC_ADI, 0x980),
+ INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
+ INTC_VECT(SCIF2_BRI, 0x940), INTC_VECT(SCIF2_TXI, 0x960),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
+ INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+ INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+ INTC_VECT(LCDC, 0x9a0),
+ INTC_VECT(PCC0, 0x9c0), INTC_VECT(PCC1, 0x9e0),
+#endif
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+ INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+ INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+ INTC_GROUP(SCI, SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(DMAC, 7),
+ INTC_PRIO(SCI, 3),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(SCIF0, 3),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+ { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
+ { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, 0, SCIF2, ADC_ADI } },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, } },
+ { 0xa400001a, 0, 16, 4, /* IPRE */ { 0, SCIF0 } },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+ { 0xa400001c, 0, 16, 4, /* IPRF */ { 0, LCDC, PCC0, PCC1, } },
+#endif
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups,
+ priorities, NULL, prio_registers, NULL);
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+ INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL,
+ priorities, NULL, prio_registers, NULL);
+#endif
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xfffffec0,
+ .end = 0xfffffec0 + 0x1e,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfffffe80,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 23, 24, 25, 0 },
+ },
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ {
+ .mapbase = 0xa4000150,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 56, 57, 59, 58 },
+ },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ {
+ .mapbase = 0xa4000140,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_IRDA,
+ .irqs = { 52, 53, 55, 54 },
+ },
+#endif
+ {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh770x_devices[] __initdata = {
+ &sci_device,
+ &rtc_device,
+};
+
+static int __init sh770x_devices_setup(void)
+{
+ return platform_add_devices(sh770x_devices,
+ ARRAY_SIZE(sh770x_devices));
+}
+__initcall(sh770x_devices_setup);
+
+#define INTC_ICR1 0xa4000010UL
+#define INTC_ICR1_IRQLVL (1<<14)
+
+void __init plat_irq_setup_pins(int mode)
+{
+ if (mode == IRQ_MODE_IRQ) {
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ ctrl_outw(ctrl_inw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1);
+ register_intc_controller(&intc_desc_irq);
+ return;
+#endif
+ }
+ BUG();
+}
+
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 13228489337..84e5629fa84 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -1,7 +1,7 @@
/*
- * SH7710 Setup
+ * SH3 Setup code for SH7710, SH7712
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006, 2007 Paul Mundt
* Copyright (C) 2007 Nobuhiro Iwamatsu
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -10,8 +10,140 @@
*/
#include <linux/platform_device.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/serial.h>
#include <asm/sci.h>
+#include <asm/rtc.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+ DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ DMAC_DEI4, DMAC_DEI5,
+ IPSEC,
+ EDMAC0, EDMAC1, EDMAC2,
+ SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI,
+ SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI,
+ TMU0, TMU1, TMU2,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT,
+ REF,
+
+ /* interrupt groups */
+ RTC, DMAC1, SCIF0, SCIF1, DMAC2, SIOF0, SIOF1,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+ INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+ INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+ INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+ INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+ INTC_VECT(SCIF1_ERI, 0x900), INTC_VECT(SCIF1_RXI, 0x920),
+ INTC_VECT(SCIF1_BRI, 0x940), INTC_VECT(SCIF1_TXI, 0x960),
+ INTC_VECT(DMAC_DEI4, 0xb80), INTC_VECT(DMAC_DEI5, 0xba0),
+#ifdef CONFIG_CPU_SUBTYPE_SH7710
+ INTC_VECT(IPSEC, 0xbe0),
+#endif
+ INTC_VECT(EDMAC0, 0xc00), INTC_VECT(EDMAC1, 0xc20),
+ INTC_VECT(EDMAC2, 0xc40),
+ INTC_VECT(SIOF0_ERI, 0xe00), INTC_VECT(SIOF0_TXI, 0xe20),
+ INTC_VECT(SIOF0_RXI, 0xe40), INTC_VECT(SIOF0_CCI, 0xe60),
+ INTC_VECT(SIOF1_ERI, 0xe80), INTC_VECT(SIOF1_TXI, 0xea0),
+ INTC_VECT(SIOF1_RXI, 0xec0), INTC_VECT(SIOF1_CCI, 0xee0),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2, 0x440),
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(REF, 0x580),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(DMAC1, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(DMAC2, DMAC_DEI4, DMAC_DEI5),
+ INTC_GROUP(SIOF0, SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI),
+ INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(DMAC1, 7),
+ INTC_PRIO(DMAC2, 7),
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SIOF0, 3),
+ INTC_PRIO(SIOF1, 3),
+ INTC_PRIO(EDMAC0, 5),
+ INTC_PRIO(EDMAC1, 5),
+ INTC_PRIO(EDMAC2, 5),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
+ { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+ { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
+ { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC1, SCIF0, SCIF1 } },
+ { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, DMAC2 } },
+#ifdef CONFIG_CPU_SUBTYPE_SH7710
+ { 0xa4080000, 0, 16, 4, /* IPRF */ { IPSEC } },
+#endif
+ { 0xa4080002, 0, 16, 4, /* IPRG */ { EDMAC0, EDMAC1, EDMAC2 } },
+ { 0xa4080004, 0, 16, 4, /* IPRH */ { 0, 0, 0, SIOF0 } },
+ { 0xa4080006, 0, 16, 4, /* IPRI */ { 0, 0, SIOF1 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups,
+ priorities, NULL, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+ INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7710-irq", vectors_irq, NULL,
+ priorities, NULL, prio_registers, NULL);
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xa413fec0,
+ .end = 0xa413fec0 + 0x1e,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+ .capabilities = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+ .dev = {
+ .platform_data = &rtc_info,
+ },
+};
static struct plat_sci_port sci_platform_data[] = {
{
@@ -20,7 +152,7 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 52, 53, 55, 54 },
}, {
- .mapbase = 0xa4420000,
+ .mapbase = 0xa4410000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
.irqs = { 56, 57, 59, 58 },
@@ -40,6 +172,7 @@ static struct platform_device sci_device = {
static struct platform_device *sh7710_devices[] __initdata = {
&sci_device,
+ &rtc_device,
};
static int __init sh7710_devices_setup(void)
@@ -49,59 +182,16 @@ static int __init sh7710_devices_setup(void)
}
__initcall(sh7710_devices_setup);
-static struct ipr_data ipr_irq_table[] = {
- /* IRQ, IPR-idx, shift, priority */
- { 16, 0, 12, 2 }, /* TMU0 TUNI*/
- { 17, 0, 8, 2 }, /* TMU1 TUNI */
- { 18, 0, 4, 2 }, /* TMU2 TUNI */
- { 27, 1, 12, 2 }, /* WDT ITI */
- { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
- { 21, 0, 0, 2 }, /* RTC PRI (period) */
- { 22, 0, 0, 2 }, /* RTC CUI (carry) */
- { 48, 4, 12, 7 }, /* DMAC DMTE0 */
- { 49, 4, 12, 7 }, /* DMAC DMTE1 */
- { 50, 4, 12, 7 }, /* DMAC DMTE2 */
- { 51, 4, 12, 7 }, /* DMAC DMTE3 */
- { 52, 4, 8, 3 }, /* SCIF0 ERI */
- { 53, 4, 8, 3 }, /* SCIF0 RXI */
- { 54, 4, 8, 3 }, /* SCIF0 BRI */
- { 55, 4, 8, 3 }, /* SCIF0 TXI */
- { 56, 4, 4, 3 }, /* SCIF1 ERI */
- { 57, 4, 4, 3 }, /* SCIF1 RXI */
- { 58, 4, 4, 3 }, /* SCIF1 BRI */
- { 59, 4, 4, 3 }, /* SCIF1 TXI */
- { 76, 5, 8, 7 }, /* DMAC DMTE4 */
- { 77, 5, 8, 7 }, /* DMAC DMTE5 */
- { 80, 6, 12, 5 }, /* EDMAC EINT0 */
- { 81, 6, 8, 5 }, /* EDMAC EINT1 */
- { 82, 6, 4, 5 }, /* EDMAC EINT2 */
-};
-
-static unsigned long ipr_offsets[] = {
- 0xA414FEE2, /* 0: IPRA */
- 0xA414FEE4, /* 1: IPRB */
- 0xA4140016, /* 2: IPRC */
- 0xA4140018, /* 3: IPRD */
- 0xA414001A, /* 4: IPRE */
- 0xA4080000, /* 5: IPRF */
- 0xA4080002, /* 6: IPRG */
- 0xA4080004, /* 7: IPRH */
- 0xA4080006, /* 8: IPRI */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7710",
- },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+ if (mode == IRQ_MODE_IRQ) {
+ register_intc_controller(&intc_desc_irq);
+ return;
+ }
+ BUG();
+}
void __init plat_irq_setup(void)
{
- register_ipr_controller(&ipr_irq_desc);
+ register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
new file mode 100644
index 00000000000..a0929b8a95a
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -0,0 +1,210 @@
+/*
+ * SH7720 Setup
+ *
+ * Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ * Based on arch/sh/kernel/cpu/sh4/setup-sh7750.c:
+ *
+ * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006 Jamie Lenehan
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <asm/sci.h>
+#include <asm/rtc.h>
+
+#define INTC_ICR1 0xA4140010UL
+#define INTC_ICR_IRLM 0x4000
+#define INTC_ICR_IRQ (~INTC_ICR_IRLM)
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xa413fec0,
+ .end = 0xa413fec0 + 0x28 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+ .capabilities = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+ .dev = {
+ .platform_data = &rtc_info,
+ },
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xa4430000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 80, 80, 80, 80 },
+ }, {
+ .mapbase = 0xa4438000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 81, 81, 81, 81 },
+ }, {
+
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7720_devices[] __initdata = {
+ &rtc_device,
+ &sci_device,
+};
+
+static int __init sh7720_devices_setup(void)
+{
+ return platform_add_devices(sh7720_devices,
+ ARRAY_SIZE(sh7720_devices));
+}
+__initcall(sh7720_devices_setup);
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ TMU0, TMU1, TMU2, RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT, REF_RCMI, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
+ IRQ0, IRQ1, IRQ2, IRQ3,
+ USBF_SPD, TMU_SUNI, IRQ5, IRQ4,
+ DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3, LCDC, SSL,
+ ADC, DMAC2_DEI4, DMAC2_DEI5, USBFI0, USBFI1, CMT,
+ SCIF0, SCIF1,
+ PINT07, PINT815, TPU0, TPU1, TPU2, TPU3, IIC,
+ SIOF0, SIOF1, MMCI0, MMCI1, MMCI2, MMCI3, PCC,
+ USBHI, AFEIF,
+ H_UDI,
+ /* interrupt groups */
+ TMU, RTC, SIM, DMAC1, USBFI, DMAC2, USB, TPU, MMC,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2, 0x440), INTC_VECT(RTC_ATI, 0x480),
+ INTC_VECT(RTC_PRI, 0x4a0), INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(SIM_ERI, 0x4e0), INTC_VECT(SIM_RXI, 0x500),
+ INTC_VECT(SIM_TXI, 0x520), INTC_VECT(SIM_TEND, 0x540),
+ INTC_VECT(WDT, 0x560), INTC_VECT(REF_RCMI, 0x580),
+ /* H_UDI cannot be masked */ INTC_VECT(TMU_SUNI, 0x6c0),
+ INTC_VECT(USBF_SPD, 0x6e0), INTC_VECT(DMAC1_DEI0, 0x800),
+ INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840),
+ INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900),
+ INTC_VECT(SSL, 0x980), INTC_VECT(USBFI0, 0xa20),
+ INTC_VECT(USBFI1, 0xa40), INTC_VECT(USBHI, 0xa60),
+ INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0),
+ INTC_VECT(ADC, 0xbe0), INTC_VECT(SCIF0, 0xc00),
+ INTC_VECT(SCIF1, 0xc20), INTC_VECT(PINT07, 0xc80),
+ INTC_VECT(PINT815, 0xca0), INTC_VECT(SIOF0, 0xd00),
+ INTC_VECT(SIOF1, 0xd20), INTC_VECT(TPU0, 0xd80),
+ INTC_VECT(TPU1, 0xda0), INTC_VECT(TPU2, 0xdc0),
+ INTC_VECT(TPU3, 0xde0), INTC_VECT(IIC, 0xe00),
+ INTC_VECT(MMCI0, 0xe80), INTC_VECT(MMCI1, 0xea0),
+ INTC_VECT(MMCI2, 0xec0), INTC_VECT(MMCI3, 0xee0),
+ INTC_VECT(CMT, 0xf00), INTC_VECT(PCC, 0xf60),
+ INTC_VECT(AFEIF, 0xfe0),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(TMU, TMU0, TMU1, TMU2),
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
+ INTC_GROUP(DMAC1, DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3),
+ INTC_GROUP(USBFI, USBFI0, USBFI1),
+ INTC_GROUP(DMAC2, DMAC2_DEI4, DMAC2_DEI5),
+ INTC_GROUP(TPU, TPU0, TPU1, TPU2, TPU3),
+ INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(SCIF0, 2),
+ INTC_PRIO(SCIF1, 2),
+ INTC_PRIO(DMAC1, 1),
+ INTC_PRIO(DMAC2, 1),
+ INTC_PRIO(RTC, 2),
+ INTC_PRIO(TMU, 2),
+ INTC_PRIO(TPU, 2),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
+ { 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+ { 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } },
+ { 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } },
+ { 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } },
+ { 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } },
+ { 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } },
+ { 0xA4080006UL, 0, 16, 4, /* IPRI */ { SIOF0, SIOF1, MMC, PCC } },
+ { 0xA4080008UL, 0, 16, 4, /* IPRJ */ { 0, USBHI, 0, AFEIF } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups,
+ priorities, NULL, prio_registers, NULL);
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+ { INTC_ICR1, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
+};
+
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+ INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+ INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7720-irq", vectors_irq,
+ NULL, priorities, NULL, prio_registers, sense_registers);
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ:
+ ctrl_outw(ctrl_inw(INTC_ICR1) & INTC_ICR_IRQ, INTC_ICR1);
+ register_intc_controller(&intc_irq_desc);
+ break;
+ default:
+ BUG();
+ }
+}
+
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+}
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 98d28fb1ce1..21375d777e9 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -3,7 +3,7 @@
*
* CPU Subtype Probing for SH-4.
*
- * Copyright (C) 2001 - 2006 Paul Mundt
+ * Copyright (C) 2001 - 2007 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -12,7 +12,6 @@
*/
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/smp.h>
#include <asm/processor.h>
#include <asm/cache.h>
@@ -36,37 +35,34 @@ int __init detect_cpu_and_cache_system(void)
/*
* Setup some sane SH-4 defaults for the icache
*/
- current_cpu_data.icache.way_incr = (1 << 13);
- current_cpu_data.icache.entry_shift = 5;
- current_cpu_data.icache.sets = 256;
- current_cpu_data.icache.ways = 1;
- current_cpu_data.icache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.icache.way_incr = (1 << 13);
+ boot_cpu_data.icache.entry_shift = 5;
+ boot_cpu_data.icache.sets = 256;
+ boot_cpu_data.icache.ways = 1;
+ boot_cpu_data.icache.linesz = L1_CACHE_BYTES;
/*
* And again for the dcache ..
*/
- current_cpu_data.dcache.way_incr = (1 << 14);
- current_cpu_data.dcache.entry_shift = 5;
- current_cpu_data.dcache.sets = 512;
- current_cpu_data.dcache.ways = 1;
- current_cpu_data.dcache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.dcache.way_incr = (1 << 14);
+ boot_cpu_data.dcache.entry_shift = 5;
+ boot_cpu_data.dcache.sets = 512;
+ boot_cpu_data.dcache.ways = 1;
+ boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
/*
- * Setup some generic flags we can probe
- * (L2 and DSP detection only work on SH-4A)
+ * Setup some generic flags we can probe on SH-4A parts
*/
if (((pvr >> 16) & 0xff) == 0x10) {
- if ((cvr & 0x02000000) == 0)
- current_cpu_data.flags |= CPU_HAS_L2_CACHE;
if ((cvr & 0x10000000) == 0)
- current_cpu_data.flags |= CPU_HAS_DSP;
+ boot_cpu_data.flags |= CPU_HAS_DSP;
- current_cpu_data.flags |= CPU_HAS_LLSC;
+ boot_cpu_data.flags |= CPU_HAS_LLSC;
}
/* FPU detection works for everyone */
if ((cvr & 0x20000000) == 1)
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
/* Mask off the upper chip ID */
pvr &= 0xffff;
@@ -77,140 +73,140 @@ int __init detect_cpu_and_cache_system(void)
*/
switch (pvr) {
case 0x205:
- current_cpu_data.type = CPU_SH7750;
- current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ boot_cpu_data.type = CPU_SH7750;
+ boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
CPU_HAS_PERF_COUNTER;
break;
case 0x206:
- current_cpu_data.type = CPU_SH7750S;
- current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ boot_cpu_data.type = CPU_SH7750S;
+ boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
CPU_HAS_PERF_COUNTER;
break;
case 0x1100:
- current_cpu_data.type = CPU_SH7751;
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.type = CPU_SH7751;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
break;
case 0x2001:
case 0x2004:
- current_cpu_data.type = CPU_SH7770;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
+ boot_cpu_data.type = CPU_SH7770;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
+ boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
break;
case 0x2006:
case 0x200A:
if (prr == 0x61)
- current_cpu_data.type = CPU_SH7781;
+ boot_cpu_data.type = CPU_SH7781;
else
- current_cpu_data.type = CPU_SH7780;
+ boot_cpu_data.type = CPU_SH7780;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
CPU_HAS_LLSC;
break;
case 0x3000:
case 0x3003:
case 0x3009:
- current_cpu_data.type = CPU_SH7343;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_LLSC;
+ boot_cpu_data.type = CPU_SH7343;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.flags |= CPU_HAS_LLSC;
break;
case 0x3004:
case 0x3007:
- current_cpu_data.type = CPU_SH7785;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ boot_cpu_data.type = CPU_SH7785;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
CPU_HAS_LLSC;
break;
case 0x3008:
if (prr == 0xa0) {
- current_cpu_data.type = CPU_SH7722;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_LLSC;
+ boot_cpu_data.type = CPU_SH7722;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.flags |= CPU_HAS_LLSC;
}
break;
case 0x4000: /* 1st cut */
case 0x4001: /* 2nd cut */
- current_cpu_data.type = CPU_SHX3;
- current_cpu_data.icache.ways = 4;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ boot_cpu_data.type = CPU_SHX3;
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.dcache.ways = 4;
+ boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
CPU_HAS_LLSC;
break;
case 0x8000:
- current_cpu_data.type = CPU_ST40RA;
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.type = CPU_ST40RA;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
break;
case 0x8100:
- current_cpu_data.type = CPU_ST40GX1;
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.type = CPU_ST40GX1;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
break;
case 0x700:
- current_cpu_data.type = CPU_SH4_501;
- current_cpu_data.icache.ways = 2;
- current_cpu_data.dcache.ways = 2;
+ boot_cpu_data.type = CPU_SH4_501;
+ boot_cpu_data.icache.ways = 2;
+ boot_cpu_data.dcache.ways = 2;
break;
case 0x600:
- current_cpu_data.type = CPU_SH4_202;
- current_cpu_data.icache.ways = 2;
- current_cpu_data.dcache.ways = 2;
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.type = CPU_SH4_202;
+ boot_cpu_data.icache.ways = 2;
+ boot_cpu_data.dcache.ways = 2;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
break;
case 0x500 ... 0x501:
switch (prr) {
case 0x10:
- current_cpu_data.type = CPU_SH7750R;
+ boot_cpu_data.type = CPU_SH7750R;
break;
case 0x11:
- current_cpu_data.type = CPU_SH7751R;
+ boot_cpu_data.type = CPU_SH7751R;
break;
case 0x50 ... 0x5f:
- current_cpu_data.type = CPU_SH7760;
+ boot_cpu_data.type = CPU_SH7760;
break;
}
- current_cpu_data.icache.ways = 2;
- current_cpu_data.dcache.ways = 2;
+ boot_cpu_data.icache.ways = 2;
+ boot_cpu_data.dcache.ways = 2;
- current_cpu_data.flags |= CPU_HAS_FPU;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
break;
default:
- current_cpu_data.type = CPU_SH_NONE;
+ boot_cpu_data.type = CPU_SH_NONE;
break;
}
#ifdef CONFIG_SH_DIRECT_MAPPED
- current_cpu_data.icache.ways = 1;
- current_cpu_data.dcache.ways = 1;
+ boot_cpu_data.icache.ways = 1;
+ boot_cpu_data.dcache.ways = 1;
#endif
#ifdef CONFIG_CPU_HAS_PTEA
- current_cpu_data.flags |= CPU_HAS_PTEA;
+ boot_cpu_data.flags |= CPU_HAS_PTEA;
#endif
/*
* On anything that's not a direct-mapped cache, look to the CVR
* for I/D-cache specifics.
*/
- if (current_cpu_data.icache.ways > 1) {
+ if (boot_cpu_data.icache.ways > 1) {
size = sizes[(cvr >> 20) & 0xf];
- current_cpu_data.icache.way_incr = (size >> 1);
- current_cpu_data.icache.sets = (size >> 6);
+ boot_cpu_data.icache.way_incr = (size >> 1);
+ boot_cpu_data.icache.sets = (size >> 6);
}
/* And the rest of the D-cache */
- if (current_cpu_data.dcache.ways > 1) {
+ if (boot_cpu_data.dcache.ways > 1) {
size = sizes[(cvr >> 16) & 0xf];
- current_cpu_data.dcache.way_incr = (size >> 1);
- current_cpu_data.dcache.sets = (size >> 6);
+ boot_cpu_data.dcache.way_incr = (size >> 1);
+ boot_cpu_data.dcache.sets = (size >> 6);
}
/*
@@ -218,7 +214,7 @@ int __init detect_cpu_and_cache_system(void)
*
* SH-4A's have an optional PIPT L2.
*/
- if (current_cpu_data.flags & CPU_HAS_L2_CACHE) {
+ if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
/*
* Size calculation is much more sensible
* than it is for the L1.
@@ -229,22 +225,22 @@ int __init detect_cpu_and_cache_system(void)
BUG_ON(!size);
- current_cpu_data.scache.way_incr = (1 << 16);
- current_cpu_data.scache.entry_shift = 5;
- current_cpu_data.scache.ways = 4;
- current_cpu_data.scache.linesz = L1_CACHE_BYTES;
+ boot_cpu_data.scache.way_incr = (1 << 16);
+ boot_cpu_data.scache.entry_shift = 5;
+ boot_cpu_data.scache.ways = 4;
+ boot_cpu_data.scache.linesz = L1_CACHE_BYTES;
- current_cpu_data.scache.entry_mask =
- (current_cpu_data.scache.way_incr -
- current_cpu_data.scache.linesz);
+ boot_cpu_data.scache.entry_mask =
+ (boot_cpu_data.scache.way_incr -
+ boot_cpu_data.scache.linesz);
- current_cpu_data.scache.sets = size /
- (current_cpu_data.scache.linesz *
- current_cpu_data.scache.ways);
+ boot_cpu_data.scache.sets = size /
+ (boot_cpu_data.scache.linesz *
+ boot_cpu_data.scache.ways);
- current_cpu_data.scache.way_size =
- (current_cpu_data.scache.sets *
- current_cpu_data.scache.linesz);
+ boot_cpu_data.scache.way_size =
+ (boot_cpu_data.scache.sets *
+ boot_cpu_data.scache.linesz);
}
return 0;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index f2286de22bd..523f68a9ce0 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -104,7 +104,7 @@ enum {
DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
};
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
@@ -118,7 +118,7 @@ static struct intc_vect vectors[] = {
INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
};
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
@@ -126,20 +126,20 @@ static struct intc_group groups[] = {
INTC_GROUP(REF, REF_RCMI, REF_ROVI),
};
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
INTC_PRIO(SCIF, 3),
INTC_PRIO(SCI1, 3),
INTC_PRIO(DMAC, 7),
};
-static struct intc_prio_reg prio_registers[] = {
- { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
- { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
- { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
- { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
- { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
- TMU4, TMU3,
- PCIC1, PCIC0_PCISERR } },
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+ { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+ { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+ { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+ TMU4, TMU3,
+ PCIC1, PCIC0_PCISERR } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
@@ -150,13 +150,13 @@ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7091)
-static struct intc_vect vectors_dma4[] = {
+static struct intc_vect vectors_dma4[] __initdata = {
INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
INTC_VECT(DMAC_DMAE, 0x6c0),
};
-static struct intc_group groups_dma4[] = {
+static struct intc_group groups_dma4[] __initdata = {
INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
DMAC_DMTE3, DMAC_DMAE),
};
@@ -168,7 +168,7 @@ static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
/* SH7750R and SH7751R both have 8-channel DMA controllers */
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_dma8[] = {
+static struct intc_vect vectors_dma8[] __initdata = {
INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
@@ -176,7 +176,7 @@ static struct intc_vect vectors_dma8[] = {
INTC_VECT(DMAC_DMAE, 0x6c0),
};
-static struct intc_group groups_dma8[] = {
+static struct intc_group groups_dma8[] __initdata = {
INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
@@ -191,11 +191,11 @@ static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_tmu34[] = {
+static struct intc_vect vectors_tmu34[] __initdata = {
INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
};
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, TMU4, TMU3,
@@ -210,7 +210,7 @@ static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
#endif
/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
-static struct intc_vect vectors_irlm[] = {
+static struct intc_vect vectors_irlm[] __initdata = {
INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
};
@@ -220,14 +220,14 @@ static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
/* SH7751 and SH7751R both have PCI */
#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_pci[] = {
+static struct intc_vect vectors_pci[] __initdata = {
INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
};
-static struct intc_group groups_pci[] = {
+static struct intc_group groups_pci[] __initdata = {
INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
};
@@ -282,13 +282,19 @@ void __init plat_irq_setup(void)
#define INTC_ICR 0xffd00000UL
#define INTC_ICR_IRLM (1<<7)
-/* enable individual interrupt mode for external interupts */
-void __init ipr_irq_enable_irlm(void)
+void __init plat_irq_setup_pins(int mode)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+ return;
#endif
- register_intc_controller(&intc_desc_irlm);
- ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+ switch (mode) {
+ case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+ register_intc_controller(&intc_desc_irlm);
+ break;
+ default:
+ BUG();
+ }
}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index 47fa2705625..7a898cb1d94 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -12,6 +12,136 @@
#include <linux/serial.h>
#include <asm/sci.h>
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRL0, IRL1, IRL2, IRL3,
+ HUDI, GPIOI,
+ DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+ DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+ DMAC_DMAE,
+ IRQ4, IRQ5, IRQ6, IRQ7,
+ HCAN20, HCAN21,
+ SSI0, SSI1,
+ HAC0, HAC1,
+ I2C0, I2C1,
+ USB, LCDC,
+ DMABRG0, DMABRG1, DMABRG2,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+ SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+ HSPI,
+ MMCIF0, MMCIF1, MMCIF2, MMCIF3,
+ MFI, ADC, CMT,
+ TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+ WDT,
+ REF_RCMI, REF_ROVI,
+
+ /* interrupt groups */
+ DMAC, DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF, TMU2, REF,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+ INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+ INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+ INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+ INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+ INTC_VECT(DMAC_DMAE, 0x6c0),
+ INTC_VECT(IRQ4, 0x800), INTC_VECT(IRQ5, 0x820),
+ INTC_VECT(IRQ6, 0x840), INTC_VECT(IRQ6, 0x860),
+ INTC_VECT(HCAN20, 0x900), INTC_VECT(HCAN21, 0x920),
+ INTC_VECT(SSI0, 0x940), INTC_VECT(SSI1, 0x960),
+ INTC_VECT(HAC0, 0x980), INTC_VECT(HAC1, 0x9a0),
+ INTC_VECT(I2C0, 0x9c0), INTC_VECT(I2C1, 0x9e0),
+ INTC_VECT(USB, 0xa00), INTC_VECT(LCDC, 0xa20),
+ INTC_VECT(DMABRG0, 0xa80), INTC_VECT(DMABRG1, 0xaa0),
+ INTC_VECT(DMABRG2, 0xac0),
+ INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+ INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+ INTC_VECT(SCIF1_ERI, 0xb00), INTC_VECT(SCIF1_RXI, 0xb20),
+ INTC_VECT(SCIF1_BRI, 0xb40), INTC_VECT(SCIF1_TXI, 0xb60),
+ INTC_VECT(SCIF2_ERI, 0xb80), INTC_VECT(SCIF2_RXI, 0xba0),
+ INTC_VECT(SCIF2_BRI, 0xbc0), INTC_VECT(SCIF2_TXI, 0xbe0),
+ INTC_VECT(SIM_ERI, 0xc00), INTC_VECT(SIM_RXI, 0xc20),
+ INTC_VECT(SIM_TXI, 0xc40), INTC_VECT(SIM_TEI, 0xc60),
+ INTC_VECT(HSPI, 0xc80),
+ INTC_VECT(MMCIF0, 0xd00), INTC_VECT(MMCIF1, 0xd20),
+ INTC_VECT(MMCIF2, 0xd40), INTC_VECT(MMCIF3, 0xd60),
+ INTC_VECT(MFI, 0xe80), /* 0xf80 according to data sheet */
+ INTC_VECT(ADC, 0xf80), INTC_VECT(CMT, 0xfa0),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+ DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+ DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+ INTC_GROUP(DMABRG, DMABRG0, DMABRG1, DMABRG2),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+ INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+ INTC_GROUP(MMCIF, MMCIF0, MMCIF1, MMCIF2, MMCIF3),
+ INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+ INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(SIM, 3),
+ INTC_PRIO(DMAC, 7),
+ INTC_PRIO(DMABRG, 13),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+ { IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21,
+ SSI0, SSI1, HAC0, HAC1, I2C0, I2C1, USB, LCDC,
+ 0, DMABRG0, DMABRG1, DMABRG2,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, } },
+ { 0xfe080044, 0xfe080064, 32, /* INTMSK04 / INTMSKCLR04 */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+ HSPI, MMCIF0, MMCIF1, MMCIF2,
+ MMCIF3, 0, 0, 0, 0, 0, 0, 0,
+ 0, MFI, 0, 0, 0, 0, ADC, CMT, } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } },
+ { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
+ { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, 0, HUDI } },
+ { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+ { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xfe080004, 0, 32, 4, /* INTPRI04 */ { HCAN20, HCAN21, SSI0, SSI1,
+ HAC0, HAC1, I2C0, I2C1 } },
+ { 0xfe080008, 0, 32, 4, /* INTPRI08 */ { USB, LCDC, DMABRG, SCIF0,
+ SCIF1, SCIF2, SIM, HSPI } },
+ { 0xfe08000c, 0, 32, 4, /* INTPRI0C */ { 0, 0, MMCIF, 0,
+ MFI, 0, ADC, CMT } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups,
+ priorities, mask_registers, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+ INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups,
+ priorities, mask_registers, prio_registers, NULL);
+
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xfe600000,
@@ -29,6 +159,11 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 76, 77, 79, 78 },
}, {
+ .mapbase = 0xfe480000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 80, 81, 82, 0 },
+ }, {
.flags = 0,
}
};
@@ -52,114 +187,18 @@ static int __init sh7760_devices_setup(void)
}
__initcall(sh7760_devices_setup);
-static struct intc2_data intc2_irq_table[] = {
- {48, 0, 28, 0, 31, 3}, /* IRQ 4 */
- {49, 0, 24, 0, 30, 3}, /* IRQ 3 */
- {50, 0, 20, 0, 29, 3}, /* IRQ 2 */
- {51, 0, 16, 0, 28, 3}, /* IRQ 1 */
- {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */
- {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */
- {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */
- {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */
- {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */
- {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */
- {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */
- {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */
- {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */
- {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */
- {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */
- {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */
- {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */
- {65, 8, 24, 0, 16, 3}, /* LCDC */
- {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */
- {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */
- {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */
- {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */
- {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */
- {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */
- {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */
- {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */
- {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */
- {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */
- {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */
- {80, 8, 4, 4, 23, 3}, /* SIM_ERI */
- {81, 8, 4, 4, 22, 3}, /* SIM_RXI */
- {82, 8, 4, 4, 21, 3}, /* SIM_TXI */
- {83, 8, 4, 4, 20, 3}, /* SIM_TEI */
- {84, 8, 0, 4, 19, 3}, /* HSPII */
- {88, 12, 20, 4, 18, 3}, /* MMCI0 */
- {89, 12, 20, 4, 17, 3}, /* MMCI1 */
- {90, 12, 20, 4, 16, 3}, /* MMCI2 */
- {91, 12, 20, 4, 15, 3}, /* MMCI3 */
- {92, 12, 12, 4, 6, 3}, /* MFI */
- {108,12, 4, 4, 1, 3}, /* ADC */
- {109,12, 0, 4, 0, 3}, /* CMTI */
-};
-
-static struct intc2_desc intc2_irq_desc __read_mostly = {
- .prio_base = 0xfe080000,
- .msk_base = 0xfe080040,
- .mskclr_base = 0xfe080060,
-
- .intc2_data = intc2_irq_table,
- .nr_irqs = ARRAY_SIZE(intc2_irq_table),
-
- .chip = {
- .name = "INTC2-sh7760",
- },
-};
-
-static struct ipr_data ipr_irq_table[] = {
- /* IRQ, IPR-idx, shift, priority */
- { 16, 0, 12, 2 }, /* TMU0 TUNI*/
- { 17, 0, 8, 2 }, /* TMU1 TUNI */
- { 18, 0, 4, 2 }, /* TMU2 TUNI */
- { 19, 0, 4, 2 }, /* TMU2 TIPCI */
- { 27, 1, 12, 2 }, /* WDT ITI */
- { 28, 1, 8, 2 }, /* REF RCMI */
- { 29, 1, 8, 2 }, /* REF ROVI */
- { 32, 2, 0, 7 }, /* HUDI */
- { 33, 2, 12, 7 }, /* GPIOI */
- { 34, 2, 8, 7 }, /* DMAC DMTE0 */
- { 35, 2, 8, 7 }, /* DMAC DMTE1 */
- { 36, 2, 8, 7 }, /* DMAC DMTE2 */
- { 37, 2, 8, 7 }, /* DMAC DMTE3 */
- { 38, 2, 8, 7 }, /* DMAC DMAE */
- { 44, 2, 8, 7 }, /* DMAC DMTE4 */
- { 45, 2, 8, 7 }, /* DMAC DMTE5 */
- { 46, 2, 8, 7 }, /* DMAC DMTE6 */
- { 47, 2, 8, 7 }, /* DMAC DMTE7 */
-/* these here are only valid if INTC_ICR bit 7 is set to 1!
- * XXX: maybe CONFIG_SH_IRLMODE symbol? SH7751 could use it too */
-#if 0
- { 2, 3, 12, 3 }, /* IRL0 */
- { 5, 3, 8, 3 }, /* IRL1 */
- { 8, 3, 4, 3 }, /* IRL2 */
- { 11, 3, 0, 3 }, /* IRL3 */
-#endif
-};
-
-static unsigned long ipr_offsets[] = {
- 0xffd00004UL, /* 0: IPRA */
- 0xffd00008UL, /* 1: IPRB */
- 0xffd0000cUL, /* 2: IPRC */
- 0xffd00010UL, /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
- .ipr_offsets = ipr_offsets,
- .nr_offsets = ARRAY_SIZE(ipr_offsets),
-
- .ipr_data = ipr_irq_table,
- .nr_irqs = ARRAY_SIZE(ipr_irq_table),
-
- .chip = {
- .name = "IPR-sh7760",
- },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ:
+ register_intc_controller(&intc_desc_irq);
+ break;
+ default:
+ BUG();
+ }
+}
void __init plat_irq_setup(void)
{
- register_intc2_controller(&intc2_irq_desc);
- register_ipr_controller(&ipr_irq_desc);
+ register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index c21512c6044..b22a78c807e 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -58,11 +58,11 @@ do { \
*/
void sq_flush_range(unsigned long start, unsigned int len)
{
- volatile unsigned long *sq = (unsigned long *)start;
+ unsigned long *sq = (unsigned long *)start;
/* Flush the queues */
for (len >>= 5; len--; sq += 8)
- prefetchw((void *)sq);
+ prefetchw(sq);
/* Wait for completion */
store_queue_barrier();
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index e6a1fb5f848..24539873943 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -10,6 +10,9 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
+# SMP setup
+smp-$(CONFIG_CPU_SUBTYPE_SHX3) := smp-shx3.o
+
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
@@ -18,4 +21,5 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
-obj-y += $(clock-y)
+obj-y += $(clock-y)
+obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 91d61cf91ba..c0a3f079dfd 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -41,3 +41,7 @@ static int __init sh7343_devices_setup(void)
ARRAY_SIZE(sh7343_devices));
}
__initcall(sh7343_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 25b913e07e2..55f66104431 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -84,7 +84,7 @@ enum {
SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
};
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
@@ -117,7 +117,7 @@ static struct intc_vect vectors[] = {
INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
};
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
@@ -130,7 +130,7 @@ static struct intc_group groups[] = {
INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
};
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
INTC_PRIO(SCIF0, 3),
INTC_PRIO(SCIF1, 3),
INTC_PRIO(SCIF2, 3),
@@ -138,7 +138,7 @@ static struct intc_prio priorities[] = {
INTC_PRIO(TMU1, 2),
};
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
{ } },
{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
@@ -168,24 +168,24 @@ static struct intc_mask_reg mask_registers[] = {
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_prio_reg prio_registers[] = {
- { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
- { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
- { 0xa4080008, 16, 4, /* IPRC */ { } },
- { 0xa408000c, 16, 4, /* IPRD */ { } },
- { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
- { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
- { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
- { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
- { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
- { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
- { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
- { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
- { 0xa4140010, 32, 4, /* INTPRI00 */
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+ { 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+ { 0xa4080008, 0, 16, 4, /* IPRC */ { } },
+ { 0xa408000c, 0, 16, 4, /* IPRD */ { } },
+ { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+ { 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+ { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+ { 0xa408001c, 0, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+ { 0xa4080020, 0, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+ { 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+ { 0xa4080028, 0, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+ { 0xa408002c, 0, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+ { 0xa4140010, 0, 32, 4, /* INTPRI00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_sense_reg sense_registers[] = {
+static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa414001c, 16, 2, /* ICR1 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 6a04cc5f5ac..32f4f59a837 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -51,3 +51,7 @@ static int __init sh7770_devices_setup(void)
ARRAY_SIZE(sh7770_devices));
}
__initcall(sh7770_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index a4127ec1520..e8fd33ff060 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -10,6 +10,7 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
+#include <linux/io.h>
#include <asm/sci.h>
static struct resource rtc_resources[] = {
@@ -114,7 +115,7 @@ enum {
PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
};
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
INTC_VECT(RTC_CUI, 0x4c0),
INTC_VECT(WDT, 0x560),
@@ -150,7 +151,7 @@ static struct intc_vect vectors[] = {
INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
};
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
@@ -167,12 +168,12 @@ static struct intc_group groups[] = {
INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
};
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
INTC_PRIO(SCIF0, 3),
INTC_PRIO(SCIF1, 3),
};
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
{ 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
@@ -180,16 +181,18 @@ static struct intc_mask_reg mask_registers[] = {
HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
};
-static struct intc_prio_reg prio_registers[] = {
- { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
- { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
- { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
- { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
- { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
- { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
- PCIINTD, PCIC5 } },
- { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
- { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
+ TMU2, TMU2_TICPI } },
+ { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+ { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+ { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+ { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { CMT, HAC,
+ PCISERR, PCIINTA, } },
+ { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+ PCIINTD, PCIC5 } },
+ { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+ { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
@@ -197,24 +200,24 @@ static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
/* Support for external interrupt pins in IRQ mode */
-static struct intc_vect irq_vectors[] = {
+static struct intc_vect irq_vectors[] __initdata = {
INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
};
-static struct intc_mask_reg irq_mask_registers[] = {
+static struct intc_mask_reg irq_mask_registers[] __initdata = {
{ 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_prio_reg irq_prio_registers[] = {
- { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
- IRQ4, IRQ5, IRQ6, IRQ7 } },
+static struct intc_prio_reg irq_prio_registers[] __initdata = {
+ { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_sense_reg irq_sense_registers[] = {
+static struct intc_sense_reg irq_sense_registers[] __initdata = {
{ 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
IRQ4, IRQ5, IRQ6, IRQ7 } },
};
@@ -225,7 +228,7 @@ static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
/* External interrupt pins in IRL mode */
-static struct intc_vect irl_vectors[] = {
+static struct intc_vect irl_vectors[] __initdata = {
INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
@@ -236,16 +239,16 @@ static struct intc_vect irl_vectors[] = {
INTC_VECT(IRL_HHHL, 0x3c0),
};
-static struct intc_mask_reg irl3210_mask_registers[] = {
- { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+static struct intc_mask_reg irl3210_mask_registers[] __initdata = {
+ { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
{ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
};
-static struct intc_mask_reg irl7654_mask_registers[] = {
- { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
+ { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
@@ -259,8 +262,28 @@ static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
NULL, NULL, irl3210_mask_registers, NULL, NULL);
+#define INTC_ICR0 0xffd00000
+#define INTC_INTMSK0 0xffd00044
+#define INTC_INTMSK1 0xffd00048
+#define INTC_INTMSK2 0xffd40080
+#define INTC_INTMSKCLR1 0xffd00068
+#define INTC_INTMSKCLR2 0xffd40084
+
void __init plat_irq_setup(void)
{
+ /* disable IRQ7-0 */
+ ctrl_outl(0xff000000, INTC_INTMSK0);
+
+ /* disable IRL3-0 + IRL7-4 */
+ ctrl_outl(0xc0000000, INTC_INTMSK1);
+ ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+ /* select IRL mode for IRL3-0 + IRL7-4 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+ /* disable holding function, ie enable "SH-4 Mode" */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
register_intc_controller(&intc_desc);
}
@@ -268,12 +291,28 @@ void __init plat_irq_setup_pins(int mode)
{
switch (mode) {
case IRQ_MODE_IRQ:
+ /* select IRQ mode for IRL3-0 + IRL7-4 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0);
register_intc_controller(&intc_irq_desc);
break;
case IRQ_MODE_IRL7654:
- register_intc_controller(&intc_irl7654_desc);
+ /* enable IRL7-4 but don't provide any masking */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
break;
case IRQ_MODE_IRL3210:
+ /* enable IRL0-3 but don't provide any masking */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+ break;
+ case IRQ_MODE_IRL7654_MASK:
+ /* enable IRL7-4 and mask using cpu intc controller */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ register_intc_controller(&intc_irl7654_desc);
+ break;
+ case IRQ_MODE_IRL3210_MASK:
+ /* enable IRL0-3 and mask using cpu intc controller */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
register_intc_controller(&intc_irl3210_desc);
break;
default:
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index cf047562e43..39b215d6cee 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -10,6 +10,9 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <asm/mmzone.h>
#include <asm/sci.h>
static struct plat_sci_port sci_platform_data[] = {
@@ -72,46 +75,281 @@ static int __init sh7785_devices_setup(void)
}
__initcall(sh7785_devices_setup);
-static struct intc2_data intc2_irq_table[] = {
- { 28, 0, 24, 0, 0, 2 }, /* TMU0 */
-
- { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */
- { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */
- { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */
- { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */
-
- { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */
- { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */
- { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */
- { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */
-
- { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */
- { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */
- { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */
- { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */
- { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */
-
- { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */
- { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */
- { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */
- { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+
+ IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+ IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+ IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+ IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+ IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+ IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+ IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+ IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
+
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ WDT,
+ TMU0, TMU1, TMU2, TMU2_TICPI,
+ HUDI,
+ DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3,
+ DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9,
+ DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE,
+ HSPI,
+ SCIF2, SCIF3, SCIF4, SCIF5,
+ PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+ PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+ SIOF,
+ MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+ DU,
+ GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI,
+ TMU3, TMU4, TMU5,
+ SSI0, SSI1,
+ HAC0, HAC1,
+ FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+ GPIOI0, GPIOI1, GPIOI2, GPIOI3,
+
+ /* interrupt groups */
+
+ TMU012, DMAC0, SCIF0, SCIF1, DMAC1,
+ PCIC5, MMCIF, GDTA, TMU345, FLCTL, GPIO
};
-static struct intc2_desc intc2_irq_desc __read_mostly = {
- .prio_base = 0xffd40000,
- .msk_base = 0xffd40038,
- .mskclr_base = 0xffd4003c,
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+ INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+ INTC_VECT(HUDI, 0x600),
+ INTC_VECT(DMAC0_DMINT0, 0x620), INTC_VECT(DMAC0_DMINT1, 0x640),
+ INTC_VECT(DMAC0_DMINT2, 0x660), INTC_VECT(DMAC0_DMINT3, 0x680),
+ INTC_VECT(DMAC0_DMINT4, 0x6a0), INTC_VECT(DMAC0_DMINT5, 0x6c0),
+ INTC_VECT(DMAC0_DMAE, 0x6e0),
+ INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+ INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+ INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
+ INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
+ INTC_VECT(DMAC1_DMINT6, 0x880), INTC_VECT(DMAC1_DMINT7, 0x8a0),
+ INTC_VECT(DMAC1_DMINT8, 0x8c0), INTC_VECT(DMAC1_DMINT9, 0x8e0),
+ INTC_VECT(DMAC1_DMINT10, 0x900), INTC_VECT(DMAC1_DMINT11, 0x920),
+ INTC_VECT(DMAC1_DMAE, 0x940),
+ INTC_VECT(HSPI, 0x960),
+ INTC_VECT(SCIF2, 0x980), INTC_VECT(SCIF3, 0x9a0),
+ INTC_VECT(SCIF4, 0x9c0), INTC_VECT(SCIF5, 0x9e0),
+ INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+ INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+ INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+ INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+ INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+ INTC_VECT(SIOF, 0xc00),
+ INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+ INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+ INTC_VECT(DU, 0xd80),
+ INTC_VECT(GDTA_GACLI, 0xda0), INTC_VECT(GDTA_GAMCI, 0xdc0),
+ INTC_VECT(GDTA_GAERI, 0xde0),
+ INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+ INTC_VECT(TMU5, 0xe40),
+ INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
+ INTC_VECT(HAC0, 0xec0), INTC_VECT(HAC1, 0xee0),
+ INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+ INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+ INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+ INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+};
- .intc2_data = intc2_irq_table,
- .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+ INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+ DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+ DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE),
+ INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+ INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+ INTC_GROUP(GDTA, GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI),
+ INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+ INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+ FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+ INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
- .chip = {
- .name = "INTC2-sh7785",
- },
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(SCIF3, 3),
+ INTC_PRIO(SCIF4, 3),
+ INTC_PRIO(SCIF5, 3),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+
+ { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+ { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+ IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+ IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+ IRL0_HHLL, IRL0_HHLH, IRL0_HHHL, 0,
+ IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+ IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+ IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+ IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } },
+
+ { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+ { 0, 0, 0, GDTA, DU, SSI0, SSI1, GPIO,
+ FLCTL, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+ PCIINTA, PCISERR, HAC1, HAC0, DMAC1, DMAC0, HUDI, WDT,
+ SCIF5, SCIF4, SCIF3, SCIF2, SCIF1, SCIF0, TMU345, TMU012 } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
+ TMU2, TMU2_TICPI } },
+ { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, } },
+ { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1,
+ SCIF2, SCIF3 } },
+ { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { SCIF4, SCIF5, WDT, } },
+ { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { HUDI, DMAC0, DMAC1, } },
+ { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { HAC0, HAC1,
+ PCISERR, PCIINTA } },
+ { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { PCIINTB, PCIINTC,
+ PCIINTD, PCIC5 } },
+ { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { SIOF, HSPI, MMCIF, } },
+ { 0xffd40020, 0, 32, 8, /* INT2PRI8 */ { FLCTL, GPIO, SSI0, SSI1, } },
+ { 0xffd40024, 0, 32, 8, /* INT2PRI9 */ { DU, GDTA, } },
};
+static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups, priorities,
+ mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect vectors_irq0123[] __initdata = {
+ INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+ INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_vect vectors_irq4567[] __initdata = {
+ INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+ INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+ { 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq0123, "sh7785-irq0123", vectors_irq0123,
+ NULL, NULL, mask_registers, prio_registers,
+ sense_registers);
+
+static DECLARE_INTC_DESC(intc_desc_irq4567, "sh7785-irq4567", vectors_irq4567,
+ NULL, NULL, mask_registers, prio_registers,
+ sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl0123[] __initdata = {
+ INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+ INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+ INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+ INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+ INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+ INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+ INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+ INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static struct intc_vect vectors_irl4567[] __initdata = {
+ INTC_VECT(IRL4_LLLL, 0xb00), INTC_VECT(IRL4_LLLH, 0xb20),
+ INTC_VECT(IRL4_LLHL, 0xb40), INTC_VECT(IRL4_LLHH, 0xb60),
+ INTC_VECT(IRL4_LHLL, 0xb80), INTC_VECT(IRL4_LHLH, 0xba0),
+ INTC_VECT(IRL4_LHHL, 0xbc0), INTC_VECT(IRL4_LHHH, 0xbe0),
+ INTC_VECT(IRL4_HLLL, 0xc00), INTC_VECT(IRL4_HLLH, 0xc20),
+ INTC_VECT(IRL4_HLHL, 0xc40), INTC_VECT(IRL4_HLHH, 0xc60),
+ INTC_VECT(IRL4_HHLL, 0xc80), INTC_VECT(IRL4_HHLH, 0xca0),
+ INTC_VECT(IRL4_HHHL, 0xcc0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7785-irl0123", vectors_irl0123,
+ NULL, NULL, mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567,
+ NULL, NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0 0xffd00000
+#define INTC_INTMSK0 0xffd00044
+#define INTC_INTMSK1 0xffd00048
+#define INTC_INTMSK2 0xffd40080
+#define INTC_INTMSKCLR1 0xffd00068
+#define INTC_INTMSKCLR2 0xffd40084
+
void __init plat_irq_setup(void)
{
- register_intc2_controller(&intc2_irq_desc);
+ /* disable IRQ3-0 + IRQ7-4 */
+ ctrl_outl(0xff000000, INTC_INTMSK0);
+
+ /* disable IRL3-0 + IRL7-4 */
+ ctrl_outl(0xc0000000, INTC_INTMSK1);
+ ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+ /* select IRL mode for IRL3-0 + IRL7-4 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+ /* disable holding function, ie enable "SH-4 Mode" */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+ register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ7654:
+ /* select IRQ mode for IRL7-4 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0);
+ register_intc_controller(&intc_desc_irq4567);
+ break;
+ case IRQ_MODE_IRQ3210:
+ /* select IRQ mode for IRL3-0 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+ register_intc_controller(&intc_desc_irq0123);
+ break;
+ case IRQ_MODE_IRL7654:
+ /* enable IRL7-4 but don't provide any masking */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
+ break;
+ case IRQ_MODE_IRL3210:
+ /* enable IRL0-3 but don't provide any masking */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+ break;
+ case IRQ_MODE_IRL7654_MASK:
+ /* enable IRL7-4 and mask using cpu intc controller */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ register_intc_controller(&intc_desc_irl4567);
+ break;
+ case IRQ_MODE_IRL3210_MASK:
+ /* enable IRL0-3 and mask using cpu intc controller */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ register_intc_controller(&intc_desc_irl0123);
+ break;
+ default:
+ BUG();
+ }
}
+void __init plat_mem_setup(void)
+{
+ /* Register the URAM space as Node 1 */
+ setup_bootmem_node(1, 0xe55f0000, 0xe5610000);
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 704c064f70d..c6cdd7e3b04 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/io.h>
+#include <asm/mmzone.h>
#include <asm/sci.h>
static struct plat_sci_port sci_platform_data[] = {
@@ -58,28 +59,229 @@ static int __init shx3_devices_setup(void)
}
__initcall(shx3_devices_setup);
-static struct intc2_data intc2_irq_table[] = {
- { 16, 0, 0, 0, 1, 2 }, /* TMU0 */
- { 40, 4, 0, 0x20, 0, 3 }, /* SCIF0 ERI */
- { 41, 4, 0, 0x20, 1, 3 }, /* SCIF0 RXI */
- { 42, 4, 0, 0x20, 2, 3 }, /* SCIF0 BRI */
- { 43, 4, 0, 0x20, 3, 3 }, /* SCIF0 TXI */
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL,
+ IRQ0, IRQ1, IRQ2, IRQ3,
+ HUDII,
+ TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
+ PCII0, PCII1, PCII2, PCII3, PCII4,
+ PCII5, PCII6, PCII7, PCII8, PCII9,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+ SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI,
+ DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3,
+ DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE,
+ DU,
+ DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9,
+ DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE,
+ IIC, VIN0, VIN1, VCORE0, ATAPI,
+ DTU0_TEND, DTU0_AE, DTU0_TMISS,
+ DTU1_TEND, DTU1_AE, DTU1_TMISS,
+ DTU2_TEND, DTU2_AE, DTU2_TMISS,
+ DTU3_TEND, DTU3_AE, DTU3_TMISS,
+ FE0, FE1,
+ GPIO0, GPIO1, GPIO2, GPIO3,
+ PAM, IRM,
+ INTICI0, INTICI1, INTICI2, INTICI3,
+ INTICI4, INTICI5, INTICI6, INTICI7,
+
+ /* interrupt groups */
+ IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+ DMAC0, DMAC1, DTU0, DTU1, DTU2, DTU3,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(HUDII, 0x3e0),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2, 0x440), INTC_VECT(TMU3, 0x460),
+ INTC_VECT(TMU4, 0x480), INTC_VECT(TMU5, 0x4a0),
+ INTC_VECT(PCII0, 0x500), INTC_VECT(PCII1, 0x520),
+ INTC_VECT(PCII2, 0x540), INTC_VECT(PCII3, 0x560),
+ INTC_VECT(PCII4, 0x580), INTC_VECT(PCII5, 0x5a0),
+ INTC_VECT(PCII6, 0x5c0), INTC_VECT(PCII7, 0x5e0),
+ INTC_VECT(PCII8, 0x600), INTC_VECT(PCII9, 0x620),
+ INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+ INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+ INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
+ INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
+ INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
+ INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
+ INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
+ INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
+ INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
+ INTC_VECT(DMAC0_DMINT2, 0x940), INTC_VECT(DMAC0_DMINT3, 0x960),
+ INTC_VECT(DMAC0_DMINT4, 0x980), INTC_VECT(DMAC0_DMINT5, 0x9a0),
+ INTC_VECT(DMAC0_DMAE, 0x9c0),
+ INTC_VECT(DU, 0x9e0),
+ INTC_VECT(DMAC1_DMINT6, 0xa00), INTC_VECT(DMAC1_DMINT7, 0xa20),
+ INTC_VECT(DMAC1_DMINT8, 0xa40), INTC_VECT(DMAC1_DMINT9, 0xa60),
+ INTC_VECT(DMAC1_DMINT10, 0xa80), INTC_VECT(DMAC1_DMINT11, 0xaa0),
+ INTC_VECT(DMAC1_DMAE, 0xac0),
+ INTC_VECT(IIC, 0xae0),
+ INTC_VECT(VIN0, 0xb00), INTC_VECT(VIN1, 0xb20),
+ INTC_VECT(VCORE0, 0xb00), INTC_VECT(ATAPI, 0xb60),
+ INTC_VECT(DTU0_TEND, 0xc00), INTC_VECT(DTU0_AE, 0xc20),
+ INTC_VECT(DTU0_TMISS, 0xc40),
+ INTC_VECT(DTU1_TEND, 0xc60), INTC_VECT(DTU1_AE, 0xc80),
+ INTC_VECT(DTU1_TMISS, 0xca0),
+ INTC_VECT(DTU2_TEND, 0xcc0), INTC_VECT(DTU2_AE, 0xce0),
+ INTC_VECT(DTU2_TMISS, 0xd00),
+ INTC_VECT(DTU3_TEND, 0xd20), INTC_VECT(DTU3_AE, 0xd40),
+ INTC_VECT(DTU3_TMISS, 0xd60),
+ INTC_VECT(FE0, 0xe00), INTC_VECT(FE1, 0xe20),
+ INTC_VECT(GPIO0, 0xe40), INTC_VECT(GPIO1, 0xe60),
+ INTC_VECT(GPIO2, 0xe80), INTC_VECT(GPIO3, 0xea0),
+ INTC_VECT(PAM, 0xec0), INTC_VECT(IRM, 0xee0),
+ INTC_VECT(INTICI0, 0xf00), INTC_VECT(INTICI1, 0xf20),
+ INTC_VECT(INTICI2, 0xf40), INTC_VECT(INTICI3, 0xf60),
+ INTC_VECT(INTICI4, 0xf80), INTC_VECT(INTICI5, 0xfa0),
+ INTC_VECT(INTICI6, 0xfc0), INTC_VECT(INTICI7, 0xfe0),
};
-static struct intc2_desc intc2_irq_desc __read_mostly = {
- .prio_base = 0xfe410000,
- .msk_base = 0xfe410820,
- .mskclr_base = 0xfe410850,
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL),
+ INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+ INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
+ INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+ DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+ INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+ DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+ INTC_GROUP(DTU0, DTU0_TEND, DTU0_AE, DTU0_TMISS),
+ INTC_GROUP(DTU1, DTU1_TEND, DTU1_AE, DTU1_TMISS),
+ INTC_GROUP(DTU2, DTU2_TEND, DTU2_AE, DTU2_TMISS),
+ INTC_GROUP(DTU3, DTU3_TEND, DTU3_AE, DTU3_TMISS),
+};
- .intc2_data = intc2_irq_table,
- .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(SCIF3, 3),
+};
- .chip = {
- .name = "INTC2-SHX3",
- },
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
+ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xfe410040, 0xfe410060, 32, /* CnINTMSK1 / CnINTMSKCLR1 */
+ { IRL } },
+ { 0xfe410820, 0xfe410850, 32, /* CnINT2MSK0 / CnINT2MSKCLR0 */
+ { FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
+ DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
+ 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+ { 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
+ { 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
+ PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
+ PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
+ DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
+ DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
+ DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+ { 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
+ SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
+ SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
+ SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfe410010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+
+ { 0xfe410800, 0, 32, 4, /* INT2PRI0 */ { 0, HUDII, TMU5, TMU4,
+ TMU3, TMU2, TMU1, TMU0 } },
+ { 0xfe410804, 0, 32, 4, /* INT2PRI1 */ { DTU3, DTU2, DTU1, DTU0,
+ SCIF3, SCIF2,
+ SCIF1, SCIF0 } },
+ { 0xfe410808, 0, 32, 4, /* INT2PRI2 */ { DMAC1, DMAC0,
+ PCII56789, PCII4,
+ PCII3, PCII2,
+ PCII1, PCII0 } },
+ { 0xfe41080c, 0, 32, 4, /* INT2PRI3 */ { FE1, FE0, ATAPI, VCORE0,
+ VIN1, VIN0, IIC, DU} },
+ { 0xfe410810, 0, 32, 4, /* INT2PRI4 */ { 0, 0, PAM, GPIO3,
+ GPIO2, GPIO1, GPIO0, IRM } },
+ { 0xfe410090, 0xfe4100a0, 32, 4, /* CnICIPRI / CnICIPRICLR */
+ { INTICI7, INTICI6, INTICI5, INTICI4,
+ INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 4) },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups, priorities,
+ mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+static struct intc_vect vectors_irq[] __initdata = {
+ INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+ INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+ { 0xfe41001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
};
+static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
+ priorities, mask_registers, prio_registers,
+ sense_registers);
+
+/* External interrupt pins in IRL mode */
+static struct intc_vect vectors_irl[] __initdata = {
+ INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+ INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+ INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+ INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+ INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+ INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+ INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+ INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
+ priorities, mask_registers, prio_registers, NULL);
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ:
+ register_intc_controller(&intc_desc_irq);
+ break;
+ case IRQ_MODE_IRL3210:
+ register_intc_controller(&intc_desc_irl);
+ break;
+ default:
+ BUG();
+ }
+}
+
void __init plat_irq_setup(void)
{
- register_intc2_controller(&intc2_irq_desc);
+ register_intc_controller(&intc_desc);
+}
+
+void __init plat_mem_setup(void)
+{
+ unsigned int nid = 1;
+
+ /* Register CPU#0 URAM space as Node 1 */
+ setup_bootmem_node(nid++, 0x145f0000, 0x14610000); /* CPU0 */
+
+#if 0
+ /* XXX: Not yet.. */
+ setup_bootmem_node(nid++, 0x14df0000, 0x14e10000); /* CPU1 */
+ setup_bootmem_node(nid++, 0x155f0000, 0x15610000); /* CPU2 */
+ setup_bootmem_node(nid++, 0x15df0000, 0x15e10000); /* CPU3 */
+#endif
+
+ setup_bootmem_node(nid++, 0x16000000, 0x16020000); /* CSM */
}
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
new file mode 100644
index 00000000000..e5e06845fa4
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -0,0 +1,120 @@
+/*
+ * SH-X3 SMP
+ *
+ * Copyright (C) 2007 Paul Mundt
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+void __init plat_smp_setup(void)
+{
+ unsigned int cpu = 0;
+ int i, num;
+
+ cpus_clear(cpu_possible_map);
+ cpu_set(cpu, cpu_possible_map);
+
+ __cpu_number_map[0] = 0;
+ __cpu_logical_map[0] = 0;
+
+ /*
+ * Do this stupidly for now.. we don't have an easy way to probe
+ * for the total number of cores.
+ */
+ for (i = 1, num = 0; i < NR_CPUS; i++) {
+ cpu_set(i, cpu_possible_map);
+ __cpu_number_map[i] = ++num;
+ __cpu_logical_map[num] = i;
+ }
+
+ printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
+}
+
+void __init plat_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
+#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
+
+#define STBCR_MSTP 0x00000001
+#define STBCR_RESET 0x00000002
+#define STBCR_LTSLP 0x80000000
+
+#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP)
+
+void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
+{
+ ctrl_outl(entry_point, RESET_REG(cpu));
+
+ if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+ ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
+
+ while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+ ;
+
+ /* Start up secondary processor by sending a reset */
+ ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
+}
+
+int plat_smp_processor_id(void)
+{
+ return ctrl_inl(0xff000048); /* CPIDR */
+}
+
+void plat_send_ipi(unsigned int cpu, unsigned int message)
+{
+ unsigned long addr = 0xfe410070 + (cpu * 4);
+
+ BUG_ON(cpu >= 4);
+ BUG_ON(message >= SMP_MSG_NR);
+
+ ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
+}
+
+struct ipi_data {
+ void (*handler)(void *);
+ void *arg;
+ unsigned int message;
+};
+
+static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
+{
+ struct ipi_data *id = arg;
+ unsigned int cpu = hard_smp_processor_id();
+ unsigned int offs = 4 * cpu;
+ unsigned int x;
+
+ x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
+ x &= (1 << (id->message << 2));
+ ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
+
+ id->handler(id->arg);
+
+ return IRQ_HANDLED;
+}
+
+static struct ipi_data ipi_handlers[SMP_MSG_NR];
+
+int plat_register_ipi_handler(unsigned int message,
+ void (*handler)(void *), void *arg)
+{
+ struct ipi_data *id = &ipi_handlers[message];
+
+ BUG_ON(SMP_MSG_NR >= 8);
+ BUG_ON(message >= SMP_MSG_NR);
+
+ id->handler = handler;
+ id->arg = arg;
+ id->message = message;
+
+ return request_irq(104 + message, ipi_interrupt_handler, 0, "IPI", id);
+}
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index e61890217c5..e0590ffebd7 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -77,8 +77,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
-
if (!cpu_online(policy->cpu))
return -ENODEV;
@@ -93,7 +91,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cur = sh_cpufreq_get(policy->cpu);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
@@ -144,6 +141,7 @@ static struct cpufreq_driver sh_cpufreq_driver = {
static int __init sh_cpufreq_module_init(void)
{
+ printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
return cpufreq_register_driver(&sh_cpufreq_driver);
}
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 80b637c3020..2f30977558a 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1999, 2000 Niibe Yutaka
* Copyright (C) 2002 M. R. Brown
- * Copyright (C) 2004 - 2006 Paul Mundt
+ * Copyright (C) 2004 - 2007 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -13,6 +13,7 @@
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/delay.h>
#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
@@ -62,6 +63,16 @@ static struct console bios_console = {
#include <linux/serial_core.h>
#include "../../../drivers/serial/sh-sci.h"
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+#define EPK_SCSMR_VALUE 0x000
+#define EPK_SCBRR_VALUE 0x00C
+#define EPK_FIFO_SIZE 64
+#define EPK_FIFO_BITS (0x7f00 >> 8)
+#else
+#define EPK_FIFO_SIZE 16
+#define EPK_FIFO_BITS (0x1f00 >> 8)
+#endif
+
static struct uart_port scif_port = {
.mapbase = CONFIG_EARLY_SCIF_CONSOLE_PORT,
.membase = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT,
@@ -69,7 +80,7 @@ static struct uart_port scif_port = {
static void scif_sercon_putc(int c)
{
- while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
+ while (((sci_in(&scif_port, SCFDR) & EPK_FIFO_BITS) >= EPK_FIFO_SIZE))
;
sci_out(&scif_port, SCxTDR, c);
@@ -105,7 +116,22 @@ static struct console scif_console = {
.index = -1,
};
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
+#if !defined(CONFIG_SH_STANDARD_BIOS)
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+static void scif_sercon_init(char *s)
+{
+ sci_out(&scif_port, SCSCR, 0x0000); /* clear TE and RE */
+ sci_out(&scif_port, SCFCR, 0x4006); /* reset */
+ sci_out(&scif_port, SCSCR, 0x0000); /* select internal clock */
+ sci_out(&scif_port, SCSMR, EPK_SCSMR_VALUE);
+ sci_out(&scif_port, SCBRR, EPK_SCBRR_VALUE);
+
+ mdelay(1); /* wait 1-bit time */
+
+ sci_out(&scif_port, SCFCR, 0x0030); /* TTRG=b'11 */
+ sci_out(&scif_port, SCSCR, 0x0030); /* TE, RE */
+}
+#elif defined(CONFIG_CPU_SH4)
#define DEFAULT_BAUD 115200
/*
* Simple SCIF init, primarily aimed at SH7750 and other similar SH-4
@@ -146,7 +172,8 @@ static void scif_sercon_init(char *s)
ctrl_outw(0, scif_port.mapbase + 36);
ctrl_outw(0x30, scif_port.mapbase + 8);
}
-#endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */
+#endif /* defined(CONFIG_CPU_SUBTYPE_SH7720) */
+#endif /* !defined(CONFIG_SH_STANDARD_BIOS) */
#endif /* CONFIG_EARLY_SCIF_CONSOLE */
/*
@@ -163,17 +190,12 @@ static struct console *early_console =
#endif
;
-static int __initdata keep_early;
-static int early_console_initialized;
-
-int __init setup_early_printk(char *buf)
+static int __init setup_early_printk(char *buf)
{
- if (!buf)
- return 0;
+ int keep_early = 0;
- if (early_console_initialized)
+ if (!buf)
return 0;
- early_console_initialized = 1;
if (strstr(buf, "keep"))
keep_early = 1;
@@ -186,7 +208,8 @@ int __init setup_early_printk(char *buf)
if (!strncmp(buf, "serial", 6)) {
early_console = &scif_console;
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
+#if (defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720)) && \
+ !defined(CONFIG_SH_STANDARD_BIOS)
scif_sercon_init(buf + 6);
#endif
}
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index b4672802719..e0317ed080c 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -176,7 +176,7 @@ work_notifysig:
jmp @r1
lds r0, pr
work_resched:
-#ifndef CONFIG_PREEMPT
+#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT)
! gUSA handling
mov.l @(OFF_SP,r15), r0 ! get user space stack pointer
mov r0, r1
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 0bccc0ca5a0..3338239717f 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -54,8 +54,8 @@ ENTRY(_stext)
mov.l 1f, r0 ! MD=1, RB=0, BL=0, IMASK=0xF
ldc r0, sr
! Initialize global interrupt mask
- mov #0, r0
#ifdef CONFIG_CPU_HAS_SR_RB
+ mov #0, r0
ldc r0, r6_bank
#endif
@@ -72,15 +72,18 @@ ENTRY(_stext)
!
mov.l 2f, r0
mov r0, r15 ! Set initial r15 (stack pointer)
- mov #(THREAD_SIZE >> 10), r1
- shll8 r1 ! r1 = THREAD_SIZE
- shll2 r1
- sub r1, r0 !
#ifdef CONFIG_CPU_HAS_SR_RB
+ mov.l 7f, r0
ldc r0, r7_bank ! ... and initial thread_info
#endif
! Clear BSS area
+#ifdef CONFIG_SMP
+ mov.l 3f, r0
+ cmp/eq #0, r0 ! skip clear if set to zero
+ bt 10f
+#endif
+
mov.l 3f, r1
add #4, r1
mov.l 4f, r2
@@ -89,13 +92,14 @@ ENTRY(_stext)
bf/s 9b ! while (r1 < r2)
mov.l r0,@-r2
+10:
! Additional CPU initialization
mov.l 6f, r0
jsr @r0
nop
SYNCO() ! Wait for pending instructions..
-
+
! Start kernel
mov.l 5f, r0
jmp @r0
@@ -107,8 +111,10 @@ ENTRY(_stext)
#else
1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
#endif
+ENTRY(stack_start)
2: .long init_thread_union+THREAD_SIZE
3: .long __bss_start
4: .long _end
5: .long start_kernel
6: .long sh_cpu_init
+7: .long init_thread_union
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index edd1ec214e6..2fdc700dfd6 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -150,13 +150,6 @@ struct kgdb_regs trap_registers;
char kgdb_in_gdb_mode;
char in_nmi; /* Set during NMI to prevent reentry */
int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */
-int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */
-
-/* Exposed for user access */
-struct task_struct *kgdb_current;
-unsigned int kgdb_g_imask;
-int kgdb_trapa_val;
-int kgdb_excode;
/* Default values for SCI (can override via kernel args in setup.c) */
#ifndef CONFIG_KGDB_DEFPORT
@@ -616,7 +609,7 @@ static short *get_step_address(void)
else
addr = trap_registers.pc + 2;
- kgdb_flush_icache_range(addr, addr + 2);
+ flush_icache_range(addr, addr + 2);
return (short *) addr;
}
@@ -639,8 +632,7 @@ static void do_single_step(void)
*addr = STEP_OPCODE;
/* Flush and return */
- kgdb_flush_icache_range((long) addr, (long) addr + 2);
- return;
+ flush_icache_range((long) addr, (long) addr + 2);
}
/* Undo a single step */
@@ -650,7 +642,7 @@ static void undo_single_step(void)
/* Use stepped_address in case we stopped elsewhere */
if (stepped_opcode != 0) {
*(short*)stepped_address = stepped_opcode;
- kgdb_flush_icache_range(stepped_address, stepped_address + 2);
+ flush_icache_range(stepped_address, stepped_address + 2);
}
stepped_opcode = 0;
}
@@ -736,7 +728,7 @@ static void write_mem_msg(int binary)
ebin_to_mem(ptr, (char*)addr, length);
else
hex_to_mem(ptr, (char*)addr, length);
- kgdb_flush_icache_range(addr, addr + length);
+ flush_icache_range(addr, addr + length);
ptr = 0;
send_ok_msg();
}
@@ -815,14 +807,10 @@ static void set_regs_msg(void)
/*
* Bring up the ports..
*/
-static int kgdb_serial_setup(void)
+static int __init kgdb_serial_setup(void)
{
- extern int kgdb_console_setup(struct console *co, char *options);
struct console dummy;
-
- kgdb_console_setup(&dummy, 0);
-
- return 0;
+ return kgdb_console_setup(&dummy, 0);
}
#else
#define kgdb_serial_setup() 0
@@ -833,22 +821,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
{
int sigval;
- if (excep_code == NMI_VEC) {
-#ifndef CONFIG_KGDB_NMI
- printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
- return;
-#else /* CONFIG_KGDB_NMI */
- if (!kgdb_enabled) {
- kgdb_enabled = 1;
- kgdb_init();
- }
-#endif /* CONFIG_KGDB_NMI */
- }
-
- /* Ignore if we're disabled */
- if (!kgdb_enabled)
- return;
-
/* Enter GDB mode (e.g. after detach) */
if (!kgdb_in_gdb_mode) {
/* Do serial setup, notify user, issue preemptive ack */
@@ -959,18 +931,10 @@ static void handle_exception(struct pt_regs *regs)
/* Get excode for command loop call, user access */
asm("stc r2_bank, %0":"=r"(excep_code));
- kgdb_excode = excep_code;
-
- /* Other interesting environment items for reference */
- asm("stc r6_bank, %0":"=r"(kgdb_g_imask));
- kgdb_current = current;
- kgdb_trapa_val = trapa_value;
/* Act on the exception */
kgdb_command_loop(excep_code, trapa_value);
- kgdb_current = NULL;
-
/* Copy back the (maybe modified) registers */
for (count = 0; count < 16; count++)
regs->regs[count] = trap_registers.regs[count];
@@ -994,11 +958,8 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
}
/* Initialise the KGDB data structures and serial configuration */
-int kgdb_init(void)
+int __init kgdb_init(void)
{
- if (!kgdb_enabled)
- return 1;
-
in_nmi = 0;
kgdb_nofault = 0;
stepped_opcode = 0;
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 15ae322dbd7..b4469992d6b 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -19,6 +19,7 @@
#include <linux/tick.h>
#include <linux/reboot.h>
#include <linux/fs.h>
+#include <linux/preempt.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/pgalloc.h>
@@ -349,12 +350,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
unlazy_fpu(prev, task_pt_regs(prev));
#endif
-#ifdef CONFIG_PREEMPT
+#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
{
- unsigned long flags;
struct pt_regs *regs;
- local_irq_save(flags);
+ preempt_disable();
regs = task_pt_regs(prev);
if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
int offset = (int)regs->regs[15];
@@ -365,7 +365,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
/* Go to rewind point */
regs->pc = regs->regs[0] + offset;
}
- local_irq_restore(flags);
+ preempt_enable_no_resched();
}
#endif
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 2cf7dec0d69..b3027a6775b 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -22,6 +22,7 @@
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/module.h>
+#include <linux/smp.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -42,7 +43,13 @@ extern void * __rd_start, * __rd_end;
* This value will be used at the very early stage of serial setup.
* The bigger value means no problem.
*/
-struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
+struct sh_cpuinfo cpu_data[NR_CPUS] __read_mostly = {
+ [0] = {
+ .type = CPU_SH_NONE,
+ .loops_per_jiffy = 10000000,
+ },
+};
+EXPORT_SYMBOL(cpu_data);
/*
* The machine vector. First entry in .machvec.init, or clobbered by
@@ -272,6 +279,10 @@ void __init setup_arch(char **cmdline_p)
sh_mv.mv_setup(cmdline_p);
paging_init();
+
+#ifdef CONFIG_SMP
+ plat_smp_setup();
+#endif
}
static const char *cpu_name[] = {
@@ -279,7 +290,7 @@ static const char *cpu_name[] = {
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
- [CPU_SH7712] = "SH7712",
+ [CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720",
[CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
[CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
[CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 37aef0a8519..548e4285b37 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -8,7 +8,7 @@
#include <linux/vmalloc.h>
#include <linux/pci.h>
#include <linux/irq.h>
-
+#include <asm/sections.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
@@ -43,7 +43,6 @@ EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__copy_user);
-EXPORT_SYMBOL(boot_cpu_data);
#ifdef CONFIG_MMU
EXPORT_SYMBOL(get_vm_area);
@@ -53,6 +52,7 @@ EXPORT_SYMBOL(get_vm_area);
EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(__down);
EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
@@ -128,7 +128,8 @@ DECLARE_EXPORT(__movstrSI12_i4);
#endif /* __GNUC__ == 4 */
#endif
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+ defined(CONFIG_SH7705_CACHE_32KB))
/* needed by some modules */
EXPORT_SYMBOL(flush_cache_all);
EXPORT_SYMBOL(flush_cache_range);
@@ -136,17 +137,11 @@ EXPORT_SYMBOL(flush_dcache_page);
EXPORT_SYMBOL(__flush_purge_region);
#endif
-#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
- defined(CONFIG_SH7705_CACHE_32KB))
+#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+ (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
EXPORT_SYMBOL(clear_user_page);
#endif
-EXPORT_SYMBOL(__down_trylock);
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(synchronize_irq);
-#endif
-
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
#ifdef CONFIG_IPV6
@@ -154,3 +149,4 @@ EXPORT_SYMBOL(csum_ipv6_magic);
#endif
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(_ebss);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 706d81ccd10..2f42442cf16 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -507,13 +507,11 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
ctrl_inw(regs->pc - 4));
break;
}
+#ifdef CONFIG_GUSA
} else {
/* gUSA handling */
-#ifdef CONFIG_PREEMPT
- unsigned long flags;
+ preempt_disable();
- local_irq_save(flags);
-#endif
if (regs->regs[15] >= 0xc0000000) {
int offset = (int)regs->regs[15];
@@ -524,8 +522,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
regs->pc = regs->regs[0] + offset -
instruction_size(ctrl_inw(regs->pc-4));
}
-#ifdef CONFIG_PREEMPT
- local_irq_restore(flags);
+
+ preempt_enable_no_resched();
#endif
}
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 283e1425ced..94075e1a1e6 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -3,68 +3,40 @@
*
* SMP support for the SuperH processors.
*
- * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2006 - 2007 Akio Idehara
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
-
#include <linux/err.h>
#include <linux/cache.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/spinlock.h>
-#include <linux/threads.h>
+#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-
+#include <linux/interrupt.h>
#include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/sections.h>
-/*
- * This was written with the Sega Saturn (SMP SH-2 7604) in mind,
- * but is designed to be usable regardless if there's an MMU
- * present or not.
- */
-struct sh_cpuinfo cpu_data[NR_CPUS];
-
-extern void per_cpu_trap_init(void);
+int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
+int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */
cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);
cpumask_t cpu_online_map;
EXPORT_SYMBOL(cpu_online_map);
-static atomic_t cpus_booted = ATOMIC_INIT(0);
-/* These are defined by the board-specific code. */
-
-/*
- * Cause the function described by call_data to be executed on the passed
- * cpu. When the function has finished, increment the finished field of
- * call_data.
- */
-void __smp_send_ipi(unsigned int cpu, unsigned int action);
-
-/*
- * Find the number of available processors
- */
-unsigned int __smp_probe_cpus(void);
-
-/*
- * Start a particular processor
- */
-void __smp_slave_init(unsigned int cpu);
+static atomic_t cpus_booted = ATOMIC_INIT(0);
/*
* Run specified function on a particular processor.
@@ -73,74 +45,123 @@ void __smp_call_function(unsigned int cpu);
static inline void __init smp_store_cpu_info(unsigned int cpu)
{
- cpu_data[cpu].loops_per_jiffy = loops_per_jiffy;
+ struct sh_cpuinfo *c = cpu_data + cpu;
+
+ c->loops_per_jiffy = loops_per_jiffy;
}
void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int cpu = smp_processor_id();
- int i;
- atomic_set(&cpus_booted, 1);
- smp_store_cpu_info(cpu);
-
- for (i = 0; i < __smp_probe_cpus(); i++)
- cpu_set(i, cpu_possible_map);
+ init_new_context(current, &init_mm);
+ current_thread_info()->cpu = cpu;
+ plat_prepare_cpus(max_cpus);
+
+#ifndef CONFIG_HOTPLUG_CPU
+ cpu_present_map = cpu_possible_map;
+#endif
}
void __devinit smp_prepare_boot_cpu(void)
{
unsigned int cpu = smp_processor_id();
+ __cpu_number_map[0] = cpu;
+ __cpu_logical_map[0] = cpu;
+
cpu_set(cpu, cpu_online_map);
cpu_set(cpu, cpu_possible_map);
}
-int __cpu_up(unsigned int cpu)
+asmlinkage void __cpuinit start_secondary(void)
{
- struct task_struct *tsk;
+ unsigned int cpu;
+ struct mm_struct *mm = &init_mm;
- tsk = fork_idle(cpu);
+ atomic_inc(&mm->mm_count);
+ atomic_inc(&mm->mm_users);
+ current->active_mm = mm;
+ BUG_ON(current->mm);
+ enter_lazy_tlb(mm, current);
- if (IS_ERR(tsk))
- panic("Failed forking idle task for cpu %d\n", cpu);
-
- task_thread_info(tsk)->cpu = cpu;
+ per_cpu_trap_init();
+
+ preempt_disable();
+
+ local_irq_enable();
+
+ calibrate_delay();
+
+ cpu = smp_processor_id();
+ smp_store_cpu_info(cpu);
cpu_set(cpu, cpu_online_map);
- return 0;
+ cpu_idle();
}
-int start_secondary(void *unused)
+extern struct {
+ unsigned long sp;
+ unsigned long bss_start;
+ unsigned long bss_end;
+ void *start_kernel_fn;
+ void *cpu_init_fn;
+ void *thread_info;
+} stack_start;
+
+int __cpuinit __cpu_up(unsigned int cpu)
{
- unsigned int cpu;
+ struct task_struct *tsk;
+ unsigned long timeout;
- cpu = smp_processor_id();
+ tsk = fork_idle(cpu);
+ if (IS_ERR(tsk)) {
+ printk(KERN_ERR "Failed forking idle task for cpu %d\n", cpu);
+ return PTR_ERR(tsk);
+ }
- atomic_inc(&init_mm.mm_count);
- current->active_mm = &init_mm;
+ /* Fill in data in head.S for secondary cpus */
+ stack_start.sp = tsk->thread.sp;
+ stack_start.thread_info = tsk->stack;
+ stack_start.bss_start = 0; /* don't clear bss for secondary cpus */
+ stack_start.start_kernel_fn = start_secondary;
- smp_store_cpu_info(cpu);
+ flush_cache_all();
- __smp_slave_init(cpu);
- preempt_disable();
- per_cpu_trap_init();
-
- atomic_inc(&cpus_booted);
+ plat_start_cpu(cpu, (unsigned long)_stext);
- cpu_idle();
- return 0;
+ timeout = jiffies + HZ;
+ while (time_before(jiffies, timeout)) {
+ if (cpu_online(cpu))
+ break;
+
+ udelay(10);
+ }
+
+ if (cpu_online(cpu))
+ return 0;
+
+ return -ENOENT;
}
void __init smp_cpus_done(unsigned int max_cpus)
{
- smp_mb();
+ unsigned long bogosum = 0;
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ bogosum += cpu_data[cpu].loops_per_jiffy;
+
+ printk(KERN_INFO "SMP: Total of %d processors activated "
+ "(%lu.%02lu BogoMIPS).\n", num_online_cpus(),
+ bogosum / (500000/HZ),
+ (bogosum / (5000/HZ)) % 100);
}
void smp_send_reschedule(int cpu)
{
- __smp_send_ipi(cpu, SMP_MSG_RESCHEDULE);
+ plat_send_ipi(cpu, SMP_MSG_RESCHEDULE);
}
static void stop_this_cpu(void *unused)
@@ -157,7 +178,6 @@ void smp_send_stop(void)
smp_call_function(stop_this_cpu, 0, 1, 0);
}
-
struct smp_fn_call_struct smp_fn_call = {
.lock = SPIN_LOCK_UNLOCKED,
.finished = ATOMIC_INIT(0),
@@ -175,9 +195,6 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
unsigned int nr_cpus = atomic_read(&cpus_booted);
int i;
- if (nr_cpus < 2)
- return 0;
-
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
@@ -189,7 +206,7 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
for (i = 0; i < nr_cpus; i++)
if (i != smp_processor_id())
- __smp_call_function(i);
+ plat_send_ipi(i, SMP_MSG_FUNCTION);
if (wait)
while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1));
@@ -205,3 +222,143 @@ int setup_profiling_timer(unsigned int multiplier)
return 0;
}
+static void flush_tlb_all_ipi(void *info)
+{
+ local_flush_tlb_all();
+}
+
+void flush_tlb_all(void)
+{
+ on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
+}
+
+static void flush_tlb_mm_ipi(void *mm)
+{
+ local_flush_tlb_mm((struct mm_struct *)mm);
+}
+
+/*
+ * The following tlb flush calls are invoked when old translations are
+ * being torn down, or pte attributes are changing. For single threaded
+ * address spaces, a new context is obtained on the current cpu, and tlb
+ * context on other cpus are invalidated to force a new context allocation
+ * at switch_mm time, should the mm ever be used on other cpus. For
+ * multithreaded address spaces, intercpu interrupts have to be sent.
+ * Another case where intercpu interrupts are required is when the target
+ * mm might be active on another cpu (eg debuggers doing the flushes on
+ * behalf of debugees, kswapd stealing pages from another process etc).
+ * Kanoj 07/00.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ preempt_disable();
+
+ if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+ smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
+ } else {
+ int i;
+ for (i = 0; i < num_online_cpus(); i++)
+ if (smp_processor_id() != i)
+ cpu_context(i, mm) = 0;
+ }
+ local_flush_tlb_mm(mm);
+
+ preempt_enable();
+}
+
+struct flush_tlb_data {
+ struct vm_area_struct *vma;
+ unsigned long addr1;
+ unsigned long addr2;
+};
+
+static void flush_tlb_range_ipi(void *info)
+{
+ struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+ local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ preempt_disable();
+ if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+ struct flush_tlb_data fd;
+
+ fd.vma = vma;
+ fd.addr1 = start;
+ fd.addr2 = end;
+ smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
+ } else {
+ int i;
+ for (i = 0; i < num_online_cpus(); i++)
+ if (smp_processor_id() != i)
+ cpu_context(i, mm) = 0;
+ }
+ local_flush_tlb_range(vma, start, end);
+ preempt_enable();
+}
+
+static void flush_tlb_kernel_range_ipi(void *info)
+{
+ struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+ local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ struct flush_tlb_data fd;
+
+ fd.addr1 = start;
+ fd.addr2 = end;
+ on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1);
+}
+
+static void flush_tlb_page_ipi(void *info)
+{
+ struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+ local_flush_tlb_page(fd->vma, fd->addr1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ preempt_disable();
+ if ((atomic_read(&vma->vm_mm->mm_users) != 1) ||
+ (current->mm != vma->vm_mm)) {
+ struct flush_tlb_data fd;
+
+ fd.vma = vma;
+ fd.addr1 = page;
+ smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
+ } else {
+ int i;
+ for (i = 0; i < num_online_cpus(); i++)
+ if (smp_processor_id() != i)
+ cpu_context(i, vma->vm_mm) = 0;
+ }
+ local_flush_tlb_page(vma, page);
+ preempt_enable();
+}
+
+static void flush_tlb_one_ipi(void *info)
+{
+ struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+ local_flush_tlb_one(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_one(unsigned long asid, unsigned long vaddr)
+{
+ struct flush_tlb_data fd;
+
+ fd.addr1 = asid;
+ fd.addr2 = vaddr;
+
+ smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1, 1);
+ local_flush_tlb_one(asid, vaddr);
+}
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index 91fb7024e06..10bec45415b 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -14,24 +14,6 @@
#include <linux/sys.h>
#include <linux/linkage.h>
-#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
-#define sys_nfsservctl sys_ni_syscall
-#endif
-
-#if !defined(CONFIG_MMU)
-#define sys_madvise sys_ni_syscall
-#define sys_readahead sys_ni_syscall
-#define sys_mprotect sys_ni_syscall
-#define sys_msync sys_ni_syscall
-#define sys_mlock sys_ni_syscall
-#define sys_munlock sys_ni_syscall
-#define sys_mlockall sys_ni_syscall
-#define sys_munlockall sys_ni_syscall
-#define sys_mremap sys_ni_syscall
-#define sys_mincore sys_ni_syscall
-#define sys_remap_file_pages sys_ni_syscall
-#endif
-
.data
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call*/
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 8a545d54e2d..628ec9a15e3 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -173,7 +173,8 @@ static int tmu_timer_init(void)
tmu_timer_stop();
-#if !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
!defined(CONFIG_CPU_SUBTYPE_SH7785) && \
!defined(CONFIG_CPU_SUBTYPE_SHX3)
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 67015044d74..dcb46e71da1 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -807,12 +807,13 @@ static inline void __init gdb_vbr_init(void)
}
#endif
-void __init per_cpu_trap_init(void)
+void __cpuinit per_cpu_trap_init(void)
{
extern void *vbr_base;
#ifdef CONFIG_SH_STANDARD_BIOS
- gdb_vbr_init();
+ if (raw_smp_processor_id() == 0)
+ gdb_vbr_init();
#endif
/* NOTE: The VBR value should be at P1
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 9cb95af7b09..6d5abba2ee2 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -62,6 +62,8 @@ SECTIONS
__nosave_end = .;
PERCPU(PAGE_SIZE)
+
+ . = ALIGN(L1_CACHE_BYTES);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
_edata = .; /* End of data section */
@@ -89,7 +91,14 @@ SECTIONS
__con_initcall_end = .;
SECURITY_INIT
+ /* .exit.text is discarded at runtime, not link time, to deal with
+ references from .rodata */
+ .exit.text : { *(.exit.text) }
+ .exit.data : { *(.exit.data) }
+
#ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(PAGE_SIZE);
+
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
@@ -107,6 +116,7 @@ SECTIONS
*(.bss.page_aligned)
*(.bss)
. = ALIGN(4);
+ _ebss = .; /* uClinux MTD sucks */
_end = . ;
}
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 43f3972a5fb..cf446bbab5b 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -2,7 +2,6 @@
# Processor families
#
config CPU_SH2
- select SH_WRITETHROUGH if !CPU_SH2A
bool
config CPU_SH2A
@@ -19,6 +18,7 @@ config CPU_SH4
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
select CPU_HAS_PTEA if (!CPU_SUBTYPE_ST40 && !CPU_SH4A) || CPU_SHX2
+ select CPU_HAS_FPU if !CPU_SH4AL_DSP
config CPU_SH4A
bool
@@ -32,7 +32,6 @@ config CPU_SH4AL_DSP
config CPU_SUBTYPE_ST40
bool
select CPU_SH4
- select CPU_HAS_INTC2_IRQ
config CPU_SHX2
bool
@@ -52,26 +51,22 @@ choice
config CPU_SUBTYPE_SH7619
bool "Support SH7619 processor"
select CPU_SH2
- select CPU_HAS_IPR_IRQ
# SH-2A Processor Support
config CPU_SUBTYPE_SH7206
bool "Support SH7206 processor"
select CPU_SH2A
- select CPU_HAS_IPR_IRQ
# SH-3 Processor Support
config CPU_SUBTYPE_SH7705
bool "Support SH7705 processor"
select CPU_SH3
- select CPU_HAS_IPR_IRQ
config CPU_SUBTYPE_SH7706
bool "Support SH7706 processor"
select CPU_SH3
- select CPU_HAS_IPR_IRQ
help
Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
@@ -91,14 +86,12 @@ config CPU_SUBTYPE_SH7708
config CPU_SUBTYPE_SH7709
bool "Support SH7709 processor"
select CPU_SH3
- select CPU_HAS_IPR_IRQ
help
Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
config CPU_SUBTYPE_SH7710
bool "Support SH7710 processor"
select CPU_SH3
- select CPU_HAS_IPR_IRQ
select CPU_HAS_DSP
help
Select SH7710 if you have a SH3-DSP SH7710 CPU.
@@ -106,24 +99,28 @@ config CPU_SUBTYPE_SH7710
config CPU_SUBTYPE_SH7712
bool "Support SH7712 processor"
select CPU_SH3
- select CPU_HAS_IPR_IRQ
select CPU_HAS_DSP
help
Select SH7712 if you have a SH3-DSP SH7712 CPU.
+config CPU_SUBTYPE_SH7720
+ bool "Support SH7720 processor"
+ select CPU_SH3
+ select CPU_HAS_DSP
+ help
+ Select SH7720 if you have a SH3-DSP SH7720 CPU.
+
# SH-4 Processor Support
config CPU_SUBTYPE_SH7750
bool "Support SH7750 processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
help
Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
config CPU_SUBTYPE_SH7091
bool "Support SH7091 processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
help
Select SH7091 if you have an SH-4 based Sega device (such as
the Dreamcast, Naomi, and Naomi 2).
@@ -131,17 +128,14 @@ config CPU_SUBTYPE_SH7091
config CPU_SUBTYPE_SH7750R
bool "Support SH7750R processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7750S
bool "Support SH7750S processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7751
bool "Support SH7751 processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
help
Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
or if you have a HD6417751R CPU.
@@ -149,13 +143,10 @@ config CPU_SUBTYPE_SH7751
config CPU_SUBTYPE_SH7751R
bool "Support SH7751R processor"
select CPU_SH4
- select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7760
bool "Support SH7760 processor"
select CPU_SH4
- select CPU_HAS_INTC2_IRQ
- select CPU_HAS_IPR_IRQ
config CPU_SUBTYPE_SH4_202
bool "Support SH4-202 processor"
@@ -185,19 +176,21 @@ config CPU_SUBTYPE_SH7770
config CPU_SUBTYPE_SH7780
bool "Support SH7780 processor"
select CPU_SH4A
- select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7785
bool "Support SH7785 processor"
select CPU_SH4A
select CPU_SHX2
- select CPU_HAS_INTC2_IRQ
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
config CPU_SUBTYPE_SHX3
bool "Support SH-X3 processor"
select CPU_SH4A
select CPU_SHX3
- select CPU_HAS_INTC2_IRQ
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
+ select SYS_SUPPORTS_SMP
# SH4AL-DSP Processor Support
@@ -209,7 +202,6 @@ config CPU_SUBTYPE_SH7722
bool "Support SH7722 processor"
select CPU_SH4AL_DSP
select CPU_SHX2
- select CPU_HAS_INTC_IRQ
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
@@ -274,7 +266,7 @@ config 32BIT
config X2TLB
bool "Enable extended TLB mode"
- depends on CPU_SHX2 && MMU && EXPERIMENTAL
+ depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL
help
Selecting this option will enable the extended mode of the SH-X2
TLB. For legacy SH-X behaviour and interoperability, say N. For
@@ -307,6 +299,7 @@ config NUMA
config NODES_SHIFT
int
+ default "3" if CPU_SUBTYPE_SHX3
default "1"
depends on NEED_MULTIPLE_NODES
@@ -323,7 +316,9 @@ config ARCH_SPARSEMEM_DEFAULT
config MAX_ACTIVE_REGIONS
int
- default "2" if (CPU_SUBTYPE_SH7722 && SPARSEMEM)
+ default "6" if (CPU_SUBTYPE_SHX3 && SPARSEMEM)
+ default "2" if SPARSEMEM && (CPU_SUBTYPE_SH7722 || \
+ CPU_SUBTYPE_SH7785)
default "1"
config ARCH_POPULATES_NODE_MAP
@@ -342,25 +337,27 @@ config ARCH_MEMORY_PROBE
choice
prompt "Kernel page size"
+ default PAGE_SIZE_8KB if X2TLB
default PAGE_SIZE_4KB
config PAGE_SIZE_4KB
bool "4kB"
+ depends on !X2TLB
help
This is the default page size used by all SuperH CPUs.
config PAGE_SIZE_8KB
bool "8kB"
- depends on EXPERIMENTAL && X2TLB
+ depends on X2TLB
help
This enables 8kB pages as supported by SH-X2 and later MMUs.
config PAGE_SIZE_64KB
bool "64kB"
- depends on EXPERIMENTAL && CPU_SH4
+ depends on CPU_SH4
help
This enables support for 64kB pages, possible on all SH-4
- CPUs and later. Highly experimental, not recommended.
+ CPUs and later.
endchoice
@@ -412,8 +409,17 @@ config SH_DIRECT_MAPPED
Turn this option off for platforms that do not have a direct-mapped
cache, and you have no need to run the caches in such a configuration.
-config SH_WRITETHROUGH
- bool "Use write-through caching"
+choice
+ prompt "Cache mode"
+ default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4
+ default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A)
+
+config CACHE_WRITEBACK
+ bool "Write-back"
+ depends on CPU_SH2A || CPU_SH3 || CPU_SH4
+
+config CACHE_WRITETHROUGH
+ bool "Write-through"
help
Selecting this option will configure the caches in write-through
mode, as opposed to the default write-back configuration.
@@ -424,4 +430,9 @@ config SH_WRITETHROUGH
If unsure, say N.
+config CACHE_OFF
+ bool "Off"
+
+endchoice
+
endmenu
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 4061e89d84d..ee30fb44dfe 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -4,29 +4,32 @@
obj-y := init.o extable.o consistent.o
-obj-$(CONFIG_CPU_SH2) += cache-sh2.o
-obj-$(CONFIG_CPU_SH3) += cache-sh3.o
-obj-$(CONFIG_CPU_SH4) += cache-sh4.o
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH2) += cache-sh2.o
+obj-$(CONFIG_CPU_SH3) += cache-sh3.o
+obj-$(CONFIG_CPU_SH4) += cache-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
+endif
mmu-y := tlb-nommu.o pg-nommu.o
-mmu-$(CONFIG_CPU_SH3) += fault-nommu.o
-mmu-$(CONFIG_CPU_SH4) += fault-nommu.o
mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
ioremap.o
obj-y += $(mmu-y)
ifdef CONFIG_DEBUG_FS
-obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
+obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
endif
ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o
-obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
+obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
+obj-$(CONFIG_CPU_SH4) += tlb-sh4.o
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH4) += pg-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
+endif
endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
obj-$(CONFIG_32BIT) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 86486326ef1..226b190c5b9 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,7 +2,7 @@
* arch/sh/mm/cache-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2001 - 2006 Paul Mundt
+ * Copyright (C) 2001 - 2007 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -44,7 +44,7 @@ static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
static void compute_alias(struct cache_info *c)
{
c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
- c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1;
+ c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0;
}
static void __init emit_cache_params(void)
@@ -54,21 +54,35 @@ static void __init emit_cache_params(void)
ctrl_inl(CCN_CVR),
ctrl_inl(CCN_PRR));
printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n",
- current_cpu_data.icache.ways,
- current_cpu_data.icache.sets,
- current_cpu_data.icache.way_incr);
+ boot_cpu_data.icache.ways,
+ boot_cpu_data.icache.sets,
+ boot_cpu_data.icache.way_incr);
printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
- current_cpu_data.icache.entry_mask,
- current_cpu_data.icache.alias_mask,
- current_cpu_data.icache.n_aliases);
+ boot_cpu_data.icache.entry_mask,
+ boot_cpu_data.icache.alias_mask,
+ boot_cpu_data.icache.n_aliases);
printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n",
- current_cpu_data.dcache.ways,
- current_cpu_data.dcache.sets,
- current_cpu_data.dcache.way_incr);
+ boot_cpu_data.dcache.ways,
+ boot_cpu_data.dcache.sets,
+ boot_cpu_data.dcache.way_incr);
printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
- current_cpu_data.dcache.entry_mask,
- current_cpu_data.dcache.alias_mask,
- current_cpu_data.dcache.n_aliases);
+ boot_cpu_data.dcache.entry_mask,
+ boot_cpu_data.dcache.alias_mask,
+ boot_cpu_data.dcache.n_aliases);
+
+ /*
+ * Emit Secondary Cache parameters if the CPU has a probed L2.
+ */
+ if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
+ printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n",
+ boot_cpu_data.scache.ways,
+ boot_cpu_data.scache.sets,
+ boot_cpu_data.scache.way_incr);
+ printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
+ boot_cpu_data.scache.entry_mask,
+ boot_cpu_data.scache.alias_mask,
+ boot_cpu_data.scache.n_aliases);
+ }
if (!__flush_dcache_segment_fn)
panic("unknown number of cache ways\n");
@@ -79,10 +93,11 @@ static void __init emit_cache_params(void)
*/
void __init p3_cache_init(void)
{
- compute_alias(&current_cpu_data.icache);
- compute_alias(&current_cpu_data.dcache);
+ compute_alias(&boot_cpu_data.icache);
+ compute_alias(&boot_cpu_data.dcache);
+ compute_alias(&boot_cpu_data.scache);
- switch (current_cpu_data.dcache.ways) {
+ switch (boot_cpu_data.dcache.ways) {
case 1:
__flush_dcache_segment_fn = __flush_dcache_segment_1way;
break;
@@ -187,13 +202,13 @@ void flush_cache_sigtramp(unsigned long addr)
: "m" (__m(v)));
index = CACHE_IC_ADDRESS_ARRAY |
- (v & current_cpu_data.icache.entry_mask);
+ (v & boot_cpu_data.icache.entry_mask);
local_irq_save(flags);
jump_to_P2();
- for (i = 0; i < current_cpu_data.icache.ways;
- i++, index += current_cpu_data.icache.way_incr)
+ for (i = 0; i < boot_cpu_data.icache.ways;
+ i++, index += boot_cpu_data.icache.way_incr)
ctrl_outl(0, index); /* Clear out Valid-bit */
back_to_P1();
@@ -210,7 +225,7 @@ static inline void flush_cache_4096(unsigned long start,
* All types of SH-4 require PC to be in P2 to operate on the I-cache.
* Some types of SH-4 require PC to be in P2 to operate on the D-cache.
*/
- if ((current_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
+ if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
(start < CACHE_OC_ADDRESS_ARRAY))
exec_offset = 0x20000000;
@@ -232,7 +247,7 @@ void flush_dcache_page(struct page *page)
int i, n;
/* Loop all the D-cache */
- n = current_cpu_data.dcache.n_aliases;
+ n = boot_cpu_data.dcache.n_aliases;
for (i = 0; i < n; i++, addr += 4096)
flush_cache_4096(addr, phys);
}
@@ -264,7 +279,7 @@ static inline void flush_icache_all(void)
void flush_dcache_all(void)
{
- (*__flush_dcache_segment_fn)(0UL, current_cpu_data.dcache.way_size);
+ (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size);
wmb();
}
@@ -278,8 +293,8 @@ static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
unsigned long d = 0, p = start & PAGE_MASK;
- unsigned long alias_mask = current_cpu_data.dcache.alias_mask;
- unsigned long n_aliases = current_cpu_data.dcache.n_aliases;
+ unsigned long alias_mask = boot_cpu_data.dcache.alias_mask;
+ unsigned long n_aliases = boot_cpu_data.dcache.n_aliases;
unsigned long select_bit;
unsigned long all_aliases_mask;
unsigned long addr_offset;
@@ -366,7 +381,7 @@ void flush_cache_mm(struct mm_struct *mm)
* If cache is only 4k-per-way, there are never any 'aliases'. Since
* the cache is physically tagged, the data can just be left in there.
*/
- if (current_cpu_data.dcache.n_aliases == 0)
+ if (boot_cpu_data.dcache.n_aliases == 0)
return;
/*
@@ -403,7 +418,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
unsigned long phys = pfn << PAGE_SHIFT;
unsigned int alias_mask;
- alias_mask = current_cpu_data.dcache.alias_mask;
+ alias_mask = boot_cpu_data.dcache.alias_mask;
/* We only need to flush D-cache when we have alias */
if ((address^phys) & alias_mask) {
@@ -417,7 +432,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
phys);
}
- alias_mask = current_cpu_data.icache.alias_mask;
+ alias_mask = boot_cpu_data.icache.alias_mask;
if (vma->vm_flags & VM_EXEC) {
/*
* Evict entries from the portion of the cache from which code
@@ -449,7 +464,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
* If cache is only 4k-per-way, there are never any 'aliases'. Since
* the cache is physically tagged, the data can just be left in there.
*/
- if (current_cpu_data.dcache.n_aliases == 0)
+ if (boot_cpu_data.dcache.n_aliases == 0)
return;
/*
@@ -510,7 +525,7 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys,
unsigned long a, ea, p;
unsigned long temp_pc;
- dcache = &current_cpu_data.dcache;
+ dcache = &boot_cpu_data.dcache;
/* Write this way for better assembly. */
way_count = dcache->ways;
way_incr = dcache->way_incr;
@@ -585,7 +600,7 @@ static void __flush_dcache_segment_1way(unsigned long start,
base_addr = ((base_addr >> 16) << 16);
base_addr |= start;
- dcache = &current_cpu_data.dcache;
+ dcache = &boot_cpu_data.dcache;
linesz = dcache->linesz;
way_incr = dcache->way_incr;
way_size = dcache->way_size;
@@ -627,7 +642,7 @@ static void __flush_dcache_segment_2way(unsigned long start,
base_addr = ((base_addr >> 16) << 16);
base_addr |= start;
- dcache = &current_cpu_data.dcache;
+ dcache = &boot_cpu_data.dcache;
linesz = dcache->linesz;
way_incr = dcache->way_incr;
way_size = dcache->way_size;
@@ -686,7 +701,7 @@ static void __flush_dcache_segment_4way(unsigned long start,
base_addr = ((base_addr >> 16) << 16);
base_addr |= start;
- dcache = &current_cpu_data.dcache;
+ dcache = &boot_cpu_data.dcache;
linesz = dcache->linesz;
way_incr = dcache->way_incr;
way_size = dcache->way_size;
diff --git a/arch/sh/mm/copy_page.S b/arch/sh/mm/copy_page.S
index ae039f2da16..a81dbdb0559 100644
--- a/arch/sh/mm/copy_page.S
+++ b/arch/sh/mm/copy_page.S
@@ -141,47 +141,38 @@ ENTRY(__copy_user_page)
.long 9999b, 6000f ; \
.previous
ENTRY(__copy_user)
- tst r6,r6 ! Check explicitly for zero
- bf 1f
- rts
- mov #0,r0 ! normal return
-1:
- mov.l r10,@-r15
- mov.l r9,@-r15
- mov.l r8,@-r15
+ ! Check if small number of bytes
+ mov #11,r0
mov r4,r3
- add r6,r3 ! last destination address
- mov #12,r0 ! Check if small number of bytes
- cmp/gt r0,r6
- bt 2f
- bra .L_cleanup_loop
- nop
-2:
- neg r5,r0 ! Calculate bytes needed to align source
+ cmp/gt r0,r6 ! r6 (len) > r0 (11)
+ bf/s .L_cleanup_loop_no_pop
+ add r6,r3 ! last destination address
+
+ ! Calculate bytes needed to align to src
+ mov.l r11,@-r15
+ neg r5,r0
+ mov.l r10,@-r15
add #4,r0
+ mov.l r9,@-r15
and #3,r0
+ mov.l r8,@-r15
tst r0,r0
- bt .L_jump
- mov r0,r1
+ bt 2f
-.L_loop1:
- ! Copy bytes to align source
-EX( mov.b @r5+,r0 )
- dt r1
-EX( mov.b r0,@r4 )
+1:
+ ! Copy bytes to long word align src
+EX( mov.b @r5+,r1 )
+ dt r0
add #-1,r6
- bf/s .L_loop1
+EX( mov.b r1,@r4 )
+ bf/s 1b
add #1,r4
-.L_jump:
- mov r6,r2 ! Calculate number of longwords to copy
+ ! Jump to appropriate routine depending on dest
+2: mov #3,r1
+ mov r6, r2
+ and r4,r1
shlr2 r2
- tst r2,r2
- bt .L_cleanup
-
- mov r4,r0 ! Jump to appropriate routine
- and #3,r0
- mov r0,r1
shll2 r1
mova .L_jump_tbl,r0
mov.l @(r0,r1),r1
@@ -195,43 +186,97 @@ EX( mov.b r0,@r4 )
.long .L_dest10
.long .L_dest11
+/*
+ * Come here if there are less than 12 bytes to copy
+ *
+ * Keep the branch target close, so the bf/s callee doesn't overflow
+ * and result in a more expensive branch being inserted. This is the
+ * fast-path for small copies, the jump via the jump table will hit the
+ * default slow-path cleanup. -PFM.
+ */
+.L_cleanup_loop_no_pop:
+ tst r6,r6 ! Check explicitly for zero
+ bt 1f
+
+2:
+EX( mov.b @r5+,r0 )
+ dt r6
+EX( mov.b r0,@r4 )
+ bf/s 2b
+ add #1,r4
+
+1: mov #0,r0 ! normal return
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+6000:
+ mov.l 8000f,r1
+ mov r3,r0
+ jmp @r1
+ sub r4,r0
+ .align 2
+8000: .long 5000b
+
+.previous
+ rts
+ nop
+
! Destination = 00
.L_dest00:
- mov r2,r7
- shlr2 r7
- shlr r7
- tst r7,r7
- mov #7,r0
- bt/s 1f
- and r0,r2
- .align 2
+ ! Skip the large copy for small transfers
+ mov #(32+32-4), r0
+ cmp/gt r6, r0 ! r0 (60) > r6 (len)
+ bt 1f
+
+ ! Align dest to a 32 byte boundary
+ neg r4,r0
+ add #0x20, r0
+ and #0x1f, r0
+ tst r0, r0
+ bt 2f
+
+ sub r0, r6
+ shlr2 r0
+3:
+EX( mov.l @r5+,r1 )
+ dt r0
+EX( mov.l r1,@r4 )
+ bf/s 3b
+ add #4,r4
+
2:
EX( mov.l @r5+,r0 )
+EX( mov.l @r5+,r1 )
+EX( mov.l @r5+,r2 )
+EX( mov.l @r5+,r7 )
EX( mov.l @r5+,r8 )
EX( mov.l @r5+,r9 )
EX( mov.l @r5+,r10 )
-EX( mov.l r0,@r4 )
-EX( mov.l r8,@(4,r4) )
-EX( mov.l r9,@(8,r4) )
-EX( mov.l r10,@(12,r4) )
-EX( mov.l @r5+,r0 )
-EX( mov.l @r5+,r8 )
-EX( mov.l @r5+,r9 )
-EX( mov.l @r5+,r10 )
- dt r7
-EX( mov.l r0,@(16,r4) )
-EX( mov.l r8,@(20,r4) )
-EX( mov.l r9,@(24,r4) )
-EX( mov.l r10,@(28,r4) )
+EX( mov.l @r5+,r11 )
+EX( movca.l r0,@r4 )
+ add #-32, r6
+EX( mov.l r1,@(4,r4) )
+ mov #32, r0
+EX( mov.l r2,@(8,r4) )
+ cmp/gt r6, r0 ! r0 (32) > r6 (len)
+EX( mov.l r7,@(12,r4) )
+EX( mov.l r8,@(16,r4) )
+EX( mov.l r9,@(20,r4) )
+EX( mov.l r10,@(24,r4) )
+EX( mov.l r11,@(28,r4) )
bf/s 2b
add #32,r4
- tst r2,r2
+
+1: mov r6, r0
+ shlr2 r0
+ tst r0, r0
bt .L_cleanup
1:
-EX( mov.l @r5+,r0 )
- dt r2
-EX( mov.l r0,@r4 )
+EX( mov.l @r5+,r1 )
+ dt r0
+EX( mov.l r1,@r4 )
bf/s 1b
add #4,r4
@@ -250,7 +295,7 @@ EX( mov.l r0,@r4 )
and r0,r2
2:
dt r7
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
EX( mov.l @r5+,r0 )
EX( mov.l @r5+,r1 )
EX( mov.l @r5+,r8 )
@@ -320,7 +365,7 @@ EX( mov.w r0,@(2,r4) )
1: ! Read longword, write two words per iteration
EX( mov.l @r5+,r0 )
dt r2
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
EX( mov.w r0,@r4 )
shlr16 r0
EX( mov.w r0,@(2,r4) )
@@ -342,7 +387,7 @@ EX( mov.w r0,@r4 )
! Read longword, write byte, word, byte per iteration
EX( mov.l @r5+,r0 )
dt r2
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
EX( mov.b r0,@r4 )
shlr8 r0
add #1,r4
@@ -379,6 +424,7 @@ EX( mov.b r0,@r4 )
.L_exit:
mov #0,r0 ! normal return
+
5000:
# Exception handler:
@@ -394,5 +440,6 @@ EX( mov.b r0,@r4 )
.previous
mov.l @r15+,r8
mov.l @r15+,r9
+ mov.l @r15+,r10
rts
- mov.l @r15+,r10
+ mov.l @r15+,r11
diff --git a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c
deleted file mode 100644
index c6f5b51ec2c..00000000000
--- a/arch/sh/mm/fault-nommu.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * arch/sh/mm/fault-nommu.c
- *
- * Copyright (C) 2002 - 2007 Paul Mundt
- *
- * Based on linux/arch/sh/mm/fault.c:
- * Copyright (C) 1999 Niibe Yutaka
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/hardirq.h>
-#include <linux/kprobes.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/kgdb.h>
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
- unsigned long writeaccess,
- unsigned long address)
-{
- trace_hardirqs_on();
- local_irq_enable();
-
-#if defined(CONFIG_SH_KGDB)
- if (kgdb_nofault && kgdb_bus_err_hook)
- kgdb_bus_err_hook();
-#endif
-
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
- if (address < PAGE_SIZE) {
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- } else {
- printk(KERN_ALERT "Unable to handle kernel paging request");
- }
-
- printk(" at virtual address %08lx\n", address);
- printk(KERN_ALERT "pc = %08lx\n", regs->pc);
-
- die("Oops", regs, writeaccess);
- do_exit(SIGKILL);
-}
-
-asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
- unsigned long writeaccess,
- unsigned long address)
-{
-#if defined(CONFIG_SH_KGDB)
- if (kgdb_nofault && kgdb_bus_err_hook)
- kgdb_bus_err_hook();
-#endif
-
- return (address >= TASK_SIZE);
-}
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index a08a4a958ad..7d43758dc24 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -145,7 +145,7 @@ repeat:
ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
-#ifdef CONFIG_SH_WRITETHROUGH
+#ifdef CONFIG_CACHE_WRITETHROUGH
/*
* When we are in 32-bit address extended mode, CCR.CB becomes
* invalid, so care must be taken to manually adjust cacheable
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
index f74cf667c8f..2d1dd604430 100644
--- a/arch/sh/mm/tlb-sh4.c
+++ b/arch/sh/mm/tlb-sh4.c
@@ -4,27 +4,14 @@
* SH-4 specific TLB operations
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
-#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-
+#include <linux/io.h>
#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -34,22 +21,27 @@ void update_mmu_cache(struct vm_area_struct * vma,
unsigned long flags;
unsigned long pteval;
unsigned long vpn;
- struct page *page;
- unsigned long pfn;
/* Ptrace may call this routine. */
if (vma && current->active_mm != vma->vm_mm)
return;
- pfn = pte_pfn(pte);
- if (pfn_valid(pfn)) {
- page = pfn_to_page(pfn);
- if (!test_bit(PG_mapped, &page->flags)) {
- unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
- __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE);
- __set_bit(PG_mapped, &page->flags);
+#ifndef CONFIG_CACHE_OFF
+ {
+ unsigned long pfn = pte_pfn(pte);
+
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+
+ if (!test_bit(PG_mapped, &page->flags)) {
+ unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+ __flush_wback_region((void *)P1SEGADDR(phys),
+ PAGE_SIZE);
+ __set_bit(PG_mapped, &page->flags);
+ }
}
}
+#endif
local_irq_save(flags);
@@ -57,16 +49,26 @@ void update_mmu_cache(struct vm_area_struct * vma,
vpn = (address & MMU_VPN_MASK) | get_asid();
ctrl_outl(vpn, MMU_PTEH);
- pteval = pte_val(pte);
+ pteval = pte.pte_low;
/* Set PTEA register */
+#ifdef CONFIG_X2TLB
+ /*
+ * For the extended mode TLB this is trivial, only the ESZ and
+ * EPR bits need to be written out to PTEA, with the remainder of
+ * the protection bits (with the exception of the compat-mode SZ
+ * and PR bits, which are cleared) being written out in PTEL.
+ */
+ ctrl_outl(pte.pte_high, MMU_PTEA);
+#else
if (cpu_data->flags & CPU_HAS_PTEA)
/* TODO: make this look less hacky */
ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+#endif
/* Set PTEL register */
pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-#ifdef CONFIG_SH_WRITETHROUGH
+#ifdef CONFIG_CACHE_WRITETHROUGH
pteval |= _PAGE_WT;
#endif
/* conveniently, we want all the software flags to be 0 anyway */
@@ -93,4 +95,3 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page)
ctrl_outl(data, addr);
back_to_P1();
}
-
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 5664631d8ae..b3327ce8e82 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -36,6 +36,14 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_HARDIRQS
+ bool
+ default y
+
+config GENERIC_IRQ_PROBE
+ bool
+ default y
+
config RWSEM_XCHGADD_ALGORITHM
bool
@@ -58,18 +66,12 @@ choice
prompt "SuperH system type"
default SH_SIMULATOR
-config SH_GENERIC
- bool "Generic"
-
config SH_SIMULATOR
bool "Simulator"
config SH_CAYMAN
bool "Cayman"
-config SH_ROMRAM
- bool "ROM/RAM"
-
config SH_HARP
bool "ST50-Harp"
@@ -152,60 +154,54 @@ comment "Memory options"
config CACHED_MEMORY_OFFSET
hex "Cached Area Offset"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "20000000"
config MEMORY_START
hex "Physical memory start address"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "80000000"
config MEMORY_SIZE_IN_MB
- int "Memory size (in MB)" if SH_HARP || SH_CAYMAN || SH_SIMULATOR
- default "64" if SH_HARP || SH_CAYMAN
+ int "Memory size (in MB)"
default "8" if SH_SIMULATOR
+ default "64"
comment "Cache options"
-config DCACHE_DISABLED
- bool "DCache Disabling"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
-
choice
prompt "DCache mode"
- depends on !DCACHE_DISABLED && !SH_SIMULATOR
+ default DCACHE_DISABLED if SH_SIMULATOR
default DCACHE_WRITE_BACK
config DCACHE_WRITE_BACK
bool "Write-back"
+ depends on !SH_SIMULATOR
config DCACHE_WRITE_THROUGH
bool "Write-through"
+ depends on !SH_SIMULATOR
+
+config DCACHE_DISABLED
+ bool "Disabled"
endchoice
config ICACHE_DISABLED
bool "ICache Disabling"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
config PCIDEVICE_MEMORY_START
hex
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "C0000000"
config DEVICE_MEMORY_START
hex
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "E0000000"
config FLASH_MEMORY_START
hex "Flash memory/on-chip devices start address"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "00000000"
config PCI_BLOCK_START
hex "PCI block start address"
- depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
default "40000000"
comment "CPU Subtype specific options"
@@ -214,8 +210,10 @@ config SH64_ID2815_WORKAROUND
bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
comment "Misc options"
+
config HEARTBEAT
bool "Heartbeat LED"
+ depends on SH_CAYMAN
config HDSP253_LED
bool "Support for HDSP-253 LED"
@@ -242,6 +240,7 @@ config SBUS
config PCI
bool "PCI support"
+ depends on SH_CAYMAN
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
@@ -294,15 +293,3 @@ source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
-
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_IRQ_PROBE
- bool
- default y
-
diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug
index 26d842c0713..05c07c4e4ed 100644
--- a/arch/sh64/Kconfig.debug
+++ b/arch/sh64/Kconfig.debug
@@ -5,9 +5,6 @@ source "lib/Kconfig.debug"
config EARLY_PRINTK
bool "Early SCIF console support"
-config DEBUG_KERNEL_WITH_GDB_STUB
- bool "GDB Stub kernel debug"
-
config SH64_PROC_TLB
bool "Debug: report TLB fill/purge activity through /proc/tlb"
depends on PROC_FS
@@ -28,17 +25,9 @@ config POOR_MANS_STRACE
config SH_ALPHANUMERIC
bool "Enable debug outputs to on-board alphanumeric display"
+ depends on SH_CAYMAN
config SH_NO_BSS_INIT
bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
-config FRAME_POINTER
- bool "Compile the kernel with frame pointers"
- default y if KGDB
- help
- If you say Y here the resulting kernel image will be slightly larger
- and slower, but it will give very useful debugging information.
- If you don't debug the kernel, you can say N, but we may not be able
- to solve problems without frame pointers.
-
endmenu
diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile
index ebf20043991..8290c6380d7 100644
--- a/arch/sh64/Makefile
+++ b/arch/sh64/Makefile
@@ -40,6 +40,8 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S
#
KBUILD_DEFCONFIG := cayman_defconfig
+KBUILD_IMAGE := arch/$(ARCH)/boot/zImage
+
ifdef LOADADDR
LINKFLAGS += -Ttext $(word 1,$(LOADADDR))
endif
@@ -47,7 +49,6 @@ endif
machine-$(CONFIG_SH_CAYMAN) := cayman
machine-$(CONFIG_SH_SIMULATOR) := sim
machine-$(CONFIG_SH_HARP) := harp
-machine-$(CONFIG_SH_ROMRAM) := romram
head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
@@ -106,6 +107,5 @@ arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S
CLEAN_FILES += arch/$(ARCH)/lib/syscalltab.h
define archhelp
- @echo ' zImage - Compressed kernel image (arch/sh64/boot/zImage)'
+ @echo '* zImage - Compressed kernel image'
endef
-
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
index 78443414334..91b59118c1b 100644
--- a/arch/sh64/configs/cayman_defconfig
+++ b/arch/sh64/configs/cayman_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22
-# Fri Jul 20 12:28:34 2007
+# Linux kernel version: 2.6.23-rc8
+# Tue Oct 9 15:37:16 2007
#
CONFIG_SUPERH=y
CONFIG_SUPERH64=y
@@ -11,21 +11,20 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
@@ -57,7 +56,6 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
@@ -67,7 +65,12 @@ CONFIG_SLAB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
@@ -90,10 +93,8 @@ CONFIG_DEFAULT_IOSCHED="cfq"
#
# System type
#
-# CONFIG_SH_GENERIC is not set
# CONFIG_SH_SIMULATOR is not set
CONFIG_SH_CAYMAN=y
-# CONFIG_SH_ROMRAM is not set
# CONFIG_SH_HARP is not set
CONFIG_CPU_SH5=y
CONFIG_CPU_SUBTYPE_SH5_101=y
@@ -119,9 +120,9 @@ CONFIG_MEMORY_SIZE_IN_MB=128
#
# Cache options
#
-# CONFIG_DCACHE_DISABLED is not set
CONFIG_DCACHE_WRITE_BACK=y
# CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_DCACHE_DISABLED is not set
# CONFIG_ICACHE_DISABLED is not set
CONFIG_PCIDEVICE_MEMORY_START=C0000000
CONFIG_DEVICE_MEMORY_START=E0000000
@@ -151,7 +152,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -276,7 +276,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
-# 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
@@ -325,6 +324,7 @@ CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -332,12 +332,8 @@ CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_SPI_ATTRS=y
# 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_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
@@ -347,7 +343,6 @@ CONFIG_SCSI_SPI_ATTRS=y
# 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
@@ -449,6 +444,7 @@ CONFIG_NETDEV_1000=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
@@ -572,7 +568,6 @@ CONFIG_WATCHDOG=y
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_SH_WDT is not set
#
# PCI-based Watchdog Cards
@@ -586,7 +581,59 @@ CONFIG_HW_RANDOM=y
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# 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_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM 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
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
@@ -599,16 +646,51 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 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
@@ -621,8 +703,115 @@ CONFIG_HWMON=y
#
# Multimedia devices
#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_TEA5761 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_DVB_CORE=y
+# CONFIG_DVB_CORE_ATTACH is not set
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+# CONFIG_DVB_STV0299 is not set
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+# CONFIG_DVB_TDA8083 is not set
+# CONFIG_DVB_MT312 is not set
+# CONFIG_DVB_VES1X93 is not set
+# CONFIG_DVB_S5H1420 is not set
+# CONFIG_DVB_TDA10086 is not set
+
+#
+# DVB-T (terrestrial) frontends
+#
+# CONFIG_DVB_SP8870 is not set
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_CX22700 is not set
+# CONFIG_DVB_CX22702 is not set
+# CONFIG_DVB_L64781 is not set
+# CONFIG_DVB_TDA1004X is not set
+# CONFIG_DVB_NXT6000 is not set
+# CONFIG_DVB_MT352 is not set
+# CONFIG_DVB_ZL10353 is not set
+# CONFIG_DVB_DIB3000MB is not set
+# CONFIG_DVB_DIB3000MC is not set
+# CONFIG_DVB_DIB7000M is not set
+# CONFIG_DVB_DIB7000P is not set
+
+#
+# DVB-C (cable) frontends
+#
+# CONFIG_DVB_VES1820 is not set
+# CONFIG_DVB_TDA10021 is not set
+# CONFIG_DVB_TDA10023 is not set
+# CONFIG_DVB_STV0297 is not set
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+# CONFIG_DVB_NXT200X is not set
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+# CONFIG_DVB_BCM3510 is not set
+# CONFIG_DVB_LGDT330X is not set
+
+#
+# Tuners/PLL support
+#
+# CONFIG_DVB_PLL is not set
+# CONFIG_DVB_TDA826X is not set
+# CONFIG_DVB_TDA827X is not set
+# CONFIG_DVB_TUNER_QT1010 is not set
+# CONFIG_DVB_TUNER_MT2060 is not set
+
+#
+# Miscellaneous devices
+#
+# CONFIG_DVB_LNBP21 is not set
+# CONFIG_DVB_ISL6421 is not set
+# CONFIG_DVB_TUA6100 is not set
CONFIG_DAB=y
#
@@ -635,6 +824,7 @@ CONFIG_DAB=y
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
@@ -728,24 +918,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
-
-#
-# LED devices
-#
# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
# CONFIG_INFINIBAND is not set
-
-#
-# Real Time Clock
-#
# CONFIG_RTC_CLASS is not set
#
@@ -929,9 +1103,9 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
CONFIG_FRAME_POINTER=y
CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_EARLY_PRINTK is not set
-# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
CONFIG_SH64_PROC_TLB=y
CONFIG_SH64_PROC_ASIDS=y
CONFIG_SH64_SR_WATCH=y
@@ -960,5 +1134,3 @@ CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/sh64/configs/harp_defconfig b/arch/sh64/configs/harp_defconfig
new file mode 100644
index 00000000000..e4b84b51baf
--- /dev/null
+++ b/arch/sh64/configs/harp_defconfig
@@ -0,0 +1,756 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc8
+# Mon Oct 1 18:01:38 2007
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_QUICKLIST=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG 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"
+
+#
+# System type
+#
+# CONFIG_SH_SIMULATOR is not set
+# CONFIG_SH_CAYMAN is not set
+CONFIG_SH_HARP=y
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+CONFIG_DCACHE_WRITE_BACK=y
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_DCACHE_DISABLED is not set
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+# CONFIG_SH_DMA is not set
+CONFIG_PREEMPT=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=0
+CONFIG_NR_QUICK=1
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=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=y
+# 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=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 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
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# 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=y
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+CONFIG_SH64_PROC_TLB=y
+CONFIG_SH64_PROC_ASIDS=y
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
+# CONFIG_SH_ALPHANUMERIC is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh64/configs/sim_defconfig b/arch/sh64/configs/sim_defconfig
new file mode 100644
index 00000000000..f83bae659dc
--- /dev/null
+++ b/arch/sh64/configs/sim_defconfig
@@ -0,0 +1,566 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc8
+# Mon Oct 1 17:50:35 2007
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_QUICKLIST=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG 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"
+
+#
+# System type
+#
+CONFIG_SH_SIMULATOR=y
+# CONFIG_SH_CAYMAN is not set
+# CONFIG_SH_HARP is not set
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+# CONFIG_DCACHE_WRITE_BACK is not set
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+CONFIG_DCACHE_DISABLED=y
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+# CONFIG_SH_DMA is not set
+CONFIG_PREEMPT=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=0
+CONFIG_NR_QUICK=1
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=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=y
+# 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=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# 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_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# 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
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+CONFIG_SH64_PROC_TLB=y
+CONFIG_SH64_PROC_ASIDS=y
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
+# CONFIG_SH_ALPHANUMERIC is not set
+CONFIG_SH_NO_BSS_INIT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh64/kernel/Makefile b/arch/sh64/kernel/Makefile
index 5816657c079..e3467bda616 100644
--- a/arch/sh64/kernel/Makefile
+++ b/arch/sh64/kernel/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_SH_DMA) += dma.o
obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KALLSYMS) += unwind.o
-obj-$(CONFIG_PCI) += pci-dma.o pcibios.o
+obj-$(CONFIG_PCI) += pcibios.o
obj-$(CONFIG_MODULES) += module.o
ifeq ($(CONFIG_PCI),y)
diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c
index 91707c1acd7..d1619d95fba 100644
--- a/arch/sh64/kernel/alphanum.c
+++ b/arch/sh64/kernel/alphanum.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
void mach_alphanum(int pos, unsigned char val);
-void mach_led(int pos, int val);
void print_seg(char *file, int line)
{
diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
index 461ea3de316..b1705acc8e6 100644
--- a/arch/sh64/kernel/sh_ksyms.c
+++ b/arch/sh64/kernel/sh_ksyms.c
@@ -31,16 +31,11 @@ extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
/* platform dependent support */
EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy_nocheck);
-EXPORT_SYMBOL(strstr);
-
#ifdef CONFIG_VT
EXPORT_SYMBOL(screen_info);
#endif
@@ -50,27 +45,18 @@ EXPORT_SYMBOL(__down_trylock);
EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(__put_user_asm_l);
EXPORT_SYMBOL(__get_user_asm_l);
-EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strlen);
-
+EXPORT_SYMBOL(udelay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(ndelay);
+EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(flush_dcache_page);
-
-/* For ext3 */
EXPORT_SYMBOL(sh64_page_clear);
/* Ugh. These come in from libgcc.a at link time. */
+#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
-extern void __sdivsi3(void);
-extern void __muldi3(void);
-extern void __udivsi3(void);
-extern char __div_table;
-EXPORT_SYMBOL(__sdivsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__div_table);
-
-
+DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__muldi3);
+DECLARE_EXPORT(__udivsi3);
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
index b37f4f4981d..06f3c179e34 100644
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -476,8 +476,18 @@ static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
-static struct irqaction irq1 = { sh64_rtc_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "rtc", NULL, NULL};
+static struct irqaction irq0 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "timer",
+};
+static struct irqaction irq1 = {
+ .handler = sh64_rtc_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "rtc",
+};
void __init time_init(void)
{
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index 267b4f9af2e..f533a064da5 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -30,14 +30,6 @@
#define LOAD_OFFSET CONFIG_CACHED_MEMORY_OFFSET
#include <asm-generic/vmlinux.lds.h>
-#ifdef NOTDEF
-#ifdef CONFIG_LITTLE_ENDIAN
-OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux")
-#else
-OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64")
-#endif
-#endif
-
OUTPUT_ARCH(sh:sh5)
#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
@@ -74,10 +66,12 @@ SECTIONS
__ex_table : C_PHYS(__ex_table) { *(__ex_table) }
__stop___ex_table = .;
- RODATA
-
_etext = .; /* End of text section */
+ NOTES
+
+ RODATA
+
.data : C_PHYS(.data) { /* Data */
DATA_DATA
CONSTRUCTORS
@@ -86,13 +80,9 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
.data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) }
- . = ALIGN(PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : C_PHYS(.data.percpu) {
- *(.data.percpu)
- *(.data.percpu.shared_aligned)
- }
- __per_cpu_end = . ;
+ PERCPU(PAGE_SIZE)
+
+ . = ALIGN(L1_CACHE_BYTES);
.data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) }
_edata = .; /* End of data section */
@@ -145,38 +135,6 @@ SECTIONS
*(.exitcall.exit)
}
- /* Stabs debugging sections. */
- .stab 0 : C_PHYS(.stab) { *(.stab) }
- .stabstr 0 : C_PHYS(.stabstr) { *(.stabstr) }
- .stab.excl 0 : C_PHYS(.stab.excl) { *(.stab.excl) }
- .stab.exclstr 0 : C_PHYS(.stab.exclstr) { *(.stab.exclstr) }
- .stab.index 0 : C_PHYS(.stab.index) { *(.stab.index) }
- .stab.indexstr 0 : C_PHYS(.stab.indexstr) { *(.stab.indexstr) }
- .comment 0 : C_PHYS(.comment) { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging section are relative to the beginning
- of the section so we begin .debug at 0. */
- /* DWARF 1 */
- .debug 0 : C_PHYS(.debug) { *(.debug) }
- .line 0 : C_PHYS(.line) { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : C_PHYS(.debug_srcinfo) { *(.debug_srcinfo) }
- .debug_sfnames 0 : C_PHYS(.debug_sfnames) { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : C_PHYS(.debug_aranges) { *(.debug_aranges) }
- .debug_pubnames 0 : C_PHYS(.debug_pubnames) { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : C_PHYS(.debug_info) { *(.debug_info) }
- .debug_abbrev 0 : C_PHYS(.debug_abbrev) { *(.debug_abbrev) }
- .debug_line 0 : C_PHYS(.debug_line) { *(.debug_line) }
- .debug_frame 0 : C_PHYS(.debug_frame) { *(.debug_frame) }
- .debug_str 0 : C_PHYS(.debug_str) { *(.debug_str) }
- .debug_loc 0 : C_PHYS(.debug_loc) { *(.debug_loc) }
- .debug_macinfo 0 : C_PHYS(.debug_macinfo) { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : C_PHYS(.debug_weaknames) { *(.debug_weaknames) }
- .debug_funcnames 0 : C_PHYS(.debug_funcnames) { *(.debug_funcnames) }
- .debug_typenames 0 : C_PHYS(.debug_typenames) { *(.debug_typenames) }
- .debug_varnames 0 : C_PHYS(.debug_varnames) { *(.debug_varnames) }
- /* These must appear regardless of . */
+ STABS_DEBUG
+ DWARF_DEBUG
}
diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c
index bd550176024..053137abd8a 100644
--- a/arch/sh64/lib/c-checksum.c
+++ b/arch/sh64/lib/c-checksum.c
@@ -10,6 +10,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
@@ -110,7 +111,7 @@ static unsigned long do_csum(const unsigned char *buff, int len)
if (odd)
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
- pr_debug("\nCHECKSUM is 0x%x\n", result);
+ pr_debug("\nCHECKSUM is 0x%lx\n", result);
out:
return result;
diff --git a/arch/sh64/lib/io.c b/arch/sh64/lib/io.c
index 587baa3dffb..a3f3a2b8e25 100644
--- a/arch/sh64/lib/io.c
+++ b/arch/sh64/lib/io.c
@@ -11,30 +11,11 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/io.h>
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the SuperH architecture, we just read/write the
- * memory location directly.
- */
-
-/* This is horrible at the moment - needs more work to do something sensible */
-#define IO_DELAY()
-
-#define OUT_DELAY(x,type) \
-void out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
-
-#define IN_DELAY(x,type) \
-unsigned type in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
-
-#if 1
-OUT_DELAY(b, long) OUT_DELAY(w, long) OUT_DELAY(l, long)
- IN_DELAY(b, long) IN_DELAY(w, long) IN_DELAY(l, long)
-#endif
/* Now for the string version of these functions */
void outsb(unsigned long port, const void *addr, unsigned long count)
{
@@ -45,6 +26,7 @@ void outsb(unsigned long port, const void *addr, unsigned long count)
outb(*p, port);
}
}
+EXPORT_SYMBOL(outsb);
void insb(unsigned long port, void *addr, unsigned long count)
{
@@ -55,6 +37,7 @@ void insb(unsigned long port, void *addr, unsigned long count)
*p = inb(port);
}
}
+EXPORT_SYMBOL(insb);
/* For the 16 and 32 bit string functions, we have to worry about alignment.
* The SH does not do unaligned accesses, so we have to read as bytes and
@@ -74,6 +57,7 @@ void outsw(unsigned long port, const void *addr, unsigned long count)
outw(tmp, port);
}
}
+EXPORT_SYMBOL(outsw);
void insw(unsigned long port, void *addr, unsigned long count)
{
@@ -87,6 +71,7 @@ void insw(unsigned long port, void *addr, unsigned long count)
p[1] = (tmp >> 8) & 0xff;
}
}
+EXPORT_SYMBOL(insw);
void outsl(unsigned long port, const void *addr, unsigned long count)
{
@@ -100,6 +85,7 @@ void outsl(unsigned long port, const void *addr, unsigned long count)
outl(tmp, port);
}
}
+EXPORT_SYMBOL(outsl);
void insl(unsigned long port, void *addr, unsigned long count)
{
@@ -116,6 +102,7 @@ void insl(unsigned long port, void *addr, unsigned long count)
}
}
+EXPORT_SYMBOL(insl);
void memcpy_toio(void __iomem *to, const void *from, long count)
{
@@ -126,6 +113,7 @@ void memcpy_toio(void __iomem *to, const void *from, long count)
writeb(*p++, to++);
}
}
+EXPORT_SYMBOL(memcpy_toio);
void memcpy_fromio(void *to, void __iomem *from, long count)
{
@@ -137,3 +125,4 @@ void memcpy_fromio(void *to, void __iomem *from, long count)
from++;
}
}
+EXPORT_SYMBOL(memcpy_fromio);
diff --git a/arch/sh64/lib/iomap.c b/arch/sh64/lib/iomap.c
index 5cd3d5e9c76..253d1e351d4 100644
--- a/arch/sh64/lib/iomap.c
+++ b/arch/sh64/lib/iomap.c
@@ -17,12 +17,15 @@ ioport_map(unsigned long port, unsigned int len)
{
return (void __iomem *)port;
}
+EXPORT_SYMBOL(ioport_map);
void ioport_unmap(void __iomem *addr)
{
/* Nothing .. */
}
+EXPORT_SYMBOL(ioport_unmap);
+#ifdef CONFIG_PCI
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
{
unsigned long start = pci_resource_start(dev, bar);
@@ -41,14 +44,11 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
/* What? */
return NULL;
}
+EXPORT_SYMBOL(pci_iomap);
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
/* Nothing .. */
}
-
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);
-
+#endif
diff --git a/arch/sh64/mach-cayman/setup.c b/arch/sh64/mach-cayman/setup.c
index c3611cc2735..726c520d7eb 100644
--- a/arch/sh64/mach-cayman/setup.c
+++ b/arch/sh64/mach-cayman/setup.c
@@ -18,19 +18,11 @@
* lethal@linux-sh.org: 15th May 2003
* Use the generic procfs cpuinfo interface, just return a valid board name.
*/
-
-#include <linux/stddef.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
#include <linux/kernel.h>
-#include <linux/seq_file.h>
-#include <asm/processor.h>
#include <asm/platform.h>
-#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/page.h>
+#include <asm/io.h>
/*
* Platform Dependent Interrupt Priorities.
diff --git a/arch/sh64/mach-harp/Makefile b/arch/sh64/mach-harp/Makefile
index 63f065bad2f..2f2963fa213 100644
--- a/arch/sh64/mach-harp/Makefile
+++ b/arch/sh64/mach-harp/Makefile
@@ -1,14 +1 @@
-#
-# Makefile for the ST50 Harp specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := harp.o
-
obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
diff --git a/arch/sh64/mach-harp/setup.c b/arch/sh64/mach-harp/setup.c
index fcd90afac29..05011cb369b 100644
--- a/arch/sh64/mach-harp/setup.c
+++ b/arch/sh64/mach-harp/setup.c
@@ -17,20 +17,10 @@
* lethal@linux-sh.org: 15th May 2003
* Use the generic procfs cpuinfo interface, just return a valid board name.
*/
-
-#include <linux/stddef.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
#include <linux/kernel.h>
-#include <asm/processor.h>
#include <asm/platform.h>
-#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/page.h>
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
/*
* Platform Dependent Interrupt Priorities.
@@ -78,8 +68,10 @@ struct resource io_resources[] = {
};
struct resource kram_resources[] = {
- { "Kernel code", 0, 0 }, /* These must be last in the array */
- { "Kernel data", 0, 0 } /* These must be last in the array */
+ /* These must be last in the array */
+ { .name = "Kernel code", .start = 0, .end = 0 },
+ /* These must be last in the array */
+ { .name = "Kernel data", .start = 0, .end = 0 }
};
struct resource xram_resources[] = {
@@ -95,13 +87,13 @@ struct sh64_platform platform_parms = {
.initial_root_dev = 0x0100,
.loader_type = 1,
.io_res_p = io_resources,
- .io_res_count = RES_COUNT(io_resources),
+ .io_res_count = ARRAY_SIZE(io_resources),
.kram_res_p = kram_resources,
- .kram_res_count = RES_COUNT(kram_resources),
+ .kram_res_count = ARRAY_SIZE(kram_resources),
.xram_res_p = xram_resources,
- .xram_res_count = RES_COUNT(xram_resources),
+ .xram_res_count = ARRAY_SIZE(xram_resources),
.rom_res_p = rom_resources,
- .rom_res_count = RES_COUNT(rom_resources),
+ .rom_res_count = ARRAY_SIZE(rom_resources),
};
int platform_int_priority[NR_INTC_IRQS] = {
@@ -135,4 +127,3 @@ const char *get_system_type(void)
{
return "ST50 Harp";
}
-
diff --git a/arch/sh64/mach-romram/Makefile b/arch/sh64/mach-romram/Makefile
deleted file mode 100644
index 02d05c05afa..00000000000
--- a/arch/sh64/mach-romram/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the SH-5 ROM/RAM specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := romram.o
-
-obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
diff --git a/arch/sh64/mach-romram/setup.c b/arch/sh64/mach-romram/setup.c
deleted file mode 100644
index eb98a1640cc..00000000000
--- a/arch/sh64/mach-romram/setup.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * arch/sh64/mach-romram/setup.c
- *
- * SH-5 ROM/RAM Platform Support
- *
- * This file handles the architecture-dependent parts of initialization
- *
- * Copyright (C) 2000, 2001 Paolo Alberelli
- *
- * benedict.gaster@superh.com: 3rd May 2002
- * Added support for ramdisk, removing statically linked romfs at the same time. *
- *
- * lethal@linux-sh.org: 15th May 2003
- * Use the generic procfs cpuinfo interface, just return a valid board name.
- *
- * Sean.McGoogan@superh.com 17th Feb 2004
- * copied from arch/sh64/mach-harp/setup.c
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <asm/processor.h>
-#include <asm/platform.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
-
-/*
- * Platform Dependent Interrupt Priorities.
- */
-
-/* Using defaults defined in irq.h */
-#define RES NO_PRIORITY /* Disabled */
-#define IR0 IRL0_PRIORITY /* IRLs */
-#define IR1 IRL1_PRIORITY
-#define IR2 IRL2_PRIORITY
-#define IR3 IRL3_PRIORITY
-#define PCA INTA_PRIORITY /* PCI Ints */
-#define PCB INTB_PRIORITY
-#define PCC INTC_PRIORITY
-#define PCD INTD_PRIORITY
-#define SER TOP_PRIORITY
-#define ERR TOP_PRIORITY
-#define PW0 TOP_PRIORITY
-#define PW1 TOP_PRIORITY
-#define PW2 TOP_PRIORITY
-#define PW3 TOP_PRIORITY
-#define DM0 NO_PRIORITY /* DMA Ints */
-#define DM1 NO_PRIORITY
-#define DM2 NO_PRIORITY
-#define DM3 NO_PRIORITY
-#define DAE NO_PRIORITY
-#define TU0 TIMER_PRIORITY /* TMU Ints */
-#define TU1 NO_PRIORITY
-#define TU2 NO_PRIORITY
-#define TI2 NO_PRIORITY
-#define ATI NO_PRIORITY /* RTC Ints */
-#define PRI NO_PRIORITY
-#define CUI RTC_PRIORITY
-#define ERI SCIF_PRIORITY /* SCIF Ints */
-#define RXI SCIF_PRIORITY
-#define BRI SCIF_PRIORITY
-#define TXI SCIF_PRIORITY
-#define ITI TOP_PRIORITY /* WDT Ints */
-
-/*
- * Platform dependent structures: maps and parms block.
- */
-struct resource io_resources[] = {
- /* To be updated with external devices */
-};
-
-struct resource kram_resources[] = {
- { "Kernel code", 0, 0 }, /* These must be last in the array */
- { "Kernel data", 0, 0 } /* These must be last in the array */
-};
-
-struct resource xram_resources[] = {
- /* To be updated with external devices */
-};
-
-struct resource rom_resources[] = {
- /* To be updated with external devices */
-};
-
-struct sh64_platform platform_parms = {
- .readonly_rootfs = 1,
- .initial_root_dev = 0x0100,
- .loader_type = 1,
- .io_res_p = io_resources,
- .io_res_count = RES_COUNT(io_resources),
- .kram_res_p = kram_resources,
- .kram_res_count = RES_COUNT(kram_resources),
- .xram_res_p = xram_resources,
- .xram_res_count = RES_COUNT(xram_resources),
- .rom_res_p = rom_resources,
- .rom_res_count = RES_COUNT(rom_resources),
-};
-
-int platform_int_priority[NR_INTC_IRQS] = {
- IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */
- RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */
- PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */
- RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */
- TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */
- RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */
- RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */
- RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */
-};
-
-void __init platform_setup(void)
-{
- /* ROM/RAM platform leaves the decision to head.S, for now */
- platform_parms.fpu_flags = fpu_in_use;
-}
-
-void __init platform_monitor(void)
-{
- /* Nothing yet .. */
-}
-
-void __init platform_reserve(void)
-{
- /* Nothing yet .. */
-}
-
-const char *get_system_type(void)
-{
- return "ROM/RAM";
-}
-
diff --git a/arch/sh64/mach-sim/Makefile b/arch/sh64/mach-sim/Makefile
index 819c4078fdc..2f2963fa213 100644
--- a/arch/sh64/mach-sim/Makefile
+++ b/arch/sh64/mach-sim/Makefile
@@ -1,14 +1 @@
-#
-# Makefile for the SH-5 Simulator specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := sim.o
-
obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
diff --git a/arch/sh64/mach-sim/setup.c b/arch/sh64/mach-sim/setup.c
index f09400c1ad1..e3386ec1ce1 100644
--- a/arch/sh64/mach-sim/setup.c
+++ b/arch/sh64/mach-sim/setup.c
@@ -14,46 +14,10 @@
* lethal@linux-sh.org: 15th May 2003
* Use the generic procfs cpuinfo interface, just return a valid board name.
*/
-
-#include <linux/stddef.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
-#include <asm/processor.h>
#include <asm/platform.h>
-#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/page.h>
-
-#ifdef CONFIG_BLK_DEV_INITRD
-#include "../rootfs/rootfs.h"
-#endif
-
-static __init void platform_monitor(void);
-static __init void platform_setup(void);
-static __init void platform_reserve(void);
-
-
-#define PHYS_MEMORY CONFIG_MEMORY_SIZE_IN_MB*1024*1024
-
-#if (PHYS_MEMORY < P1SEG_FOOTPRINT_RAM)
-#error "Invalid kernel configuration. Physical memory below footprint requirements."
-#endif
-
-#define RAM_DISK_START CONFIG_MEMORY_START+P1SEG_INITRD_BLOCK /* Top of 4MB */
-#ifdef PLATFORM_ROMFS_SIZE
-#define RAM_DISK_SIZE (PAGE_ALIGN(PLATFORM_ROMFS_SIZE)) /* Variable Top */
-#if ((RAM_DISK_START + RAM_DISK_SIZE) > (CONFIG_MEMORY_START + PHYS_MEMORY))
-#error "Invalid kernel configuration. ROM RootFS exceeding physical memory."
-#endif
-#else
-#define RAM_DISK_SIZE P1SEG_INITRD_BLOCK_SIZE /* Top of 4MB */
-#endif
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
/*
* Platform Dependent Interrupt Priorities.
@@ -101,8 +65,10 @@ struct resource io_resources[] = {
};
struct resource kram_resources[] = {
- { "Kernel code", 0, 0 }, /* These must be last in the array */
- { "Kernel data", 0, 0 } /* These must be last in the array */
+ /* These must be last in the array */
+ { .name = "Kernel code", .start = 0, .end = 0 },
+ /* These must be last in the array */
+ { .name = "Kernel data", .start = 0, .end = 0 }
};
struct resource xram_resources[] = {
@@ -117,16 +83,14 @@ struct sh64_platform platform_parms = {
.readonly_rootfs = 1,
.initial_root_dev = 0x0100,
.loader_type = 1,
- .initrd_start = RAM_DISK_START,
- .initrd_size = RAM_DISK_SIZE,
.io_res_p = io_resources,
- .io_res_count = RES_COUNT(io_resources),
+ .io_res_count = ARRAY_SIZE(io_resources),
.kram_res_p = kram_resources,
- .kram_res_count = RES_COUNT(kram_resources),
+ .kram_res_count = ARRAY_SIZE(kram_resources),
.xram_res_p = xram_resources,
- .xram_res_count = RES_COUNT(xram_resources),
+ .xram_res_count = ARRAY_SIZE(xram_resources),
.rom_res_p = rom_resources,
- .rom_res_count = RES_COUNT(rom_resources),
+ .rom_res_count = ARRAY_SIZE(rom_resources),
};
int platform_int_priority[NR_IRQS] = {
@@ -160,4 +124,3 @@ const char *get_system_type(void)
{
return "SH-5 Simulator";
}
-
diff --git a/arch/sh64/mm/Makefile b/arch/sh64/mm/Makefile
index ff19378ac90..d0e81363248 100644
--- a/arch/sh64/mm/Makefile
+++ b/arch/sh64/mm/Makefile
@@ -13,7 +13,8 @@
# unless it's something special (ie not a .c file).
#
-obj-y := init.o fault.o ioremap.o extable.o cache.o tlbmiss.o tlb.o
+obj-y := cache.o consistent.o extable.o fault.o init.o ioremap.o \
+ tlbmiss.o tlb.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
@@ -41,4 +42,3 @@ CFLAGS_tlbmiss.o += -ffixed-r7 \
-ffixed-r41 -ffixed-r42 -ffixed-r43 \
-ffixed-r60 -ffixed-r61 -ffixed-r62 \
-fomit-frame-pointer
-
diff --git a/arch/sh64/kernel/pci-dma.c b/arch/sh64/mm/consistent.c
index a9328f89475..8875a2a40da 100644
--- a/arch/sh64/kernel/pci-dma.c
+++ b/arch/sh64/mm/consistent.c
@@ -11,6 +11,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <asm/io.h>
void *consistent_alloc(struct pci_dev *hwdev, size_t size,
@@ -36,6 +37,7 @@ void *consistent_alloc(struct pci_dev *hwdev, size_t size,
return vp;
}
+EXPORT_SYMBOL(consistent_alloc);
void consistent_free(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
@@ -47,4 +49,4 @@ void consistent_free(struct pci_dev *hwdev, size_t size,
iounmap(vaddr);
}
-
+EXPORT_SYMBOL(consistent_free);
diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c
index 559717f30d1..21cf42de23e 100644
--- a/arch/sh64/mm/init.c
+++ b/arch/sh64/mm/init.c
@@ -22,10 +22,6 @@
#include <asm/pgtable.h>
#include <asm/tlb.h>
-#ifdef CONFIG_BLK_DEV_INITRD
-#include <linux/blk.h>
-#endif
-
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
/*
diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
index 990857756d4..535304e6601 100644
--- a/arch/sh64/mm/ioremap.c
+++ b/arch/sh64/mm/ioremap.c
@@ -19,11 +19,12 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/io.h>
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
#include <linux/ioport.h>
#include <linux/bootmem.h>
#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
static void shmedia_mapioaddr(unsigned long, unsigned long);
static unsigned long shmedia_ioremap(struct resource *, u32, int);
@@ -80,6 +81,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
}
return (void *) (offset + (char *)addr);
}
+EXPORT_SYMBOL(__ioremap);
void iounmap(void *addr)
{
@@ -94,6 +96,7 @@ void iounmap(void *addr)
kfree(area);
}
+EXPORT_SYMBOL(iounmap);
static struct resource shmedia_iomap = {
.name = "shmedia_iomap",
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug
index 120f6b52934..87dd496f15e 100644
--- a/arch/sparc/Kconfig.debug
+++ b/arch/sparc/Kconfig.debug
@@ -1,5 +1,9 @@
menu "Kernel hacking"
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ default y
+
source "lib/Kconfig.debug"
config DEBUG_STACK_USAGE
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index b76dc03fc31..722d67d3296 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -56,7 +56,7 @@
#define SMP_NOP2
#define SMP_NOP3
#endif /* SMP */
-unsigned long __local_irq_save(void)
+unsigned long __raw_local_irq_save(void)
{
unsigned long retval;
unsigned long tmp;
@@ -74,7 +74,7 @@ unsigned long __local_irq_save(void)
return retval;
}
-void local_irq_enable(void)
+void raw_local_irq_enable(void)
{
unsigned long tmp;
@@ -89,7 +89,7 @@ void local_irq_enable(void)
: "memory");
}
-void local_irq_restore(unsigned long old_psr)
+void raw_local_irq_restore(unsigned long old_psr)
{
unsigned long tmp;
@@ -105,9 +105,9 @@ void local_irq_restore(unsigned long old_psr)
: "memory");
}
-EXPORT_SYMBOL(__local_irq_save);
-EXPORT_SYMBOL(local_irq_enable);
-EXPORT_SYMBOL(local_irq_restore);
+EXPORT_SYMBOL(__raw_local_irq_save);
+EXPORT_SYMBOL(raw_local_irq_enable);
+EXPORT_SYMBOL(raw_local_irq_restore);
/*
* Dave Redman (djhr@tadpole.co.uk)
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 36383f73d68..fb2caef79ce 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -588,7 +588,10 @@ __setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
- drv->driver.name = drv->name;
+ if (!drv->driver.name)
+ drv->driver.name = drv->name;
+ if (!drv->driver.owner)
+ drv->driver.owner = drv->owner;
drv->driver.bus = bus;
/* register with core */
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 6a251332162..4bf78a5e8e0 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -347,9 +347,11 @@ static struct of_device_id clock_match[] = {
};
static struct of_platform_driver clock_driver = {
- .name = "clock",
.match_table = clock_match,
.probe = clock_probe,
+ .driver = {
+ .name = "clock",
+ },
};
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 15109c156e8..a8b4200f9cc 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -1,6 +1,7 @@
/* ld script to make SparcLinux kernel */
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc")
OUTPUT_ARCH(sparc)
@@ -8,84 +9,104 @@ ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
- . = 0x10000 + SIZEOF_HEADERS;
- .text 0xf0004000 :
- {
- _text = .;
- TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- *(.gnu.warning)
- } =0
- _etext = .;
- PROVIDE (etext = .);
- RODATA
- .data :
- {
- DATA_DATA
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- _edata = .;
- PROVIDE (edata = .);
- __start___fixup = .;
- .fixup : { *(.fixup) }
- __stop___fixup = .;
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
+ . = 0x10000 + SIZEOF_HEADERS;
+ .text 0xf0004000 :
+ {
+ _text = .;
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ *(.gnu.warning)
+ } = 0
+ _etext = .;
+ PROVIDE (etext = .);
+ RODATA
+ .data : {
+ DATA_DATA
+ CONSTRUCTORS
+ }
+ .data1 : {
+ *(.data1)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
- NOTES
+ .fixup : {
+ __start___fixup = .;
+ *(.fixup)
+ __stop___fixup = .;
+ }
+ __ex_table : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
- . = ALIGN(4096);
- __init_begin = .;
- _sinittext = .;
- .init.text : {
- *(.init.text)
- }
- _einittext = .;
- __init_text_end = .;
- .init.data : { *(.init.data) }
- . = ALIGN(16);
- __setup_start = .;
- .init.setup : { *(.init.setup) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : {
- INITCALLS
- }
- __initcall_end = .;
- __con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
- __con_initcall_end = .;
- SECURITY_INIT
+ NOTES
+
+ . = ALIGN(PAGE_SIZE);
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
+ __init_text_end = .;
+ .init.data : {
+ *(.init.data)
+ }
+ . = ALIGN(16);
+ .init.setup : {
+ __setup_start = .;
+ *(.init.setup)
+ __setup_end = .;
+ }
+ .initcall.init : {
+ __initcall_start = .;
+ INITCALLS
+ __initcall_end = .;
+ }
+ .con_initcall.init : {
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+ __con_initcall_end = .;
+ }
+ SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(4096);
- __initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
- __initramfs_end = .;
+ . = ALIGN(PAGE_SIZE);
+ .init.ramfs : {
+ __initramfs_start = .;
+ *(.init.ramfs)
+ __initramfs_end = .;
+ }
#endif
- PERCPU(4096)
- . = ALIGN(4096);
- __init_end = .;
- . = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+ PERCPU(PAGE_SIZE)
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
+ . = ALIGN(32);
+ .data.cacheline_aligned : {
+ *(.data.cacheline_aligned)
+ }
- STABS_DEBUG
+ __bss_start = .;
+ .sbss : {
+ *(.sbss)
+ *(.scommon) }
+ .bss : {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+ /DISCARD/ : {
+ *(.exit.text)
+ *(.exit.data)
+ *(.exitcall.exit)
+ }
- DWARF_DEBUG
+ STABS_DEBUG
+ DWARF_DEBUG
}
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 7d07297db87..1aa2c4048e4 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc6
-# Sun Sep 16 09:52:11 2007
+# Linux kernel version: 2.6.23
+# Sat Oct 13 21:53:54 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -69,7 +69,6 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
@@ -89,6 +88,7 @@ CONFIG_KMOD=y
CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_BLK_DEV_BSG=y
+CONFIG_BLOCK_COMPAT=y
#
# IO Schedulers
@@ -111,6 +111,7 @@ CONFIG_GENERIC_HARDIRQS=y
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_SMP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=m
@@ -119,6 +120,8 @@ CONFIG_CPU_FREQ_STAT=m
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=m
@@ -213,6 +216,7 @@ CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -304,6 +308,7 @@ CONFIG_NET_TCPPROBE=m
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
@@ -355,6 +360,11 @@ CONFIG_IDE_PROC_FS=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_IDEPCI_PCIBUS_ORDER=y
@@ -391,7 +401,6 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_TC86C001 is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -505,6 +514,8 @@ CONFIG_DUMMY=m
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
@@ -518,13 +529,16 @@ CONFIG_CASSINI=m
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
@@ -543,6 +557,7 @@ CONFIG_NETDEV_1000=y
CONFIG_E1000=m
CONFIG_E1000_NAPI=y
# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
@@ -560,11 +575,14 @@ CONFIG_BNX2=m
CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
# CONFIG_TR is not set
#
@@ -820,6 +838,12 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
@@ -1399,6 +1423,7 @@ CONFIG_ASYNC_MEMCPY=m
CONFIG_ASYNC_XOR=m
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
@@ -1417,6 +1442,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_XTS=m
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
@@ -1431,11 +1457,13 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_HW=y
#
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 40d2f3aae91..112c46e6657 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
+obj-$(CONFIG_PCI_MSI) += pci_msi.o
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 7b379761e9f..c55f0293eac 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -148,9 +148,11 @@ static int __devinit auxio_probe(struct of_device *dev, const struct of_device_i
}
static struct of_platform_driver auxio_driver = {
- .name = "auxio",
.match_table = auxio_match,
.probe = auxio_probe,
+ .driver = {
+ .name = "auxio",
+ },
};
static int __init auxio_init(void)
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 8059531bf0a..c9b0d7af64a 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -429,16 +429,16 @@ do_ivec:
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
- sethi %hi(ivector_table), %g2
- sllx %g3, 3, %g3
- or %g2, %lo(ivector_table), %g2
+ sethi %hi(ivector_table_pa), %g2
+ ldx [%g2 + %lo(ivector_table_pa)], %g2
+ sllx %g3, 4, %g3
add %g2, %g3, %g3
- TRAP_LOAD_IRQ_WORK(%g6, %g1)
+ TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
- lduw [%g6], %g5 /* g5 = irq_work(cpu) */
- stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
- stw %g3, [%g6] /* irq_work(cpu) = bucket */
+ ldx [%g6], %g5
+ stxa %g5, [%g3] ASI_PHYS_USE_EC
+ stx %g3, [%g6]
wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
retry
do_ivec_xcall:
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 23956096b3b..f3922e5a89f 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -21,7 +21,6 @@
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
-#include <linux/msi.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -43,6 +42,7 @@
#include <asm/auxio.h>
#include <asm/head.h>
#include <asm/hypervisor.h>
+#include <asm/cacheflush.h>
/* UPA nodes send interrupt packet to UltraSparc with first data reg
* value low 5 (7 on Starfire) bits holding the IRQ identifier being
@@ -52,86 +52,128 @@
* To make processing these packets efficient and race free we use
* an array of irq buckets below. The interrupt vector handler in
* entry.S feeds incoming packets into per-cpu pil-indexed lists.
- * The IVEC handler does not need to act atomically, the PIL dispatch
- * code uses CAS to get an atomic snapshot of the list and clear it
- * at the same time.
*
* If you make changes to ino_bucket, please update hand coded assembler
* of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
*/
struct ino_bucket {
- /* Next handler in per-CPU IRQ worklist. We know that
- * bucket pointers have the high 32-bits clear, so to
- * save space we only store the bits we need.
- */
-/*0x00*/unsigned int irq_chain;
+/*0x00*/unsigned long __irq_chain_pa;
/* Virtual interrupt number assigned to this INO. */
-/*0x04*/unsigned int virt_irq;
+/*0x08*/unsigned int __virt_irq;
+/*0x0c*/unsigned int __pad;
};
#define NUM_IVECS (IMAP_INR + 1)
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
-
-#define __irq_ino(irq) \
- (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0])
-#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
-#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
-
-/* This has to be in the main kernel image, it cannot be
- * turned into per-cpu data. The reason is that the main
- * kernel image is locked into the TLB and this structure
- * is accessed from the vectored interrupt trap handler. If
- * access to this structure takes a TLB miss it could cause
- * the 5-level sparc v9 trap stack to overflow.
+struct ino_bucket *ivector_table;
+unsigned long ivector_table_pa;
+
+/* On several sun4u processors, it is illegal to mix bypass and
+ * non-bypass accesses. Therefore we access all INO buckets
+ * using bypass accesses only.
*/
-#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
+static unsigned long bucket_get_chain_pa(unsigned long bucket_pa)
+{
+ unsigned long ret;
+
+ __asm__ __volatile__("ldxa [%1] %2, %0"
+ : "=&r" (ret)
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __irq_chain_pa)),
+ "i" (ASI_PHYS_USE_EC));
+
+ return ret;
+}
+
+static void bucket_clear_chain_pa(unsigned long bucket_pa)
+{
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
+ : /* no outputs */
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __irq_chain_pa)),
+ "i" (ASI_PHYS_USE_EC));
+}
+
+static unsigned int bucket_get_virt_irq(unsigned long bucket_pa)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=&r" (ret)
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __virt_irq)),
+ "i" (ASI_PHYS_USE_EC));
+
+ return ret;
+}
+
+static void bucket_set_virt_irq(unsigned long bucket_pa,
+ unsigned int virt_irq)
+{
+ __asm__ __volatile__("stwa %0, [%1] %2"
+ : /* no outputs */
+ : "r" (virt_irq),
+ "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __virt_irq)),
+ "i" (ASI_PHYS_USE_EC));
+}
+
+#define irq_work_pa(__cpu) &(trap_block[(__cpu)].irq_worklist_pa)
static struct {
- unsigned int irq;
unsigned int dev_handle;
unsigned int dev_ino;
-} virt_to_real_irq_table[NR_IRQS];
+ unsigned int in_use;
+} virt_irq_table[NR_IRQS];
+static DEFINE_SPINLOCK(virt_irq_alloc_lock);
-static unsigned char virt_irq_alloc(unsigned int real_irq)
+unsigned char virt_irq_alloc(unsigned int dev_handle,
+ unsigned int dev_ino)
{
+ unsigned long flags;
unsigned char ent;
BUILD_BUG_ON(NR_IRQS >= 256);
+ spin_lock_irqsave(&virt_irq_alloc_lock, flags);
+
for (ent = 1; ent < NR_IRQS; ent++) {
- if (!virt_to_real_irq_table[ent].irq)
+ if (!virt_irq_table[ent].in_use)
break;
}
if (ent >= NR_IRQS) {
printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
- return 0;
+ ent = 0;
+ } else {
+ virt_irq_table[ent].dev_handle = dev_handle;
+ virt_irq_table[ent].dev_ino = dev_ino;
+ virt_irq_table[ent].in_use = 1;
}
- virt_to_real_irq_table[ent].irq = real_irq;
+ spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
return ent;
}
#ifdef CONFIG_PCI_MSI
-static void virt_irq_free(unsigned int virt_irq)
+void virt_irq_free(unsigned int virt_irq)
{
- unsigned int real_irq;
+ unsigned long flags;
if (virt_irq >= NR_IRQS)
return;
- real_irq = virt_to_real_irq_table[virt_irq].irq;
- virt_to_real_irq_table[virt_irq].irq = 0;
+ spin_lock_irqsave(&virt_irq_alloc_lock, flags);
- __bucket(real_irq)->virt_irq = 0;
-}
-#endif
+ virt_irq_table[virt_irq].in_use = 0;
-static unsigned int virt_to_real_irq(unsigned char virt_irq)
-{
- return virt_to_real_irq_table[virt_irq].irq;
+ spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
}
+#endif
/*
* /proc/interrupts printing:
@@ -217,38 +259,8 @@ struct irq_handler_data {
void (*pre_handler)(unsigned int, void *, void *);
void *pre_handler_arg1;
void *pre_handler_arg2;
-
- u32 msi;
};
-void sparc64_set_msi(unsigned int virt_irq, u32 msi)
-{
- struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-
- if (data)
- data->msi = msi;
-}
-
-u32 sparc64_get_msi(unsigned int virt_irq)
-{
- struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-
- if (data)
- return data->msi;
- return 0xffffffff;
-}
-
-static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
-{
- unsigned int real_irq = virt_to_real_irq(virt_irq);
- struct ino_bucket *bucket = NULL;
-
- if (likely(real_irq))
- bucket = __bucket(real_irq);
-
- return bucket;
-}
-
#ifdef CONFIG_SMP
static int irq_choose_cpu(unsigned int virt_irq)
{
@@ -348,201 +360,152 @@ static void sun4u_irq_end(unsigned int virt_irq)
static void sun4v_irq_enable(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
-
- if (likely(bucket)) {
- unsigned long cpuid;
- int err;
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ unsigned long cpuid = irq_choose_cpu(virt_irq);
+ int err;
- cpuid = irq_choose_cpu(virt_irq);
-
- err = sun4v_intr_settarget(ino, cpuid);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
- "err(%d)\n", ino, cpuid, err);
- err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_setstate(%x): "
- "err(%d)\n", ino, err);
- err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
- ino, err);
- }
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
+ err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
+ ino, err);
}
static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ unsigned long cpuid = irq_choose_cpu(virt_irq);
+ int err;
- if (likely(bucket)) {
- unsigned long cpuid;
- int err;
-
- cpuid = irq_choose_cpu(virt_irq);
-
- err = sun4v_intr_settarget(ino, cpuid);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
- "err(%d)\n", ino, cpuid, err);
- }
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
}
static void sun4v_irq_disable(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
-
- if (likely(bucket)) {
- int err;
-
- err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_setenabled(%x): "
- "err(%d)\n", ino, err);
- }
-}
-
-#ifdef CONFIG_PCI_MSI
-static void sun4v_msi_enable(unsigned int virt_irq)
-{
- sun4v_irq_enable(virt_irq);
- unmask_msi_irq(virt_irq);
-}
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ int err;
-static void sun4v_msi_disable(unsigned int virt_irq)
-{
- mask_msi_irq(virt_irq);
- sun4v_irq_disable(virt_irq);
+ err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): "
+ "err(%d)\n", ino, err);
}
-#endif
static void sun4v_irq_end(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
struct irq_desc *desc = irq_desc + virt_irq;
+ int err;
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
return;
- if (likely(bucket)) {
- int err;
-
- err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_intr_setstate(%x): "
- "err(%d)\n", ino, err);
- }
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
}
static void sun4v_virq_enable(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-
- if (likely(bucket)) {
- unsigned long cpuid, dev_handle, dev_ino;
- int err;
-
- cpuid = irq_choose_cpu(virt_irq);
-
- dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
- dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
- err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
- "err(%d)\n",
- dev_handle, dev_ino, cpuid, err);
- err = sun4v_vintr_set_state(dev_handle, dev_ino,
- HV_INTR_STATE_IDLE);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
- "HV_INTR_STATE_IDLE): err(%d)\n",
- dev_handle, dev_ino, err);
- err = sun4v_vintr_set_valid(dev_handle, dev_ino,
- HV_INTR_ENABLED);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
- "HV_INTR_ENABLED): err(%d)\n",
- dev_handle, dev_ino, err);
- }
+ unsigned long cpuid, dev_handle, dev_ino;
+ int err;
+
+ cpuid = irq_choose_cpu(virt_irq);
+
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+ "err(%d)\n",
+ dev_handle, dev_ino, cpuid, err);
+ err = sun4v_vintr_set_state(dev_handle, dev_ino,
+ HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_STATE_IDLE): err(%d)\n",
+ dev_handle, dev_ino, err);
+ err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+ HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_ENABLED): err(%d)\n",
+ dev_handle, dev_ino, err);
}
static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned long cpuid, dev_handle, dev_ino;
+ int err;
- if (likely(bucket)) {
- unsigned long cpuid, dev_handle, dev_ino;
- int err;
+ cpuid = irq_choose_cpu(virt_irq);
- cpuid = irq_choose_cpu(virt_irq);
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
- dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
- dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
- err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
- "err(%d)\n",
- dev_handle, dev_ino, cpuid, err);
- }
+ err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+ "err(%d)\n",
+ dev_handle, dev_ino, cpuid, err);
}
static void sun4v_virq_disable(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned long dev_handle, dev_ino;
+ int err;
- if (likely(bucket)) {
- unsigned long dev_handle, dev_ino;
- int err;
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
- dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
- dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
- err = sun4v_vintr_set_valid(dev_handle, dev_ino,
- HV_INTR_DISABLED);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
- "HV_INTR_DISABLED): err(%d)\n",
- dev_handle, dev_ino, err);
- }
+ err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+ HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_DISABLED): err(%d)\n",
+ dev_handle, dev_ino, err);
}
static void sun4v_virq_end(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
struct irq_desc *desc = irq_desc + virt_irq;
+ unsigned long dev_handle, dev_ino;
+ int err;
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
return;
- if (likely(bucket)) {
- unsigned long dev_handle, dev_ino;
- int err;
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
- dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
- dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
- err = sun4v_vintr_set_state(dev_handle, dev_ino,
- HV_INTR_STATE_IDLE);
- if (err != HV_EOK)
- printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
- "HV_INTR_STATE_IDLE): err(%d)\n",
- dev_handle, dev_ino, err);
- }
+ err = sun4v_vintr_set_state(dev_handle, dev_ino,
+ HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_STATE_IDLE): err(%d)\n",
+ dev_handle, dev_ino, err);
}
static void run_pre_handler(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ unsigned int ino;
+ ino = virt_irq_table[virt_irq].dev_ino;
if (likely(data->pre_handler)) {
- data->pre_handler(__irq_ino(__irq(bucket)),
+ data->pre_handler(ino,
data->pre_handler_arg1,
data->pre_handler_arg2);
}
@@ -573,28 +536,6 @@ static struct irq_chip sun4v_irq = {
.set_affinity = sun4v_set_affinity,
};
-static struct irq_chip sun4v_irq_ack = {
- .typename = "sun4v+ack",
- .enable = sun4v_irq_enable,
- .disable = sun4v_irq_disable,
- .ack = run_pre_handler,
- .end = sun4v_irq_end,
- .set_affinity = sun4v_set_affinity,
-};
-
-#ifdef CONFIG_PCI_MSI
-static struct irq_chip sun4v_msi = {
- .typename = "sun4v+msi",
- .mask = mask_msi_irq,
- .unmask = unmask_msi_irq,
- .enable = sun4v_msi_enable,
- .disable = sun4v_msi_disable,
- .ack = run_pre_handler,
- .end = sun4v_irq_end,
- .set_affinity = sun4v_set_affinity,
-};
-#endif
-
static struct irq_chip sun4v_virq = {
.typename = "vsun4v",
.enable = sun4v_virq_enable,
@@ -603,59 +544,48 @@ static struct irq_chip sun4v_virq = {
.set_affinity = sun4v_virt_set_affinity,
};
-static struct irq_chip sun4v_virq_ack = {
- .typename = "vsun4v+ack",
- .enable = sun4v_virq_enable,
- .disable = sun4v_virq_disable,
- .ack = run_pre_handler,
- .end = sun4v_virq_end,
- .set_affinity = sun4v_virt_set_affinity,
-};
-
void irq_install_pre_handler(int virt_irq,
void (*func)(unsigned int, void *, void *),
void *arg1, void *arg2)
{
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
- struct irq_chip *chip;
+ struct irq_chip *chip = get_irq_chip(virt_irq);
+
+ if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
+ printk(KERN_ERR "IRQ: Trying to install pre-handler on "
+ "sun4v irq %u\n", virt_irq);
+ return;
+ }
data->pre_handler = func;
data->pre_handler_arg1 = arg1;
data->pre_handler_arg2 = arg2;
- chip = get_irq_chip(virt_irq);
- if (chip == &sun4u_irq_ack ||
- chip == &sun4v_irq_ack ||
- chip == &sun4v_virq_ack
-#ifdef CONFIG_PCI_MSI
- || chip == &sun4v_msi
-#endif
- )
+ if (chip == &sun4u_irq_ack)
return;
- chip = (chip == &sun4u_irq ?
- &sun4u_irq_ack :
- (chip == &sun4v_irq ?
- &sun4v_irq_ack : &sun4v_virq_ack));
- set_irq_chip(virt_irq, chip);
+ set_irq_chip(virt_irq, &sun4u_irq_ack);
}
unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
+ unsigned int virt_irq;
int ino;
BUG_ON(tlb_type == hypervisor);
ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
bucket = &ivector_table[ino];
- if (!bucket->virt_irq) {
- bucket->virt_irq = virt_irq_alloc(__irq(bucket));
- set_irq_chip(bucket->virt_irq, &sun4u_irq);
+ virt_irq = bucket_get_virt_irq(__pa(bucket));
+ if (!virt_irq) {
+ virt_irq = virt_irq_alloc(0, ino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+ set_irq_chip(virt_irq, &sun4u_irq);
}
- data = get_irq_chip_data(bucket->virt_irq);
+ data = get_irq_chip_data(virt_irq);
if (unlikely(data))
goto out;
@@ -664,13 +594,13 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
- set_irq_chip_data(bucket->virt_irq, data);
+ set_irq_chip_data(virt_irq, data);
data->imap = imap;
data->iclr = iclr;
out:
- return bucket->virt_irq;
+ return virt_irq;
}
static unsigned int sun4v_build_common(unsigned long sysino,
@@ -678,16 +608,19 @@ static unsigned int sun4v_build_common(unsigned long sysino,
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
+ unsigned int virt_irq;
BUG_ON(tlb_type != hypervisor);
bucket = &ivector_table[sysino];
- if (!bucket->virt_irq) {
- bucket->virt_irq = virt_irq_alloc(__irq(bucket));
- set_irq_chip(bucket->virt_irq, chip);
+ virt_irq = bucket_get_virt_irq(__pa(bucket));
+ if (!virt_irq) {
+ virt_irq = virt_irq_alloc(0, sysino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+ set_irq_chip(virt_irq, chip);
}
- data = get_irq_chip_data(bucket->virt_irq);
+ data = get_irq_chip_data(virt_irq);
if (unlikely(data))
goto out;
@@ -696,7 +629,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
- set_irq_chip_data(bucket->virt_irq, data);
+ set_irq_chip_data(virt_irq, data);
/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
@@ -706,7 +639,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
data->iclr = ~0UL;
out:
- return bucket->virt_irq;
+ return virt_irq;
}
unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
@@ -718,86 +651,52 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
{
- unsigned long sysino, hv_err;
- unsigned int virq;
-
- BUG_ON(devhandle & devino);
-
- sysino = devhandle | devino;
- BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
-
- hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
- if (hv_err) {
- prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
- "err=%lu\n", devhandle, devino, hv_err);
- prom_halt();
- }
-
- virq = sun4v_build_common(sysino, &sun4v_virq);
-
- virt_to_real_irq_table[virq].dev_handle = devhandle;
- virt_to_real_irq_table[virq].dev_ino = devino;
-
- return virq;
-}
-
-#ifdef CONFIG_PCI_MSI
-unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
- unsigned int msi_start, unsigned int msi_end)
-{
- struct ino_bucket *bucket;
struct irq_handler_data *data;
- unsigned long sysino;
- unsigned int devino;
-
- BUG_ON(tlb_type != hypervisor);
-
- /* Find a free devino in the given range. */
- for (devino = msi_start; devino < msi_end; devino++) {
- sysino = sun4v_devino_to_sysino(devhandle, devino);
- bucket = &ivector_table[sysino];
- if (!bucket->virt_irq)
- break;
- }
- if (devino >= msi_end)
- return -ENOSPC;
+ struct ino_bucket *bucket;
+ unsigned long hv_err, cookie;
+ unsigned int virt_irq;
- sysino = sun4v_devino_to_sysino(devhandle, devino);
- bucket = &ivector_table[sysino];
- bucket->virt_irq = virt_irq_alloc(__irq(bucket));
- *virt_irq_p = bucket->virt_irq;
- set_irq_chip(bucket->virt_irq, &sun4v_msi);
+ bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
+ if (unlikely(!bucket))
+ return 0;
+ __flush_dcache_range((unsigned long) bucket,
+ ((unsigned long) bucket +
+ sizeof(struct ino_bucket)));
- data = get_irq_chip_data(bucket->virt_irq);
- if (unlikely(data))
- return devino;
+ virt_irq = virt_irq_alloc(devhandle, devino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+ set_irq_chip(virt_irq, &sun4v_virq);
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
- if (unlikely(!data)) {
- virt_irq_free(*virt_irq_p);
- return -ENOMEM;
- }
- set_irq_chip_data(bucket->virt_irq, data);
+ if (unlikely(!data))
+ return 0;
+
+ set_irq_chip_data(virt_irq, data);
+ /* Catch accidental accesses to these things. IMAP/ICLR handling
+ * is done by hypervisor calls on sun4v platforms, not by direct
+ * register accesses.
+ */
data->imap = ~0UL;
data->iclr = ~0UL;
- return devino;
-}
+ cookie = ~__pa(bucket);
+ hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
+ if (hv_err) {
+ prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
+ "err=%lu\n", devhandle, devino, hv_err);
+ prom_halt();
+ }
-void sun4v_destroy_msi(unsigned int virt_irq)
-{
- virt_irq_free(virt_irq);
+ return virt_irq;
}
-#endif
void ack_bad_irq(unsigned int virt_irq)
{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = 0xdeadbeef;
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
- if (bucket)
- ino = bucket - &ivector_table[0];
+ if (!ino)
+ ino = 0xdeadbeef;
printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n",
ino, virt_irq);
@@ -805,7 +704,7 @@ void ack_bad_irq(unsigned int virt_irq)
void handler_irq(int irq, struct pt_regs *regs)
{
- struct ino_bucket *bucket;
+ unsigned long pstate, bucket_pa;
struct pt_regs *old_regs;
clear_softint(1 << irq);
@@ -813,15 +712,28 @@ void handler_irq(int irq, struct pt_regs *regs)
old_regs = set_irq_regs(regs);
irq_enter();
- /* Sliiiick... */
- bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0));
- while (bucket) {
- struct ino_bucket *next = __bucket(bucket->irq_chain);
+ /* Grab an atomic snapshot of the pending IVECs. */
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %3, %%pstate\n\t"
+ "ldx [%2], %1\n\t"
+ "stx %%g0, [%2]\n\t"
+ "wrpr %0, 0x0, %%pstate\n\t"
+ : "=&r" (pstate), "=&r" (bucket_pa)
+ : "r" (irq_work_pa(smp_processor_id())),
+ "i" (PSTATE_IE)
+ : "memory");
+
+ while (bucket_pa) {
+ unsigned long next_pa;
+ unsigned int virt_irq;
- bucket->irq_chain = 0;
- __do_IRQ(bucket->virt_irq);
+ next_pa = bucket_get_chain_pa(bucket_pa);
+ virt_irq = bucket_get_virt_irq(bucket_pa);
+ bucket_clear_chain_pa(bucket_pa);
- bucket = next;
+ __do_IRQ(virt_irq);
+
+ bucket_pa = next_pa;
}
irq_exit();
@@ -921,7 +833,7 @@ void init_irqwork_curcpu(void)
{
int cpu = hard_smp_processor_id();
- trap_block[cpu].irq_worklist = 0;
+ trap_block[cpu].irq_worklist_pa = 0UL;
}
/* Please be very careful with register_one_mondo() and
@@ -1035,9 +947,21 @@ static struct irqaction timer_irq_action = {
/* Only invoked on boot processor. */
void __init init_IRQ(void)
{
+ unsigned long size;
+
map_prom_timers();
kill_prom_timer();
- memset(&ivector_table[0], 0, sizeof(ivector_table));
+
+ size = sizeof(struct ino_bucket) * NUM_IVECS;
+ ivector_table = alloc_bootmem_low(size);
+ if (!ivector_table) {
+ prom_printf("Fatal error, cannot allocate ivector_table\n");
+ prom_halt();
+ }
+ __flush_dcache_range((unsigned long) ivector_table,
+ ((unsigned long) ivector_table) + size);
+
+ ivector_table_pa = __pa(ivector_table);
if (tlb_type == hypervisor)
sun4v_init_mondo_queues();
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 4cc77485f53..42d779866fb 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -872,7 +872,10 @@ __setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
- drv->driver.name = drv->name;
+ if (!drv->driver.name)
+ drv->driver.name = drv->name;
+ if (!drv->driver.owner)
+ drv->driver.owner = drv->owner;
drv->driver.bus = bus;
/* register with core */
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index e8dac81d8a0..9b808640a19 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -29,8 +29,6 @@
#include "pci_impl.h"
-unsigned long pci_memspace_mask = 0xffffffffUL;
-
#ifndef CONFIG_PCI
/* A "nop" PCI implementation. */
asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
@@ -1066,8 +1064,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
return 0;
}
-/* Adjust vm_pgoff of VMA such that it is the physical page offset corresponding
- * to the 32-bit pci bus offset for DEV requested by the user.
+/* Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
*
* Basically, the user finds the base address for his device which he wishes
* to mmap. They read the 32-bit value from the config space base register,
@@ -1076,21 +1074,35 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
*
* Returns negative error code on failure, zero on success.
*/
-static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+static int __pci_mmap_make_offset(struct pci_dev *pdev,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long user32 = user_offset & pci_memspace_mask;
- unsigned long largest_base, this_base, addr32;
- int i;
+ unsigned long user_paddr, user_size;
+ int i, err;
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
- return __pci_mmap_make_offset_bus(dev, vma, mmap_state);
+ /* First compute the physical address in vma->vm_pgoff,
+ * making sure the user offset is within range in the
+ * appropriate PCI space.
+ */
+ err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
+ if (err)
+ return err;
+
+ /* If this is a mapping on a host bridge, any address
+ * is OK.
+ */
+ if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ return err;
+
+ /* Otherwise make sure it's in the range for one of the
+ * device's resources.
+ */
+ user_paddr = vma->vm_pgoff << PAGE_SHIFT;
+ user_size = vma->vm_end - vma->vm_start;
- /* Figure out which base address this is for. */
- largest_base = 0UL;
for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &dev->resource[i];
+ struct resource *rp = &pdev->resource[i];
/* Active? */
if (!rp->flags)
@@ -1108,26 +1120,14 @@ static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vm
continue;
}
- this_base = rp->start;
-
- addr32 = (this_base & PAGE_MASK) & pci_memspace_mask;
-
- if (mmap_state == pci_mmap_io)
- addr32 &= 0xffffff;
-
- if (addr32 <= user32 && this_base > largest_base)
- largest_base = this_base;
+ if ((rp->start <= user_paddr) &&
+ (user_paddr + user_size) <= (rp->end + 1UL))
+ break;
}
- if (largest_base == 0UL)
+ if (i > PCI_ROM_RESOURCE)
return -EINVAL;
- /* Now construct the final physical address. */
- if (mmap_state == pci_mmap_io)
- vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT);
- else
- vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT);
-
return 0;
}
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index 14d67fe21ab..fef3b37487b 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -6,9 +6,12 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/irq.h>
#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/irq.h>
#include "pci_impl.h"
@@ -84,6 +87,266 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
return 0;
}
+#ifdef CONFIG_PCI_MSI
+struct pci_msiq_entry {
+ u64 word0;
+#define MSIQ_WORD0_RESV 0x8000000000000000UL
+#define MSIQ_WORD0_FMT_TYPE 0x7f00000000000000UL
+#define MSIQ_WORD0_FMT_TYPE_SHIFT 56
+#define MSIQ_WORD0_LEN 0x00ffc00000000000UL
+#define MSIQ_WORD0_LEN_SHIFT 46
+#define MSIQ_WORD0_ADDR0 0x00003fff00000000UL
+#define MSIQ_WORD0_ADDR0_SHIFT 32
+#define MSIQ_WORD0_RID 0x00000000ffff0000UL
+#define MSIQ_WORD0_RID_SHIFT 16
+#define MSIQ_WORD0_DATA0 0x000000000000ffffUL
+#define MSIQ_WORD0_DATA0_SHIFT 0
+
+#define MSIQ_TYPE_MSG 0x6
+#define MSIQ_TYPE_MSI32 0xb
+#define MSIQ_TYPE_MSI64 0xf
+
+ u64 word1;
+#define MSIQ_WORD1_ADDR1 0xffffffffffff0000UL
+#define MSIQ_WORD1_ADDR1_SHIFT 16
+#define MSIQ_WORD1_DATA1 0x000000000000ffffUL
+#define MSIQ_WORD1_DATA1_SHIFT 0
+
+ u64 resv[6];
+};
+
+/* All MSI registers are offset from pbm->pbm_regs */
+#define EVENT_QUEUE_BASE_ADDR_REG 0x010000UL
+#define EVENT_QUEUE_BASE_ADDR_ALL_ONES 0xfffc000000000000UL
+
+#define EVENT_QUEUE_CONTROL_SET(EQ) (0x011000UL + (EQ) * 0x8UL)
+#define EVENT_QUEUE_CONTROL_SET_OFLOW 0x0200000000000000UL
+#define EVENT_QUEUE_CONTROL_SET_EN 0x0000100000000000UL
+
+#define EVENT_QUEUE_CONTROL_CLEAR(EQ) (0x011200UL + (EQ) * 0x8UL)
+#define EVENT_QUEUE_CONTROL_CLEAR_OF 0x0200000000000000UL
+#define EVENT_QUEUE_CONTROL_CLEAR_E2I 0x0000800000000000UL
+#define EVENT_QUEUE_CONTROL_CLEAR_DIS 0x0000100000000000UL
+
+#define EVENT_QUEUE_STATE(EQ) (0x011400UL + (EQ) * 0x8UL)
+#define EVENT_QUEUE_STATE_MASK 0x0000000000000007UL
+#define EVENT_QUEUE_STATE_IDLE 0x0000000000000001UL
+#define EVENT_QUEUE_STATE_ACTIVE 0x0000000000000002UL
+#define EVENT_QUEUE_STATE_ERROR 0x0000000000000004UL
+
+#define EVENT_QUEUE_TAIL(EQ) (0x011600UL + (EQ) * 0x8UL)
+#define EVENT_QUEUE_TAIL_OFLOW 0x0200000000000000UL
+#define EVENT_QUEUE_TAIL_VAL 0x000000000000007fUL
+
+#define EVENT_QUEUE_HEAD(EQ) (0x011800UL + (EQ) * 0x8UL)
+#define EVENT_QUEUE_HEAD_VAL 0x000000000000007fUL
+
+#define MSI_MAP(MSI) (0x020000UL + (MSI) * 0x8UL)
+#define MSI_MAP_VALID 0x8000000000000000UL
+#define MSI_MAP_EQWR_N 0x4000000000000000UL
+#define MSI_MAP_EQNUM 0x000000000000003fUL
+
+#define MSI_CLEAR(MSI) (0x028000UL + (MSI) * 0x8UL)
+#define MSI_CLEAR_EQWR_N 0x4000000000000000UL
+
+#define IMONDO_DATA0 0x02C000UL
+#define IMONDO_DATA0_DATA 0xffffffffffffffc0UL
+
+#define IMONDO_DATA1 0x02C008UL
+#define IMONDO_DATA1_DATA 0xffffffffffffffffUL
+
+#define MSI_32BIT_ADDR 0x034000UL
+#define MSI_32BIT_ADDR_VAL 0x00000000ffff0000UL
+
+#define MSI_64BIT_ADDR 0x034008UL
+#define MSI_64BIT_ADDR_VAL 0xffffffffffff0000UL
+
+static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long *head)
+{
+ *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+ return 0;
+}
+
+static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long *head, unsigned long *msi)
+{
+ unsigned long type_fmt, type, msi_num;
+ struct pci_msiq_entry *base, *ep;
+
+ base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) * 8192));
+ ep = &base[*head];
+
+ if ((ep->word0 & MSIQ_WORD0_FMT_TYPE) == 0)
+ return 0;
+
+ type_fmt = ((ep->word0 & MSIQ_WORD0_FMT_TYPE) >>
+ MSIQ_WORD0_FMT_TYPE_SHIFT);
+ type = (type_fmt >> 3);
+ if (unlikely(type != MSIQ_TYPE_MSI32 &&
+ type != MSIQ_TYPE_MSI64))
+ return -EINVAL;
+
+ *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
+ MSIQ_WORD0_DATA0_SHIFT);
+
+ fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
+ MSI_CLEAR_EQWR_N);
+
+ /* Clear the entry. */
+ ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
+
+ /* Go to next entry in ring. */
+ (*head)++;
+ if (*head >= pbm->msiq_ent_count)
+ *head = 0;
+
+ return 1;
+}
+
+static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long head)
+{
+ fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+ return 0;
+}
+
+static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long msi, int is_msi64)
+{
+ u64 val;
+
+ val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val &= ~(MSI_MAP_EQNUM);
+ val |= msiqid;
+ fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+ fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
+ MSI_CLEAR_EQWR_N);
+
+ val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val |= MSI_MAP_VALID;
+ fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+ return 0;
+}
+
+static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
+{
+ unsigned long msiqid;
+ u64 val;
+
+ val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ msiqid = (val & MSI_MAP_EQNUM);
+
+ val &= ~MSI_MAP_VALID;
+
+ fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+ return 0;
+}
+
+static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
+{
+ unsigned long pages, order, i;
+
+ order = get_order(512 * 1024);
+ pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order);
+ if (pages == 0UL) {
+ printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n",
+ order);
+ return -ENOMEM;
+ }
+ memset((char *)pages, 0, PAGE_SIZE << order);
+ pbm->msi_queues = (void *) pages;
+
+ fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
+ (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+ __pa(pbm->msi_queues)));
+
+ fire_write(pbm->pbm_regs + IMONDO_DATA0,
+ pbm->portid << 6);
+ fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+
+ fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
+ pbm->msi32_start);
+ fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
+ pbm->msi64_start);
+
+ for (i = 0; i < pbm->msiq_num; i++) {
+ fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
+ fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+ }
+
+ return 0;
+}
+
+static void pci_fire_msiq_free(struct pci_pbm_info *pbm)
+{
+ unsigned long pages, order;
+
+ order = get_order(512 * 1024);
+ pages = (unsigned long) pbm->msi_queues;
+
+ free_pages(pages, order);
+
+ pbm->msi_queues = NULL;
+}
+
+static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
+ unsigned long msiqid,
+ unsigned long devino)
+{
+ unsigned long cregs = (unsigned long) pbm->pbm_regs;
+ unsigned long imap_reg, iclr_reg, int_ctrlr;
+ unsigned int virt_irq;
+ int fixup;
+ u64 val;
+
+ imap_reg = cregs + (0x001000UL + (devino * 0x08UL));
+ iclr_reg = cregs + (0x001400UL + (devino * 0x08UL));
+
+ /* XXX iterate amongst the 4 IRQ controllers XXX */
+ int_ctrlr = (1UL << 6);
+
+ val = fire_read(imap_reg);
+ val |= (1UL << 63) | int_ctrlr;
+ fire_write(imap_reg, val);
+
+ fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
+
+ virt_irq = build_irq(fixup, iclr_reg, imap_reg);
+ if (!virt_irq)
+ return -ENOMEM;
+
+ fire_write(pbm->pbm_regs +
+ EVENT_QUEUE_CONTROL_SET(msiqid),
+ EVENT_QUEUE_CONTROL_SET_EN);
+
+ return virt_irq;
+}
+
+static const struct sparc64_msiq_ops pci_fire_msiq_ops = {
+ .get_head = pci_fire_get_head,
+ .dequeue_msi = pci_fire_dequeue_msi,
+ .set_head = pci_fire_set_head,
+ .msi_setup = pci_fire_msi_setup,
+ .msi_teardown = pci_fire_msi_teardown,
+ .msiq_alloc = pci_fire_msiq_alloc,
+ .msiq_free = pci_fire_msiq_free,
+ .msiq_build_irq = pci_fire_msiq_build_irq,
+};
+
+static void pci_fire_msi_init(struct pci_pbm_info *pbm)
+{
+ sparc64_pbm_msi_init(pbm, &pci_fire_msiq_ops);
+}
+#else /* CONFIG_PCI_MSI */
+static void pci_fire_msi_init(struct pci_pbm_info *pbm)
+{
+}
+#endif /* !(CONFIG_PCI_MSI) */
+
/* Based at pbm->controller_regs */
#define FIRE_PARITY_CONTROL 0x470010UL
#define FIRE_PARITY_ENAB 0x8000000000000000UL
@@ -176,6 +439,7 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
+ int err;
if ((portid & 1) == 0)
pbm = &p->pbm_A;
@@ -208,7 +472,13 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
pci_fire_hw_init(pbm);
- return pci_fire_pbm_iommu_init(pbm);
+ err = pci_fire_pbm_iommu_init(pbm);
+ if (err)
+ return err;
+
+ pci_fire_msi_init(pbm);
+
+ return 0;
}
static inline int portid_compare(u32 x, u32 y)
@@ -249,13 +519,6 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
p->pbm_B.iommu = iommu;
- /* XXX MSI support XXX */
-
- /* Like PSYCHO and SCHIZO we have a 2GB aligned area
- * for memory space.
- */
- pci_memspace_mask = 0x7fffffffUL;
-
if (pci_fire_pbm_init(p, dp, portid))
goto fatal_memory_error;
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index f660c2b685e..4a50da13ce4 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -29,6 +29,33 @@
#define PCI_STC_FLUSHFLAG_SET(STC) \
(*((STC)->strbuf_flushflag) != 0UL)
+#ifdef CONFIG_PCI_MSI
+struct pci_pbm_info;
+struct sparc64_msiq_ops {
+ int (*get_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long *head);
+ int (*dequeue_msi)(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long *head, unsigned long *msi);
+ int (*set_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long head);
+ int (*msi_setup)(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long msi, int is_msi64);
+ int (*msi_teardown)(struct pci_pbm_info *pbm, unsigned long msi);
+ int (*msiq_alloc)(struct pci_pbm_info *pbm);
+ void (*msiq_free)(struct pci_pbm_info *pbm);
+ int (*msiq_build_irq)(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long devino);
+};
+
+extern void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
+ const struct sparc64_msiq_ops *ops);
+
+struct sparc64_msiq_cookie {
+ struct pci_pbm_info *pbm;
+ unsigned long msiqid;
+};
+#endif
+
struct pci_controller_info;
struct pci_pbm_info {
@@ -90,6 +117,8 @@ struct pci_pbm_info {
u32 msiq_ent_count;
u32 msiq_first;
u32 msiq_first_devino;
+ u32 msiq_rotor;
+ struct sparc64_msiq_cookie *msiq_irq_cookies;
u32 msi_num;
u32 msi_first;
u32 msi_data_mask;
@@ -100,9 +129,11 @@ struct pci_pbm_info {
u32 msi64_len;
void *msi_queues;
unsigned long *msi_bitmap;
+ unsigned int *msi_irq_table;
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
struct msi_desc *entry);
void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
+ const struct sparc64_msiq_ops *msi_ops;
#endif /* !(CONFIG_PCI_MSI) */
/* This PBM's streaming buffer. */
@@ -126,7 +157,6 @@ struct pci_controller_info {
};
extern struct pci_pbm_info *pci_pbm_root;
-extern unsigned long pci_memspace_mask;
extern int pci_num_pbms;
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
new file mode 100644
index 00000000000..31a165fd3e4
--- /dev/null
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -0,0 +1,433 @@
+/* pci_msi.c: Sparc64 MSI support common layer.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "pci_impl.h"
+
+static irqreturn_t sparc64_msiq_interrupt(int irq, void *cookie)
+{
+ struct sparc64_msiq_cookie *msiq_cookie = cookie;
+ struct pci_pbm_info *pbm = msiq_cookie->pbm;
+ unsigned long msiqid = msiq_cookie->msiqid;
+ const struct sparc64_msiq_ops *ops;
+ unsigned long orig_head, head;
+ int err;
+
+ ops = pbm->msi_ops;
+
+ err = ops->get_head(pbm, msiqid, &head);
+ if (unlikely(err < 0))
+ goto err_get_head;
+
+ orig_head = head;
+ for (;;) {
+ unsigned long msi;
+
+ err = ops->dequeue_msi(pbm, msiqid, &head, &msi);
+ if (likely(err > 0))
+ __do_IRQ(pbm->msi_irq_table[msi - pbm->msi_first]);
+
+ if (unlikely(err < 0))
+ goto err_dequeue;
+
+ if (err == 0)
+ break;
+ }
+ if (likely(head != orig_head)) {
+ err = ops->set_head(pbm, msiqid, head);
+ if (unlikely(err < 0))
+ goto err_set_head;
+ }
+ return IRQ_HANDLED;
+
+err_get_head:
+ printk(KERN_EMERG "MSI: Get head on msiqid[%lu] gives error %d\n",
+ msiqid, err);
+ goto err_out;
+
+err_dequeue:
+ printk(KERN_EMERG "MSI: Dequeue head[%lu] from msiqid[%lu] "
+ "gives error %d\n",
+ head, msiqid, err);
+ goto err_out;
+
+err_set_head:
+ printk(KERN_EMERG "MSI: Set head[%lu] on msiqid[%lu] "
+ "gives error %d\n",
+ head, msiqid, err);
+ goto err_out;
+
+err_out:
+ return IRQ_NONE;
+}
+
+static u32 pick_msiq(struct pci_pbm_info *pbm)
+{
+ static DEFINE_SPINLOCK(rotor_lock);
+ unsigned long flags;
+ u32 ret, rotor;
+
+ spin_lock_irqsave(&rotor_lock, flags);
+
+ rotor = pbm->msiq_rotor;
+ ret = pbm->msiq_first + rotor;
+
+ if (++rotor >= pbm->msiq_num)
+ rotor = 0;
+ pbm->msiq_rotor = rotor;
+
+ spin_unlock_irqrestore(&rotor_lock, flags);
+
+ return ret;
+}
+
+
+static int alloc_msi(struct pci_pbm_info *pbm)
+{
+ int i;
+
+ for (i = 0; i < pbm->msi_num; i++) {
+ if (!test_and_set_bit(i, pbm->msi_bitmap))
+ return i + pbm->msi_first;
+ }
+
+ return -ENOENT;
+}
+
+static void free_msi(struct pci_pbm_info *pbm, int msi_num)
+{
+ msi_num -= pbm->msi_first;
+ clear_bit(msi_num, pbm->msi_bitmap);
+}
+
+static struct irq_chip msi_irq = {
+ .typename = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .enable = unmask_msi_irq,
+ .disable = mask_msi_irq,
+ /* XXX affinity XXX */
+};
+
+int sparc64_setup_msi_irq(unsigned int *virt_irq_p,
+ struct pci_dev *pdev,
+ struct msi_desc *entry)
+{
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+ const struct sparc64_msiq_ops *ops = pbm->msi_ops;
+ struct msi_msg msg;
+ int msi, err;
+ u32 msiqid;
+
+ *virt_irq_p = virt_irq_alloc(0, 0);
+ err = -ENOMEM;
+ if (!*virt_irq_p)
+ goto out_err;
+
+ set_irq_chip(*virt_irq_p, &msi_irq);
+
+ err = alloc_msi(pbm);
+ if (unlikely(err < 0))
+ goto out_virt_irq_free;
+
+ msi = err;
+
+ msiqid = pick_msiq(pbm);
+
+ err = ops->msi_setup(pbm, msiqid, msi,
+ (entry->msi_attrib.is_64 ? 1 : 0));
+ if (err)
+ goto out_msi_free;
+
+ pbm->msi_irq_table[msi - pbm->msi_first] = *virt_irq_p;
+
+ if (entry->msi_attrib.is_64) {
+ msg.address_hi = pbm->msi64_start >> 32;
+ msg.address_lo = pbm->msi64_start & 0xffffffff;
+ } else {
+ msg.address_hi = 0;
+ msg.address_lo = pbm->msi32_start;
+ }
+ msg.data = msi;
+
+ set_irq_msi(*virt_irq_p, entry);
+ write_msi_msg(*virt_irq_p, &msg);
+
+ return 0;
+
+out_msi_free:
+ free_msi(pbm, msi);
+
+out_virt_irq_free:
+ set_irq_chip(*virt_irq_p, NULL);
+ virt_irq_free(*virt_irq_p);
+ *virt_irq_p = 0;
+
+out_err:
+ return err;
+}
+
+void sparc64_teardown_msi_irq(unsigned int virt_irq,
+ struct pci_dev *pdev)
+{
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+ const struct sparc64_msiq_ops *ops = pbm->msi_ops;
+ unsigned int msi_num;
+ int i, err;
+
+ for (i = 0; i < pbm->msi_num; i++) {
+ if (pbm->msi_irq_table[i] == virt_irq)
+ break;
+ }
+ if (i >= pbm->msi_num) {
+ printk(KERN_ERR "%s: teardown: No MSI for irq %u\n",
+ pbm->name, virt_irq);
+ return;
+ }
+
+ msi_num = pbm->msi_first + i;
+ pbm->msi_irq_table[i] = ~0U;
+
+ err = ops->msi_teardown(pbm, msi_num);
+ if (err) {
+ printk(KERN_ERR "%s: teardown: ops->teardown() on MSI %u, "
+ "irq %u, gives error %d\n",
+ pbm->name, msi_num, virt_irq, err);
+ return;
+ }
+
+ free_msi(pbm, msi_num);
+
+ set_irq_chip(virt_irq, NULL);
+ virt_irq_free(virt_irq);
+}
+
+static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
+{
+ unsigned long size, bits_per_ulong;
+
+ bits_per_ulong = sizeof(unsigned long) * 8;
+ size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
+ size /= 8;
+ BUG_ON(size % sizeof(unsigned long));
+
+ pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
+ if (!pbm->msi_bitmap)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void msi_bitmap_free(struct pci_pbm_info *pbm)
+{
+ kfree(pbm->msi_bitmap);
+ pbm->msi_bitmap = NULL;
+}
+
+static int msi_table_alloc(struct pci_pbm_info *pbm)
+{
+ int size, i;
+
+ size = pbm->msiq_num * sizeof(struct sparc64_msiq_cookie);
+ pbm->msiq_irq_cookies = kzalloc(size, GFP_KERNEL);
+ if (!pbm->msiq_irq_cookies)
+ return -ENOMEM;
+
+ for (i = 0; i < pbm->msiq_num; i++) {
+ struct sparc64_msiq_cookie *p;
+
+ p = &pbm->msiq_irq_cookies[i];
+ p->pbm = pbm;
+ p->msiqid = pbm->msiq_first + i;
+ }
+
+ size = pbm->msi_num * sizeof(unsigned int);
+ pbm->msi_irq_table = kzalloc(size, GFP_KERNEL);
+ if (!pbm->msi_irq_table) {
+ kfree(pbm->msiq_irq_cookies);
+ pbm->msiq_irq_cookies = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void msi_table_free(struct pci_pbm_info *pbm)
+{
+ kfree(pbm->msiq_irq_cookies);
+ pbm->msiq_irq_cookies = NULL;
+
+ kfree(pbm->msi_irq_table);
+ pbm->msi_irq_table = NULL;
+}
+
+static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
+ const struct sparc64_msiq_ops *ops,
+ unsigned long msiqid,
+ unsigned long devino)
+{
+ int irq = ops->msiq_build_irq(pbm, msiqid, devino);
+ int err;
+
+ if (irq < 0)
+ return irq;
+
+ err = request_irq(irq, sparc64_msiq_interrupt, 0,
+ "MSIQ",
+ &pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int sparc64_bringup_msi_queues(struct pci_pbm_info *pbm,
+ const struct sparc64_msiq_ops *ops)
+{
+ int i;
+
+ for (i = 0; i < pbm->msiq_num; i++) {
+ unsigned long msiqid = i + pbm->msiq_first;
+ unsigned long devino = i + pbm->msiq_first_devino;
+ int err;
+
+ err = bringup_one_msi_queue(pbm, ops, msiqid, devino);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
+ const struct sparc64_msiq_ops *ops)
+{
+ const u32 *val;
+ int len;
+
+ val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msiq_num = *val;
+ if (pbm->msiq_num) {
+ const struct msiq_prop {
+ u32 first_msiq;
+ u32 num_msiq;
+ u32 first_devino;
+ } *mqp;
+ const struct msi_range_prop {
+ u32 first_msi;
+ u32 num_msi;
+ } *mrng;
+ const struct addr_range_prop {
+ u32 msi32_high;
+ u32 msi32_low;
+ u32 msi32_len;
+ u32 msi64_high;
+ u32 msi64_low;
+ u32 msi64_len;
+ } *arng;
+
+ val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+ if (!val || len != 4)
+ goto no_msi;
+
+ pbm->msiq_ent_count = *val;
+
+ mqp = of_get_property(pbm->prom_node,
+ "msi-eq-to-devino", &len);
+ if (!mqp)
+ mqp = of_get_property(pbm->prom_node,
+ "msi-eq-devino", &len);
+ if (!mqp || len != sizeof(struct msiq_prop))
+ goto no_msi;
+
+ pbm->msiq_first = mqp->first_msiq;
+ pbm->msiq_first_devino = mqp->first_devino;
+
+ val = of_get_property(pbm->prom_node, "#msi", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msi_num = *val;
+
+ mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+ if (!mrng || len != sizeof(struct msi_range_prop))
+ goto no_msi;
+ pbm->msi_first = mrng->first_msi;
+
+ val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msi_data_mask = *val;
+
+ val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msix_data_width = *val;
+
+ arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+ &len);
+ if (!arng || len != sizeof(struct addr_range_prop))
+ goto no_msi;
+ pbm->msi32_start = ((u64)arng->msi32_high << 32) |
+ (u64) arng->msi32_low;
+ pbm->msi64_start = ((u64)arng->msi64_high << 32) |
+ (u64) arng->msi64_low;
+ pbm->msi32_len = arng->msi32_len;
+ pbm->msi64_len = arng->msi64_len;
+
+ if (msi_bitmap_alloc(pbm))
+ goto no_msi;
+
+ if (msi_table_alloc(pbm)) {
+ msi_bitmap_free(pbm);
+ goto no_msi;
+ }
+
+ if (ops->msiq_alloc(pbm)) {
+ msi_table_free(pbm);
+ msi_bitmap_free(pbm);
+ goto no_msi;
+ }
+
+ if (sparc64_bringup_msi_queues(pbm, ops)) {
+ ops->msiq_free(pbm);
+ msi_table_free(pbm);
+ msi_bitmap_free(pbm);
+ goto no_msi;
+ }
+
+ printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
+ "devino[0x%x]\n",
+ pbm->name,
+ pbm->msiq_first, pbm->msiq_num,
+ pbm->msiq_ent_count,
+ pbm->msiq_first_devino);
+ printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
+ "width[%u]\n",
+ pbm->name,
+ pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
+ pbm->msix_data_width);
+ printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
+ "addr64[0x%lx:0x%x]\n",
+ pbm->name,
+ pbm->msi32_start, pbm->msi32_len,
+ pbm->msi64_start, pbm->msi64_len);
+ printk(KERN_INFO "%s: MSI queues at RA [%016lx]\n",
+ pbm->name,
+ __pa(pbm->msi_queues));
+
+ pbm->msi_ops = ops;
+ pbm->setup_msi_irq = sparc64_setup_msi_irq;
+ pbm->teardown_msi_irq = sparc64_teardown_msi_irq;
+ }
+ return;
+
+no_msi:
+ pbm->msiq_num = 0;
+ printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index b6b4cfea5b5..d27ee5d528a 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1058,12 +1058,6 @@ void psycho_init(struct device_node *dp, char *model_name)
p->pbm_A.config_space = p->pbm_B.config_space =
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
- /*
- * Psycho's PCI MEM space is mapped to a 2GB aligned area, so
- * we need to adjust our MEM space mask.
- */
- pci_memspace_mask = 0x7fffffffUL;
-
psycho_controller_hwinit(&p->pbm_A);
if (psycho_iommu_init(&p->pbm_A))
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 3c30bfa1f3a..9546ba9f5de 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1464,9 +1464,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
p->pbm_B.iommu = iommu;
- /* Like PSYCHO we have a 2GB aligned area for memory space. */
- pci_memspace_mask = 0x7fffffffUL;
-
if (schizo_pbm_init(p, dp, portid, chip_type))
goto fatal_memory_error;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index da724b13e89..95de1444ee6 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -748,111 +748,102 @@ struct pci_sun4v_msiq_entry {
u64 reserved2;
};
-/* For now this just runs as a pre-handler for the real interrupt handler.
- * So we just walk through the queue and ACK all the entries, update the
- * head pointer, and return.
- *
- * In the longer term it would be nice to do something more integrated
- * wherein we can pass in some of this MSI info to the drivers. This
- * would be most useful for PCIe fabric error messages, although we could
- * invoke those directly from the loop here in order to pass the info around.
- */
-static void pci_sun4v_msi_prehandler(unsigned int ino, void *data1, void *data2)
+static int pci_sun4v_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long *head)
{
- struct pci_pbm_info *pbm = data1;
- struct pci_sun4v_msiq_entry *base, *ep;
- unsigned long msiqid, orig_head, head, type, err;
-
- msiqid = (unsigned long) data2;
+ unsigned long err, limit;
- head = 0xdeadbeef;
- err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, &head);
+ err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, head);
if (unlikely(err))
- goto hv_error_get;
-
- if (unlikely(head >= (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry))))
- goto bad_offset;
-
- head /= sizeof(struct pci_sun4v_msiq_entry);
- orig_head = head;
- base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
- (pbm->msiq_ent_count *
- sizeof(struct pci_sun4v_msiq_entry))));
- ep = &base[head];
- while ((ep->version_type & MSIQ_TYPE_MASK) != 0) {
- type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
- if (unlikely(type != MSIQ_TYPE_MSI32 &&
- type != MSIQ_TYPE_MSI64))
- goto bad_type;
-
- pci_sun4v_msi_setstate(pbm->devhandle,
- ep->msi_data /* msi_num */,
- HV_MSISTATE_IDLE);
-
- /* Clear the entry. */
- ep->version_type &= ~MSIQ_TYPE_MASK;
-
- /* Go to next entry in ring. */
- head++;
- if (head >= pbm->msiq_ent_count)
- head = 0;
- ep = &base[head];
- }
+ return -ENXIO;
- if (likely(head != orig_head)) {
- /* ACK entries by updating head pointer. */
- head *= sizeof(struct pci_sun4v_msiq_entry);
- err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
- if (unlikely(err))
- goto hv_error_set;
- }
- return;
+ limit = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
+ if (unlikely(*head >= limit))
+ return -EFBIG;
-hv_error_set:
- printk(KERN_EMERG "MSI: Hypervisor set head gives error %lu\n", err);
- goto hv_error_cont;
+ return 0;
+}
-hv_error_get:
- printk(KERN_EMERG "MSI: Hypervisor get head gives error %lu\n", err);
+static int pci_sun4v_dequeue_msi(struct pci_pbm_info *pbm,
+ unsigned long msiqid, unsigned long *head,
+ unsigned long *msi)
+{
+ struct pci_sun4v_msiq_entry *ep;
+ unsigned long err, type;
-hv_error_cont:
- printk(KERN_EMERG "MSI: devhandle[%x] msiqid[%lx] head[%lu]\n",
- pbm->devhandle, msiqid, head);
- return;
+ /* Note: void pointer arithmetic, 'head' is a byte offset */
+ ep = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
+ (pbm->msiq_ent_count *
+ sizeof(struct pci_sun4v_msiq_entry))) +
+ *head);
-bad_offset:
- printk(KERN_EMERG "MSI: Hypervisor gives bad offset %lx max(%lx)\n",
- head, pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry));
- return;
+ if ((ep->version_type & MSIQ_TYPE_MASK) == 0)
+ return 0;
-bad_type:
- printk(KERN_EMERG "MSI: Entry has bad type %lx\n", type);
- return;
+ type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
+ if (unlikely(type != MSIQ_TYPE_MSI32 &&
+ type != MSIQ_TYPE_MSI64))
+ return -EINVAL;
+
+ *msi = ep->msi_data;
+
+ err = pci_sun4v_msi_setstate(pbm->devhandle,
+ ep->msi_data /* msi_num */,
+ HV_MSISTATE_IDLE);
+ if (unlikely(err))
+ return -ENXIO;
+
+ /* Clear the entry. */
+ ep->version_type &= ~MSIQ_TYPE_MASK;
+
+ (*head) += sizeof(struct pci_sun4v_msiq_entry);
+ if (*head >=
+ (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry)))
+ *head = 0;
+
+ return 1;
}
-static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
+static int pci_sun4v_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long head)
{
- unsigned long size, bits_per_ulong;
+ unsigned long err;
- bits_per_ulong = sizeof(unsigned long) * 8;
- size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
- size /= 8;
- BUG_ON(size % sizeof(unsigned long));
+ err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
+ if (unlikely(err))
+ return -EINVAL;
- pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
- if (!pbm->msi_bitmap)
- return -ENOMEM;
+ return 0;
+}
+static int pci_sun4v_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
+ unsigned long msi, int is_msi64)
+{
+ if (pci_sun4v_msi_setmsiq(pbm->devhandle, msi, msiqid,
+ (is_msi64 ?
+ HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
+ return -ENXIO;
+ if (pci_sun4v_msi_setstate(pbm->devhandle, msi, HV_MSISTATE_IDLE))
+ return -ENXIO;
+ if (pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_VALID))
+ return -ENXIO;
return 0;
}
-static void msi_bitmap_free(struct pci_pbm_info *pbm)
+static int pci_sun4v_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
{
- kfree(pbm->msi_bitmap);
- pbm->msi_bitmap = NULL;
+ unsigned long err, msiqid;
+
+ err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi, &msiqid);
+ if (err)
+ return -ENXIO;
+
+ pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_INVALID);
+
+ return 0;
}
-static int msi_queue_alloc(struct pci_pbm_info *pbm)
+static int pci_sun4v_msiq_alloc(struct pci_pbm_info *pbm)
{
unsigned long q_size, alloc_size, pages, order;
int i;
@@ -906,232 +897,59 @@ h_error:
return -EINVAL;
}
-
-static int alloc_msi(struct pci_pbm_info *pbm)
+static void pci_sun4v_msiq_free(struct pci_pbm_info *pbm)
{
+ unsigned long q_size, alloc_size, pages, order;
int i;
- for (i = 0; i < pbm->msi_num; i++) {
- if (!test_and_set_bit(i, pbm->msi_bitmap))
- return i + pbm->msi_first;
- }
-
- return -ENOENT;
-}
-
-static void free_msi(struct pci_pbm_info *pbm, int msi_num)
-{
- msi_num -= pbm->msi_first;
- clear_bit(msi_num, pbm->msi_bitmap);
-}
-
-static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
- struct pci_dev *pdev,
- struct msi_desc *entry)
-{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long devino, msiqid;
- struct msi_msg msg;
- int msi_num, err;
-
- *virt_irq_p = 0;
-
- msi_num = alloc_msi(pbm);
- if (msi_num < 0)
- return msi_num;
-
- err = sun4v_build_msi(pbm->devhandle, virt_irq_p,
- pbm->msiq_first_devino,
- (pbm->msiq_first_devino +
- pbm->msiq_num));
- if (err < 0)
- goto out_err;
- devino = err;
-
- msiqid = ((devino - pbm->msiq_first_devino) +
- pbm->msiq_first);
-
- err = -EINVAL;
- if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
- if (err)
- goto out_err;
-
- if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
- goto out_err;
-
- if (pci_sun4v_msi_setmsiq(pbm->devhandle,
- msi_num, msiqid,
- (entry->msi_attrib.is_64 ?
- HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
- goto out_err;
-
- if (pci_sun4v_msi_setstate(pbm->devhandle, msi_num, HV_MSISTATE_IDLE))
- goto out_err;
-
- if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
- goto out_err;
-
- sparc64_set_msi(*virt_irq_p, msi_num);
+ for (i = 0; i < pbm->msiq_num; i++) {
+ unsigned long msiqid = pbm->msiq_first + i;
- if (entry->msi_attrib.is_64) {
- msg.address_hi = pbm->msi64_start >> 32;
- msg.address_lo = pbm->msi64_start & 0xffffffff;
- } else {
- msg.address_hi = 0;
- msg.address_lo = pbm->msi32_start;
+ (void) pci_sun4v_msiq_conf(pbm->devhandle, msiqid, 0UL, 0);
}
- msg.data = msi_num;
-
- set_irq_msi(*virt_irq_p, entry);
- write_msi_msg(*virt_irq_p, &msg);
- irq_install_pre_handler(*virt_irq_p,
- pci_sun4v_msi_prehandler,
- pbm, (void *) msiqid);
+ q_size = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
+ alloc_size = (pbm->msiq_num * q_size);
+ order = get_order(alloc_size);
- return 0;
+ pages = (unsigned long) pbm->msi_queues;
-out_err:
- free_msi(pbm, msi_num);
- return err;
+ free_pages(pages, order);
+ pbm->msi_queues = NULL;
}
-static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
- struct pci_dev *pdev)
+static int pci_sun4v_msiq_build_irq(struct pci_pbm_info *pbm,
+ unsigned long msiqid,
+ unsigned long devino)
{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long msiqid, err;
- unsigned int msi_num;
-
- msi_num = sparc64_get_msi(virt_irq);
- err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
- if (err) {
- printk(KERN_ERR "%s: getmsiq gives error %lu\n",
- pbm->name, err);
- return;
- }
+ unsigned int virt_irq = sun4v_build_irq(pbm->devhandle, devino);
- pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_INVALID);
- pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_INVALID);
+ if (!virt_irq)
+ return -ENOMEM;
- free_msi(pbm, msi_num);
+ if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
+ return -EINVAL;
+ if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
+ return -EINVAL;
- /* The sun4v_destroy_msi() will liberate the devino and thus the MSIQ
- * allocation.
- */
- sun4v_destroy_msi(virt_irq);
+ return virt_irq;
}
+static const struct sparc64_msiq_ops pci_sun4v_msiq_ops = {
+ .get_head = pci_sun4v_get_head,
+ .dequeue_msi = pci_sun4v_dequeue_msi,
+ .set_head = pci_sun4v_set_head,
+ .msi_setup = pci_sun4v_msi_setup,
+ .msi_teardown = pci_sun4v_msi_teardown,
+ .msiq_alloc = pci_sun4v_msiq_alloc,
+ .msiq_free = pci_sun4v_msiq_free,
+ .msiq_build_irq = pci_sun4v_msiq_build_irq,
+};
+
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
- const u32 *val;
- int len;
-
- val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msiq_num = *val;
- if (pbm->msiq_num) {
- const struct msiq_prop {
- u32 first_msiq;
- u32 num_msiq;
- u32 first_devino;
- } *mqp;
- const struct msi_range_prop {
- u32 first_msi;
- u32 num_msi;
- } *mrng;
- const struct addr_range_prop {
- u32 msi32_high;
- u32 msi32_low;
- u32 msi32_len;
- u32 msi64_high;
- u32 msi64_low;
- u32 msi64_len;
- } *arng;
-
- val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
- if (!val || len != 4)
- goto no_msi;
-
- pbm->msiq_ent_count = *val;
-
- mqp = of_get_property(pbm->prom_node,
- "msi-eq-to-devino", &len);
- if (!mqp || len != sizeof(struct msiq_prop))
- goto no_msi;
-
- pbm->msiq_first = mqp->first_msiq;
- pbm->msiq_first_devino = mqp->first_devino;
-
- val = of_get_property(pbm->prom_node, "#msi", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msi_num = *val;
-
- mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
- if (!mrng || len != sizeof(struct msi_range_prop))
- goto no_msi;
- pbm->msi_first = mrng->first_msi;
-
- val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msi_data_mask = *val;
-
- val = of_get_property(pbm->prom_node, "msix-data-width", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msix_data_width = *val;
-
- arng = of_get_property(pbm->prom_node, "msi-address-ranges",
- &len);
- if (!arng || len != sizeof(struct addr_range_prop))
- goto no_msi;
- pbm->msi32_start = ((u64)arng->msi32_high << 32) |
- (u64) arng->msi32_low;
- pbm->msi64_start = ((u64)arng->msi64_high << 32) |
- (u64) arng->msi64_low;
- pbm->msi32_len = arng->msi32_len;
- pbm->msi64_len = arng->msi64_len;
-
- if (msi_bitmap_alloc(pbm))
- goto no_msi;
-
- if (msi_queue_alloc(pbm)) {
- msi_bitmap_free(pbm);
- goto no_msi;
- }
-
- printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
- "devino[0x%x]\n",
- pbm->name,
- pbm->msiq_first, pbm->msiq_num,
- pbm->msiq_ent_count,
- pbm->msiq_first_devino);
- printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
- "width[%u]\n",
- pbm->name,
- pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
- pbm->msix_data_width);
- printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
- "addr64[0x%lx:0x%x]\n",
- pbm->name,
- pbm->msi32_start, pbm->msi32_len,
- pbm->msi64_start, pbm->msi64_len);
- printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
- pbm->name,
- pbm->msi_queues);
- }
- pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
- pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
-
- return;
-
-no_msi:
- pbm->msiq_num = 0;
- printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+ sparc64_pbm_msi_init(pbm, &pci_sun4v_msiq_ops);
}
#else /* CONFIG_PCI_MSI */
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
@@ -1237,11 +1055,6 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name)
p->pbm_B.iommu = iommu;
- /* Like PSYCHO and SCHIZO we have a 2GB aligned area
- * for memory space.
- */
- pci_memspace_mask = 0x7fffffffUL;
-
pci_sun4v_pbm_init(p, dp, devhandle);
return;
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 881a09ee4c4..850cdffdd69 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -105,9 +105,11 @@ static struct of_device_id power_match[] = {
};
static struct of_platform_driver power_driver = {
- .name = "power",
.match_table = power_match,
.probe = power_probe,
+ .driver = {
+ .name = "power",
+ },
};
void __init power_init(void)
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 574bc248bca..e2f8e1b4882 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -96,19 +96,21 @@ sun4v_dev_mondo:
stxa %g2, [%g4] ASI_QUEUE
membar #Sync
- /* Get &__irq_work[smp_processor_id()] into %g1. */
- TRAP_LOAD_IRQ_WORK(%g1, %g4)
+ TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
- /* Get &ivector_table[IVEC] into %g4. */
- sethi %hi(ivector_table), %g4
- sllx %g3, 3, %g3
- or %g4, %lo(ivector_table), %g4
+ /* For VIRQs, cookie is encoded as ~bucket_phys_addr */
+ brlz,pt %g3, 1f
+ xnor %g3, %g0, %g4
+
+ /* Get __pa(&ivector_table[IVEC]) into %g4. */
+ sethi %hi(ivector_table_pa), %g4
+ ldx [%g4 + %lo(ivector_table_pa)], %g4
+ sllx %g3, 4, %g3
add %g4, %g3, %g4
- /* Insert ivector_table[] entry into __irq_work[] queue. */
- lduw [%g1], %g2 /* g2 = irq_work(cpu) */
- stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */
- stw %g4, [%g1] /* irq_work(cpu) = bucket */
+1: ldx [%g1], %g2
+ stxa %g2, [%g4] ASI_PHYS_USE_EC
+ stx %g4, [%g1]
/* Signal the interrupt by setting (1 << pil) in %softint. */
wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index d108eeb0734..0d5c5026494 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -436,7 +436,7 @@ out:
asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
unsigned long third, void __user *ptr, long fifth)
{
- int err;
+ long err;
/* No need for backward compatibility. We can start fresh... */
if (call <= SEMCTL) {
@@ -453,16 +453,9 @@ asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
err = sys_semget(first, (int)second, (int)third);
goto out;
case SEMCTL: {
- union semun fourth;
- err = -EINVAL;
- if (!ptr)
- goto out;
- err = -EFAULT;
- if (get_user(fourth.__pad,
- (void __user * __user *) ptr))
- goto out;
- err = sys_semctl(first, (int)second | IPC_64,
- (int)third, fourth);
+ err = sys_semctl(first, third,
+ (int)second | IPC_64,
+ (union semun) ptr);
goto out;
}
default:
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 69cad1b653c..cd8c740cba1 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -764,9 +764,11 @@ static struct of_device_id clock_match[] = {
};
static struct of_platform_driver clock_driver = {
- .name = "clock",
.match_table = clock_match,
.probe = clock_probe,
+ .driver = {
+ .name = "clock",
+ },
};
static int __init clock_init(void)
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 6ef42b8e53d..34573a55b6e 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -2569,8 +2569,8 @@ void __init trap_init(void)
offsetof(struct trap_per_cpu, tsb_huge)) ||
(TRAP_PER_CPU_TSB_HUGE_TEMP !=
offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
- (TRAP_PER_CPU_IRQ_WORKLIST !=
- offsetof(struct trap_per_cpu, irq_worklist)) ||
+ (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
+ offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
(TRAP_PER_CPU_CPU_MONDO_QMASK !=
offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
(TRAP_PER_CPU_DEV_MONDO_QMASK !=
diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c
index 1f83fe6a82d..791c15138f3 100644
--- a/arch/sparc64/kernel/us2e_cpufreq.c
+++ b/arch/sparc64/kernel/us2e_cpufreq.c
@@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
table[2].index = 5;
table[3].frequency = CPUFREQ_TABLE_END;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index b982fa3dd74..9fcd503bc04 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -10,105 +10,138 @@ ENTRY(_start)
jiffies = jiffies_64;
SECTIONS
{
- swapper_low_pmd_dir = 0x0000000000402000;
- . = 0x4000;
- .text 0x0000000000404000 :
- {
- _text = .;
- TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.gnu.warning)
- } =0
- _etext = .;
- PROVIDE (etext = .);
+ swapper_low_pmd_dir = 0x0000000000402000;
+ . = 0x4000;
+ .text 0x0000000000404000 : {
+ _text = .;
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.gnu.warning)
+ } = 0
+ _etext = .;
+ PROVIDE (etext = .);
- RO_DATA(PAGE_SIZE)
+ RO_DATA(PAGE_SIZE)
+ .data : {
+ DATA_DATA
+ CONSTRUCTORS
+ }
+ .data1 : {
+ *(.data1)
+ }
+ . = ALIGN(64);
+ .data.cacheline_aligned : {
+ *(.data.cacheline_aligned)
+ }
+ . = ALIGN(64);
+ .data.read_mostly : {
+ *(.data.read_mostly)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ .fixup : {
+ *(.fixup)
+ }
+ . = ALIGN(16);
+ __ex_table : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
+ NOTES
- .data :
- {
- DATA_DATA
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- . = ALIGN(64);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
- . = ALIGN(64);
- .data.read_mostly : { *(.data.read_mostly) }
- _edata = .;
- PROVIDE (edata = .);
- .fixup : { *(.fixup) }
+ . = ALIGN(PAGE_SIZE);
+ .init.text : {
+ __init_begin = .;
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
+ .init.data : {
+ *(.init.data)
+ }
+ . = ALIGN(16);
+ .init.setup : {
+ __setup_start = .;
+ *(.init.setup)
+ __setup_end = .;
+ }
+ .initcall.init : {
+ __initcall_start = .;
+ INITCALLS
+ __initcall_end = .;
+ }
+ .con_initcall.init : {
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+ __con_initcall_end = .;
+ }
+ SECURITY_INIT
- . = ALIGN(16);
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
+ . = ALIGN(4);
+ .tsb_ldquad_phys_patch : {
+ __tsb_ldquad_phys_patch = .;
+ *(.tsb_ldquad_phys_patch)
+ __tsb_ldquad_phys_patch_end = .;
+ }
- NOTES
+ .tsb_phys_patch : {
+ __tsb_phys_patch = .;
+ *(.tsb_phys_patch)
+ __tsb_phys_patch_end = .;
+ }
- . = ALIGN(PAGE_SIZE);
- __init_begin = .;
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
- .init.data : { *(.init.data) }
- . = ALIGN(16);
- __setup_start = .;
- .init.setup : { *(.init.setup) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : {
- INITCALLS
- }
- __initcall_end = .;
- __con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
- __con_initcall_end = .;
- SECURITY_INIT
- . = ALIGN(4);
- __tsb_ldquad_phys_patch = .;
- .tsb_ldquad_phys_patch : { *(.tsb_ldquad_phys_patch) }
- __tsb_ldquad_phys_patch_end = .;
- __tsb_phys_patch = .;
- .tsb_phys_patch : { *(.tsb_phys_patch) }
- __tsb_phys_patch_end = .;
- __cpuid_patch = .;
- .cpuid_patch : { *(.cpuid_patch) }
- __cpuid_patch_end = .;
- __sun4v_1insn_patch = .;
- .sun4v_1insn_patch : { *(.sun4v_1insn_patch) }
- __sun4v_1insn_patch_end = .;
- __sun4v_2insn_patch = .;
- .sun4v_2insn_patch : { *(.sun4v_2insn_patch) }
- __sun4v_2insn_patch_end = .;
+ .cpuid_patch : {
+ __cpuid_patch = .;
+ *(.cpuid_patch)
+ __cpuid_patch_end = .;
+ }
+
+ .sun4v_1insn_patch : {
+ __sun4v_1insn_patch = .;
+ *(.sun4v_1insn_patch)
+ __sun4v_1insn_patch_end = .;
+ }
+ .sun4v_2insn_patch : {
+ __sun4v_2insn_patch = .;
+ *(.sun4v_2insn_patch)
+ __sun4v_2insn_patch_end = .;
+ }
#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(PAGE_SIZE);
- __initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
- __initramfs_end = .;
+ . = ALIGN(PAGE_SIZE);
+ .init.ramfs : {
+ __initramfs_start = .;
+ *(.init.ramfs)
+ __initramfs_end = .;
+ }
#endif
- PERCPU(PAGE_SIZE)
+ PERCPU(PAGE_SIZE)
- . = ALIGN(PAGE_SIZE);
- __init_end = .;
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
+ __bss_start = .;
+ .sbss : {
+ *(.sbss)
+ *(.scommon)
+ }
+ .bss : {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
- STABS_DEBUG
+ /DISCARD/ : {
+ *(.exit.text)
+ *(.exit.data)
+ *(.exitcall.exit)
+ }
- DWARF_DEBUG
+ STABS_DEBUG
+ DWARF_DEBUG
}
diff --git a/arch/sparc64/lib/xor.S b/arch/sparc64/lib/xor.S
index a79c8888170..f44f58f4023 100644
--- a/arch/sparc64/lib/xor.S
+++ b/arch/sparc64/lib/xor.S
@@ -491,12 +491,12 @@ xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
ldda [%i1 + 0x10] %asi, %i2 /* %i2/%i3 = src1 + 0x10 */
xor %g2, %i4, %g2
xor %g3, %i5, %g3
- ldda [%i7 + 0x10] %asi, %i4 /* %i4/%i5 = src2 + 0x10 */
+ ldda [%l7 + 0x10] %asi, %i4 /* %i4/%i5 = src2 + 0x10 */
xor %l0, %g2, %l0
xor %l1, %g3, %l1
stxa %l0, [%i0 + 0x00] %asi
stxa %l1, [%i0 + 0x08] %asi
- ldda [%i6 + 0x10] %asi, %g2 /* %g2/%g3 = src3 + 0x10 */
+ ldda [%l6 + 0x10] %asi, %g2 /* %g2/%g3 = src3 + 0x10 */
ldda [%i0 + 0x10] %asi, %l0 /* %l0/%l1 = dest + 0x10 */
xor %i4, %i2, %i4
@@ -504,12 +504,12 @@ xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
ldda [%i1 + 0x20] %asi, %i2 /* %i2/%i3 = src1 + 0x20 */
xor %g2, %i4, %g2
xor %g3, %i5, %g3
- ldda [%i7 + 0x20] %asi, %i4 /* %i4/%i5 = src2 + 0x20 */
+ ldda [%l7 + 0x20] %asi, %i4 /* %i4/%i5 = src2 + 0x20 */
xor %l0, %g2, %l0
xor %l1, %g3, %l1
stxa %l0, [%i0 + 0x10] %asi
stxa %l1, [%i0 + 0x18] %asi
- ldda [%i6 + 0x20] %asi, %g2 /* %g2/%g3 = src3 + 0x20 */
+ ldda [%l6 + 0x20] %asi, %g2 /* %g2/%g3 = src3 + 0x20 */
ldda [%i0 + 0x20] %asi, %l0 /* %l0/%l1 = dest + 0x20 */
xor %i4, %i2, %i4
@@ -517,12 +517,12 @@ xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
ldda [%i1 + 0x30] %asi, %i2 /* %i2/%i3 = src1 + 0x30 */
xor %g2, %i4, %g2
xor %g3, %i5, %g3
- ldda [%i7 + 0x30] %asi, %i4 /* %i4/%i5 = src2 + 0x30 */
+ ldda [%l7 + 0x30] %asi, %i4 /* %i4/%i5 = src2 + 0x30 */
xor %l0, %g2, %l0
xor %l1, %g3, %l1
stxa %l0, [%i0 + 0x20] %asi
stxa %l1, [%i0 + 0x28] %asi
- ldda [%i6 + 0x30] %asi, %g2 /* %g2/%g3 = src3 + 0x30 */
+ ldda [%l6 + 0x30] %asi, %g2 /* %g2/%g3 = src3 + 0x30 */
ldda [%i0 + 0x30] %asi, %l0 /* %l0/%l1 = dest + 0x30 */
prefetch [%i1 + 0x40], #one_read
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 3010227fe24..f0ab9aab308 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -631,7 +631,6 @@ void prom_world(int enter)
__asm__ __volatile__("flushw");
}
-#ifdef DCACHE_ALIASING_POSSIBLE
void __flush_dcache_range(unsigned long start, unsigned long end)
{
unsigned long va;
@@ -655,7 +654,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end)
"i" (ASI_DCACHE_INVALIDATE));
}
}
-#endif /* DCACHE_ALIASING_POSSIBLE */
/* get_new_mmu_context() uses "cache + 1". */
DEFINE_SPINLOCK(ctx_alloc_lock);
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 989224f2134..0666729eb97 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -176,9 +176,9 @@ include/asm-um/arch:
@echo ' SYMLINK $@'
ifneq ($(KBUILD_SRC),)
$(Q)mkdir -p $(objtree)/include/asm-um
- $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch
+ $(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch
else
- $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
+ $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(HEADER_ARCH) arch
endif
$(objtree)/$(ARCH_DIR)/include:
@@ -232,4 +232,4 @@ $(ARCH_DIR)/include/kern_constants.h: $(objtree)/$(ARCH_DIR)/include
@echo ' SYMLINK $@'
$(Q)ln -sf ../../../include/asm-um/asm-offsets.h $@
-export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS
+export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS HEADER_ARCH
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index c9f1c5b24c9..60107ed4905 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -1,4 +1,4 @@
-core-y += arch/um/sys-i386/ arch/i386/crypto/
+core-y += arch/um/sys-i386/ arch/x86/crypto/
TOP_ADDR := $(CONFIG_TOP_ADDR)
@@ -12,6 +12,7 @@ LDFLAGS += -m elf_i386
ELF_ARCH := $(SUBARCH)
ELF_FORMAT := elf32-$(SUBARCH)
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
+HEADER_ARCH := x86
ifeq ("$(origin SUBARCH)", "command line")
ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
@@ -24,6 +25,11 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
endif
endif
+CFLAGS += -DCONFIG_X86_32
+AFLAGS += -DCONFIG_X86_32
+CONFIG_X86_32 := y
+export CONFIG_X86_32
+
ARCH_KERNEL_DEFINES += -U__$(SUBARCH)__ -U$(SUBARCH)
# First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y.
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 69ecea63fda..8a00e5f6934 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -1,7 +1,7 @@
# Copyright 2003 - 2004 Pathscale, Inc
# Released under the GPL
-core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
+core-y += arch/um/sys-x86_64/ arch/x86/crypto/
START := 0x60000000
_extra_flags_ = -fno-builtin -m64
@@ -18,6 +18,7 @@ CPPFLAGS += -m64
ELF_ARCH := i386:x86-64
ELF_FORMAT := elf64-x86-64
+HEADER_ARCH := x86
# Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example.
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index a9a4b85ca51..bf23dd3e24d 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -28,5 +28,5 @@ endef
ifdef subarch-obj-y
obj-y += subarch.o
-subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y))
+subarch-y = $(addprefix ../../$(HEADER_ARCH)/,$(subarch-obj-y))
endif
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index d6b3ecd4b77..a4618b6b85b 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -4,9 +4,9 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
-subarch-obj-y = lib/bitops.o lib/semaphore.o lib/string.o
-subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o
+subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o
USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 4d9e5efa6fb..ea8185d8540 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -11,8 +11,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
obj-$(CONFIG_MODULES) += um_module.o
-subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o
ldt-y = ../sys-i386/ldt.o
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index c624193740f..7ff02063b85 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds
obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
- quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o
+ quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
@@ -37,9 +37,9 @@ obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
obj-$(CONFIG_VM86) += vm86_32.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_HPET_TIMER) += hpet_32.o
+obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_K8_NB) += k8.o
-obj-$(CONFIG_MGEODE_LX) += geode_32.o
+obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o
obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o
obj-$(CONFIG_PARAVIRT) += paravirt_32.o
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 3ab017a0a3b..43da66213a4 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
- pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \
- perfctr-watchdog.o
+ pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
+ perfctr-watchdog.o i8253.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index bd72d94e713..11b03d3c6fd 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -10,6 +10,7 @@
#include <asm/pgtable.h>
#include <asm/mce.h>
#include <asm/nmi.h>
+#include <asm/vsyscall.h>
#define MAX_PATCH_LEN (255-1)
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 925758dbca0..09b82093bc7 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -25,6 +25,7 @@
#include <linux/sysdev.h>
#include <linux/module.h>
#include <linux/ioport.h>
+#include <linux/clockchips.h>
#include <asm/atomic.h>
#include <asm/smp.h>
@@ -39,12 +40,9 @@
#include <asm/hpet.h>
#include <asm/apic.h>
-int apic_mapped;
int apic_verbosity;
-int apic_runs_main_timer;
-int apic_calibrate_pmtmr __initdata;
-
-int disable_apic_timer __initdata;
+int disable_apic_timer __cpuinitdata;
+static int apic_calibrate_pmtmr __initdata;
/* Local APIC timer works in C2? */
int local_apic_timer_c2_ok;
@@ -56,14 +54,78 @@ static struct resource lapic_resource = {
.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
};
+static unsigned int calibration_result;
+
+static int lapic_next_event(unsigned long delta,
+ struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+
+static void lapic_timer_broadcast(cpumask_t mask);
+
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
+
+static struct clock_event_device lapic_clockevent = {
+ .name = "lapic",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+ | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+ .shift = 32,
+ .set_mode = lapic_timer_setup,
+ .set_next_event = lapic_next_event,
+ .broadcast = lapic_timer_broadcast,
+ .rating = 100,
+ .irq = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
+static int lapic_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ apic_write(APIC_TMICT, delta);
+ return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ unsigned long flags;
+ unsigned int v;
+
+ /* Lapic used as dummy for broadcast ? */
+ if (evt->features & CLOCK_EVT_FEAT_DUMMY)
+ return;
+
+ local_irq_save(flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_ONESHOT:
+ __setup_APIC_LVTT(calibration_result,
+ mode != CLOCK_EVT_MODE_PERIODIC, 1);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ v = apic_read(APIC_LVTT);
+ v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+ apic_write(APIC_LVTT, v);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
/*
- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
- * IPIs in place of local APIC timers
+ * Local APIC timer broadcast function
*/
-static cpumask_t timer_interrupt_broadcast_ipi_mask;
-
-/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer __read_mostly = 0;
+static void lapic_timer_broadcast(cpumask_t mask)
+{
+#ifdef CONFIG_SMP
+ send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#endif
+}
static void apic_pm_activate(void);
@@ -184,7 +246,10 @@ void disconnect_bsp_APIC(int virt_wire_setup)
apic_write(APIC_SPIV, value);
if (!virt_wire_setup) {
- /* For LVT0 make it edge triggered, active high, external and enabled */
+ /*
+ * For LVT0 make it edge triggered, active high,
+ * external and enabled
+ */
value = apic_read(APIC_LVT0);
value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -420,10 +485,12 @@ void __cpuinit setup_local_APIC (void)
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
if (!smp_processor_id() && !value) {
value = APIC_DM_EXTINT;
- apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
+ apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
+ smp_processor_id());
} else {
value = APIC_DM_EXTINT | APIC_LVT_MASKED;
- apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
+ apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
+ smp_processor_id());
}
apic_write(APIC_LVT0, value);
@@ -706,8 +773,8 @@ void __init init_apic_mappings(void)
apic_phys = mp_lapic_addr;
set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
- apic_mapped = 1;
- apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+ apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
+ APIC_BASE, apic_phys);
/* Put local APIC into the resource map. */
lapic_resource.start = apic_phys;
@@ -730,12 +797,14 @@ void __init init_apic_mappings(void)
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mpc_apicaddr;
} else {
- ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+ ioapic_phys = (unsigned long)
+ alloc_bootmem_pages(PAGE_SIZE);
ioapic_phys = __pa(ioapic_phys);
}
set_fixmap_nocache(idx, ioapic_phys);
- apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
- __fix_to_virt(idx), ioapic_phys);
+ apic_printk(APIC_VERBOSE,
+ "mapped IOAPIC to %016lx (%016lx)\n",
+ __fix_to_virt(idx), ioapic_phys);
idx++;
if (ioapic_res != NULL) {
@@ -758,16 +827,14 @@ void __init init_apic_mappings(void)
* P5 APIC double write bug.
*/
-#define APIC_DIVISOR 16
-
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
{
unsigned int lvtt_value, tmp_value;
- int cpu = smp_processor_id();
- lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-
- if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
+ lvtt_value = LOCAL_TIMER_VECTOR;
+ if (!oneshot)
+ lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+ if (!irqen)
lvtt_value |= APIC_LVT_MASKED;
apic_write(APIC_LVTT, lvtt_value);
@@ -780,44 +847,18 @@ static void __setup_APIC_LVTT(unsigned int clocks)
& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
| APIC_TDR_DIV_16);
- apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+ if (!oneshot)
+ apic_write(APIC_TMICT, clocks);
}
-static void setup_APIC_timer(unsigned int clocks)
+static void setup_APIC_timer(void)
{
- unsigned long flags;
+ struct clock_event_device *levt = &__get_cpu_var(lapic_events);
- local_irq_save(flags);
+ memcpy(levt, &lapic_clockevent, sizeof(*levt));
+ levt->cpumask = cpumask_of_cpu(smp_processor_id());
- /* wait for irq slice */
- if (hpet_address && hpet_use_timer) {
- u32 trigger = hpet_readl(HPET_T0_CMP);
- while (hpet_readl(HPET_T0_CMP) == trigger)
- /* do nothing */ ;
- } else {
- int c1, c2;
- outb_p(0x00, 0x43);
- c2 = inb_p(0x40);
- c2 |= inb_p(0x40) << 8;
- do {
- c1 = c2;
- outb_p(0x00, 0x43);
- c2 = inb_p(0x40);
- c2 |= inb_p(0x40) << 8;
- } while (c2 - c1 < 300);
- }
- __setup_APIC_LVTT(clocks);
- /* Turn off PIT interrupt if we use APIC timer as main timer.
- Only works with the PM timer right now
- TBD fix it for HPET too. */
- if ((pmtmr_ioport != 0) &&
- smp_processor_id() == boot_cpu_id &&
- apic_runs_main_timer == 1 &&
- !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
- stop_timer_interrupt();
- apic_runs_main_timer++;
- }
- local_irq_restore(flags);
+ clockevents_register_device(levt);
}
/*
@@ -835,17 +876,22 @@ static void setup_APIC_timer(unsigned int clocks)
#define TICK_COUNT 100000000
-static int __init calibrate_APIC_clock(void)
+static void __init calibrate_APIC_clock(void)
{
unsigned apic, apic_start;
unsigned long tsc, tsc_start;
int result;
+
+ local_irq_disable();
+
/*
* Put whatever arbitrary (but long enough) timeout
* value into the APIC clock, we just want to get the
* counter running for calibration.
+ *
+ * No interrupt enable !
*/
- __setup_APIC_LVTT(4000000000);
+ __setup_APIC_LVTT(250000000, 0, 0);
apic_start = apic_read(APIC_TMCCT);
#ifdef CONFIG_X86_PM_TIMER
@@ -867,123 +913,88 @@ static int __init calibrate_APIC_clock(void)
result = (apic_start - apic) * 1000L * tsc_khz /
(tsc - tsc_start);
}
- printk("result %d\n", result);
+ local_irq_enable();
+
+ printk(KERN_DEBUG "APIC timer calibration result %d\n", result);
printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
result / 1000 / 1000, result / 1000 % 1000);
- return result * APIC_DIVISOR / HZ;
-}
+ /* Calculate the scaled math multiplication factor */
+ lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+ lapic_clockevent.max_delta_ns =
+ clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+ lapic_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xF, &lapic_clockevent);
-static unsigned int calibration_result;
+ calibration_result = result / HZ;
+}
void __init setup_boot_APIC_clock (void)
{
+ /*
+ * The local apic timer can be disabled via the kernel commandline.
+ * Register the lapic timer as a dummy clock event source on SMP
+ * systems, so the broadcast mechanism is used. On UP systems simply
+ * ignore it.
+ */
if (disable_apic_timer) {
printk(KERN_INFO "Disabling APIC timer\n");
+ /* No broadcast on UP ! */
+ if (num_possible_cpus() > 1)
+ setup_APIC_timer();
return;
}
printk(KERN_INFO "Using local APIC timer interrupts.\n");
- using_apic_timer = 1;
-
- local_irq_disable();
+ calibrate_APIC_clock();
- calibration_result = calibrate_APIC_clock();
/*
- * Now set up the timer for real.
+ * If nmi_watchdog is set to IO_APIC, we need the
+ * PIT/HPET going. Otherwise register lapic as a dummy
+ * device.
*/
- setup_APIC_timer(calibration_result);
-
- local_irq_enable();
-}
-
-void __cpuinit setup_secondary_APIC_clock(void)
-{
- local_irq_disable(); /* FIXME: Do we need this? --RR */
- setup_APIC_timer(calibration_result);
- local_irq_enable();
-}
-
-void disable_APIC_timer(void)
-{
- if (using_apic_timer) {
- unsigned long v;
+ if (nmi_watchdog != NMI_IO_APIC)
+ lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+ else
+ printk(KERN_WARNING "APIC timer registered as dummy,"
+ " due to nmi_watchdog=1!\n");
- v = apic_read(APIC_LVTT);
- /*
- * When an illegal vector value (0-15) is written to an LVT
- * entry and delivery mode is Fixed, the APIC may signal an
- * illegal vector error, with out regard to whether the mask
- * bit is set or whether an interrupt is actually seen on input.
- *
- * Boot sequence might call this function when the LVTT has
- * '0' vector value. So make sure vector field is set to
- * valid value.
- */
- v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
- apic_write(APIC_LVTT, v);
- }
+ setup_APIC_timer();
}
-void enable_APIC_timer(void)
+/*
+ * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
+ * C1E flag only in the secondary CPU, so when we detect the wreckage
+ * we already have enabled the boot CPU local apic timer. Check, if
+ * disable_apic_timer is set and the DUMMY flag is cleared. If yes,
+ * set the DUMMY flag again and force the broadcast mode in the
+ * clockevents layer.
+ */
+void __cpuinit check_boot_apic_timer_broadcast(void)
{
- int cpu = smp_processor_id();
+ struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id);
- if (using_apic_timer &&
- !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
- unsigned long v;
+ if (!disable_apic_timer ||
+ (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
+ return;
- v = apic_read(APIC_LVTT);
- apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
- }
-}
+ printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
+ lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
+ levt->features |= CLOCK_EVT_FEAT_DUMMY;
-void switch_APIC_timer_to_ipi(void *cpumask)
-{
- cpumask_t mask = *(cpumask_t *)cpumask;
- int cpu = smp_processor_id();
-
- if (cpu_isset(cpu, mask) &&
- !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
- disable_APIC_timer();
- cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
- }
+ local_irq_enable();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
+ local_irq_disable();
}
-EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
-void smp_send_timer_broadcast_ipi(void)
+void __cpuinit setup_secondary_APIC_clock(void)
{
- int cpu = smp_processor_id();
- cpumask_t mask;
-
- cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
-
- if (cpu_isset(cpu, mask)) {
- cpu_clear(cpu, mask);
- add_pda(apic_timer_irqs, 1);
- smp_local_timer_interrupt();
- }
-
- if (!cpus_empty(mask)) {
- send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
- }
+ check_boot_apic_timer_broadcast();
+ setup_APIC_timer();
}
-void switch_ipi_to_APIC_timer(void *cpumask)
-{
- cpumask_t mask = *(cpumask_t *)cpumask;
- int cpu = smp_processor_id();
-
- if (cpu_isset(cpu, mask) &&
- cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
- cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
- enable_APIC_timer();
- }
-}
-EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
-
int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
@@ -997,8 +1008,6 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
apic_write(reg, v);
}
-#undef APIC_DIVISOR
-
/*
* Local timer interrupt handler. It does both profiling and
* process statistics/rescheduling.
@@ -1011,22 +1020,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
void smp_local_timer_interrupt(void)
{
- profile_tick(CPU_PROFILING);
-#ifdef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
- if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
- main_timer_handler();
+ int cpu = smp_processor_id();
+ struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
/*
- * We take the 'long' return path, and there every subsystem
- * grabs the appropriate locks (kernel lock/ irq lock).
+ * Normally we should not be here till LAPIC has been initialized but
+ * in some cases like kdump, its possible that there is a pending LAPIC
+ * timer interrupt from previous kernel's context and is delivered in
+ * new kernel the moment interrupts are enabled.
*
- * We might want to decouple profiling from the 'long path',
- * and do the profiling totally in assembly.
- *
- * Currently this isn't too much of an issue (performance wise),
- * we can take more than 100K local irqs per second on a 100 MHz P5.
+ * Interrupts are enabled early and LAPIC is setup much later, hence
+ * its possible that when we get here evt->event_handler is NULL.
+ * Check for event_handler being NULL and discard the interrupt as
+ * spurious.
+ */
+ if (!evt->event_handler) {
+ printk(KERN_WARNING
+ "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+ /* Switch it off */
+ lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
+ return;
+ }
+
+ /*
+ * the NMI deadlock-detector uses this.
*/
+ add_pda(apic_timer_irqs, 1);
+
+ evt->event_handler(evt);
}
/*
@@ -1042,11 +1063,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
struct pt_regs *old_regs = set_irq_regs(regs);
/*
- * the NMI deadlock-detector uses this.
- */
- add_pda(apic_timer_irqs, 1);
-
- /*
* NOTE! We'd better ACK the irq immediately,
* because timer handling can be slow.
*/
@@ -1225,29 +1241,13 @@ static __init int setup_noapictimer(char *str)
disable_apic_timer = 1;
return 1;
}
-
-static __init int setup_apicmaintimer(char *str)
-{
- apic_runs_main_timer = 1;
- nohpet = 1;
- return 1;
-}
-__setup("apicmaintimer", setup_apicmaintimer);
-
-static __init int setup_noapicmaintimer(char *str)
-{
- apic_runs_main_timer = -1;
- return 1;
-}
-__setup("noapicmaintimer", setup_noapicmaintimer);
+__setup("noapictimer", setup_noapictimer);
static __init int setup_apicpmtimer(char *s)
{
apic_calibrate_pmtmr = 1;
notsc_setup(NULL);
- return setup_apicmaintimer(NULL);
+ return 0;
}
__setup("apicpmtimer", setup_apicpmtimer);
-__setup("noapictimer", setup_noapictimer);
-
diff --git a/arch/x86/kernel/bugs_64.c b/arch/x86/kernel/bugs_64.c
index 4e5e9d364d6..9a189cef640 100644
--- a/arch/x86/kernel/bugs_64.c
+++ b/arch/x86/kernel/bugs_64.c
@@ -1,6 +1,4 @@
/*
- * arch/x86_64/kernel/bugs.c
- *
* Copyright (C) 1994 Linus Torvalds
* Copyright (C) 2000 SuSE
*/
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 59266f03d1c..205fd5ba57f 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -1,6 +1,4 @@
/*
- * arch/i386/cpu/bugs.c
- *
* Copyright (C) 1994 Linus Torvalds
*
* Cyrix stuff, June 1998 by:
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index b6434a7ef8b..ffd01e5dcb5 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -646,7 +646,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency =
perf->states[i].transition_latency * 1000;
}
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 66acd503991..32f0bda3fc9 100644
--- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@ -363,7 +363,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
policy->cur = nforce2_get(policy->cpu);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
return 0;
}
diff --git a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
index f43d98e11cc..c11baaf9f2b 100644
--- a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
+++ b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
@@ -253,7 +253,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
f_table[k].frequency = CPUFREQ_TABLE_END;
}
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
policy->cur = fsb * current_multiplier;
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
index f317276afa7..1e7ae7dafcf 100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@ -219,7 +219,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
}
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = elanfreq_get_cpu_frequency(0);
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index 461dabc4e49..ed2bda127c4 100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@ -420,7 +420,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
policy->min = maxfreq / POLICY_MIN_DIV;
policy->max = maxfreq;
policy->cur = curfreq;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = maxfreq / max_duration;
policy->cpuinfo.max_freq = maxfreq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c
index f0cce3c2dc3..5045f5d583c 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -710,6 +710,10 @@ static int enable_arbiter_disable(void)
reg = 0x78;
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
NULL);
+ /* Find PM133/VT8605 host bridge */
+ if (dev == NULL)
+ dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_8605_0, NULL);
/* Find CLE266 host bridge */
if (dev == NULL) {
reg = 0x76;
@@ -918,7 +922,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
longhaul_setup_voltagescaling();
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 200000; /* nsec */
policy->cur = calc_speed(longhaul_get_cpu_mult());
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 4c76b511e19..8eb414b906d 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -229,7 +229,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* assumed */
policy->cur = stock_freq;
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index f89524051e4..6d028533931 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@ -160,7 +160,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = busfreq * max_multiplier;
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index ca3e1d34188..7decd6a50ff 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -637,8 +637,6 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
minimum_speed/1000, maximum_speed/1000);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
policy->cur = powernow_get(0);
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 34ed53a0673..b273b69cfdd 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -76,7 +76,10 @@ static u32 find_khz_freq_from_fid(u32 fid)
/* Return a frequency in MHz, given an input fid and did */
static u32 find_freq_from_fiddid(u32 fid, u32 did)
{
- return 100 * (fid + 0x10) >> did;
+ if (current_cpu_data.x86 == 0x10)
+ return 100 * (fid + 0x10) >> did;
+ else
+ return 100 * (fid + 0x8) >> did;
}
static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
@@ -1208,7 +1211,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
/* run on any CPU again */
set_cpus_allowed(current, oldmask);
- pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
if (cpu_family == CPU_HW_PSTATE)
pol->cpus = cpumask_of_cpu(pol->cpu);
else
@@ -1325,21 +1327,16 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
static int __cpuinit powernowk8_init(void)
{
unsigned int i, supported_cpus = 0;
- unsigned int booted_cores = 1;
for_each_online_cpu(i) {
if (check_supported_cpu(i))
supported_cpus++;
}
-#ifdef CONFIG_SMP
- booted_cores = cpu_data[0].booted_cores;
-#endif
-
if (supported_cpus == num_online_cpus()) {
printk(KERN_INFO PFX "Found %d %s "
"processors (%d cpu cores) (" VERSION ")\n",
- supported_cpus/booted_cores,
+ num_online_nodes(),
boot_cpu_data.x86_model_id, supported_cpus);
return cpufreq_register_driver(&cpufreq_amd64_driver);
}
diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
index b8fb4b521c6..d9f3e90a7ae 100644
--- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
+++ b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
@@ -111,7 +111,6 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV;
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = sc520_freq_get_cpu_frequency(0);
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
index 6c5dc2c85ae..811d4743854 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -393,7 +393,6 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
freq = get_cur_freq(policy->cpu);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
policy->cur = freq;
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
index a5b2346faf1..36685e8f7be 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
@@ -348,7 +348,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
(speed / 1000));
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cur = speed;
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
index e1c509aa305..f2b5a621d27 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
@@ -290,7 +290,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
(speed / 1000));
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = speed;
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 5c2faa10e9f..f4548c93ccf 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -11,8 +11,6 @@
* ----------------------------------------------------------------------- */
/*
- * cpuid.c
- *
* x86 CPUID access device
*
* This device is accessed by lseek() to the appropriate CPUID level
diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c
index 3f532df488b..32e75d0731a 100644
--- a/arch/x86/kernel/crash_dump_32.c
+++ b/arch/x86/kernel/crash_dump_32.c
@@ -1,5 +1,5 @@
/*
- * kernel/crash_dump.c - Memory preserving reboot related code.
+ * Memory preserving reboot related code.
*
* Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
* Copyright (C) IBM Corporation, 2004. All rights reserved
diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c
index 942deac4d43..15e6c6bc4a4 100644
--- a/arch/x86/kernel/crash_dump_64.c
+++ b/arch/x86/kernel/crash_dump_64.c
@@ -1,5 +1,5 @@
/*
- * kernel/crash_dump.c - Memory preserving reboot related code.
+ * Memory preserving reboot related code.
*
* Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
* Copyright (C) IBM Corporation, 2004. All rights reserved
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 290b7bc82da..8099fea0a72 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -251,6 +251,7 @@ check_userspace:
jb resume_kernel # not returning to v8086 or userspace
ENTRY(resume_userspace)
+ LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
@@ -338,6 +339,7 @@ sysenter_past_esp:
jae syscall_badsys
call *sys_call_table(,%eax,4)
movl %eax,PT_EAX(%esp)
+ LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY)
TRACE_IRQS_OFF
movl TI_flags(%ebp), %ecx
@@ -377,6 +379,7 @@ syscall_call:
call *sys_call_table(,%eax,4)
movl %eax,PT_EAX(%esp) # store the return value
syscall_exit:
+ LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
@@ -467,6 +470,7 @@ work_pending:
jz work_notifysig
work_resched:
call schedule
+ LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 1d232e5f565..f1cacd4897f 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -244,6 +244,7 @@ ret_from_sys_call:
movl $_TIF_ALLWORK_MASK,%edi
/* edi: flagmask */
sysret_check:
+ LOCKDEP_SYS_EXIT
GET_THREAD_INFO(%rcx)
cli
TRACE_IRQS_OFF
@@ -333,6 +334,7 @@ int_ret_from_sys_call:
movl $_TIF_ALLWORK_MASK,%edi
/* edi: mask to check */
int_with_check:
+ LOCKDEP_SYS_EXIT_IRQ
GET_THREAD_INFO(%rcx)
movl threadinfo_flags(%rcx),%edx
andl %edi,%edx
@@ -544,11 +546,13 @@ exit_intr:
retint_with_reschedule:
movl $_TIF_WORK_MASK,%edi
retint_check:
+ LOCKDEP_SYS_EXIT_IRQ
movl threadinfo_flags(%rcx),%edx
andl %edi,%edx
CFI_REMEMBER_STATE
jnz retint_careful
-retint_swapgs:
+
+retint_swapgs: /* return to user-space */
/*
* The iretq could re-enable interrupts:
*/
@@ -557,7 +561,7 @@ retint_swapgs:
swapgs
jmp restore_args
-retint_restore_args:
+retint_restore_args: /* return to kernel space */
cli
/*
* The iretq could re-enable interrupts:
@@ -866,26 +870,21 @@ error_sti:
movq ORIG_RAX(%rsp),%rsi /* get error code */
movq $-1,ORIG_RAX(%rsp)
call *%rax
- /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
-error_exit:
- movl %ebx,%eax
+ /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
+error_exit:
+ movl %ebx,%eax
RESTORE_REST
cli
TRACE_IRQS_OFF
GET_THREAD_INFO(%rcx)
testl %eax,%eax
jne retint_kernel
+ LOCKDEP_SYS_EXIT_IRQ
movl threadinfo_flags(%rcx),%edx
movl $_TIF_WORK_MASK,%edi
andl %edi,%edx
jnz retint_careful
- /*
- * The iret might restore flags:
- */
- TRACE_IRQS_IRETQ
- swapgs
- RESTORE_ARGS 0,8,0
- jmp iret_label
+ jmp retint_swapgs
CFI_ENDPROC
error_kernelspace:
diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c
index 41e8aec4c61..f12d8c5d980 100644
--- a/arch/x86/kernel/geode_32.c
+++ b/arch/x86/kernel/geode_32.c
@@ -145,10 +145,14 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
static int __init geode_southbridge_init(void)
{
+ int timers;
+
if (!is_geode())
return -ENODEV;
init_lbars();
+ timers = geode_mfgpt_detect();
+ printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers);
return 0;
}
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 6c34bdd22e2..8561f626eda 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/x86_64/kernel/head64.c -- prepare to run common code
+ * prepare to run common code
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
*/
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet.c
index 533d4932bc7..f8367074da0 100644
--- a/arch/x86/kernel/hpet_32.c
+++ b/arch/x86/kernel/hpet.c
@@ -1,5 +1,6 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/hpet.h>
#include <linux/init.h>
@@ -7,11 +8,11 @@
#include <linux/pm.h>
#include <linux/delay.h>
+#include <asm/fixmap.h>
#include <asm/hpet.h>
+#include <asm/i8253.h>
#include <asm/io.h>
-extern struct clock_event_device *global_clock_event;
-
#define HPET_MASK CLOCKSOURCE_MASK(32)
#define HPET_SHIFT 22
@@ -22,9 +23,9 @@ extern struct clock_event_device *global_clock_event;
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
-static void __iomem * hpet_virt_address;
+static void __iomem *hpet_virt_address;
-static inline unsigned long hpet_readl(unsigned long a)
+unsigned long hpet_readl(unsigned long a)
{
return readl(hpet_virt_address + a);
}
@@ -34,6 +35,36 @@ static inline void hpet_writel(unsigned long d, unsigned long a)
writel(d, hpet_virt_address + a);
}
+#ifdef CONFIG_X86_64
+
+#include <asm/pgtable.h>
+
+static inline void hpet_set_mapping(void)
+{
+ set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+ __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+ hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+ hpet_virt_address = NULL;
+}
+
+#else
+
+static inline void hpet_set_mapping(void)
+{
+ hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+ iounmap(hpet_virt_address);
+ hpet_virt_address = NULL;
+}
+#endif
+
/*
* HPET command line enable / disable
*/
@@ -49,6 +80,13 @@ static int __init hpet_setup(char* str)
}
__setup("hpet=", hpet_setup);
+static int __init disable_hpet(char *str)
+{
+ boot_hpet_disable = 1;
+ return 1;
+}
+__setup("nohpet", disable_hpet);
+
static inline int is_hpet_capable(void)
{
return (!boot_hpet_disable && hpet_address);
@@ -83,7 +121,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
memset(&hd, 0, sizeof (hd));
hd.hd_phys_address = hpet_address;
- hd.hd_address = hpet_virt_address;
+ hd.hd_address = hpet;
hd.hd_nirqs = nrtimers;
hd.hd_flags = HPET_DATA_PLATFORM;
hpet_reserve_timer(&hd, 0);
@@ -111,9 +149,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { }
*/
static unsigned long hpet_period;
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt);
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
struct clock_event_device *evt);
/*
@@ -122,10 +160,11 @@ static int hpet_next_event(unsigned long delta,
static struct clock_event_device hpet_clockevent = {
.name = "hpet",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = hpet_set_mode,
- .set_next_event = hpet_next_event,
+ .set_mode = hpet_legacy_set_mode,
+ .set_next_event = hpet_legacy_next_event,
.shift = 32,
.irq = 0,
+ .rating = 50,
};
static void hpet_start_counter(void)
@@ -140,7 +179,18 @@ static void hpet_start_counter(void)
hpet_writel(cfg, HPET_CFG);
}
-static void hpet_enable_int(void)
+static void hpet_resume_device(void)
+{
+ force_hpet_resume();
+}
+
+static void hpet_restart_counter(void)
+{
+ hpet_resume_device();
+ hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
{
unsigned long cfg = hpet_readl(HPET_CFG);
@@ -149,7 +199,39 @@ static void hpet_enable_int(void)
hpet_legacy_int_enabled = 1;
}
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_clockevent_register(void)
+{
+ uint64_t hpet_freq;
+
+ /* Start HPET legacy interrupts */
+ hpet_enable_legacy_int();
+
+ /*
+ * The period is a femto seconds value. We need to calculate the
+ * scaled math multiplication factor for nanosecond to hpet tick
+ * conversion.
+ */
+ hpet_freq = 1000000000000000ULL;
+ do_div(hpet_freq, hpet_period);
+ hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+ NSEC_PER_SEC, 32);
+ /* Calculate the min / max delta */
+ hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+ &hpet_clockevent);
+ hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+ &hpet_clockevent);
+
+ /*
+ * Start hpet with the boot cpu mask and make it
+ * global after the IO_APIC has been initialized.
+ */
+ hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+ clockevents_register_device(&hpet_clockevent);
+ global_clock_event = &hpet_clockevent;
+ printk(KERN_DEBUG "hpet clockevent registered\n");
+}
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
unsigned long cfg, cmp, now;
@@ -190,12 +272,12 @@ static void hpet_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_RESUME:
- hpet_enable_int();
+ hpet_enable_legacy_int();
break;
}
}
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
struct clock_event_device *evt)
{
unsigned long cnt;
@@ -215,6 +297,13 @@ static cycle_t read_hpet(void)
return (cycle_t)hpet_readl(HPET_COUNTER);
}
+#ifdef CONFIG_X86_64
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+ return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+#endif
+
static struct clocksource clocksource_hpet = {
.name = "hpet",
.rating = 250,
@@ -222,61 +311,17 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .resume = hpet_start_counter,
+ .resume = hpet_restart_counter,
+#ifdef CONFIG_X86_64
+ .vread = vread_hpet,
+#endif
};
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
+static int hpet_clocksource_register(void)
{
- unsigned long id;
- uint64_t hpet_freq;
u64 tmp, start, now;
cycle_t t1;
- if (!is_hpet_capable())
- return 0;
-
- hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
-
- /*
- * Read the period and check for a sane value:
- */
- hpet_period = hpet_readl(HPET_PERIOD);
- if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
- goto out_nohpet;
-
- /*
- * The period is a femto seconds value. We need to calculate the
- * scaled math multiplication factor for nanosecond to hpet tick
- * conversion.
- */
- hpet_freq = 1000000000000000ULL;
- do_div(hpet_freq, hpet_period);
- hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
- NSEC_PER_SEC, 32);
- /* Calculate the min / max delta */
- hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
- &hpet_clockevent);
- hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
- &hpet_clockevent);
-
- /*
- * Read the HPET ID register to retrieve the IRQ routing
- * information and the number of channels
- */
- id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
- /*
- * The legacy routing mode needs at least two channels, tick timer
- * and the rtc emulation channel.
- */
- if (!(id & HPET_ID_NUMBER))
- goto out_nohpet;
-#endif
-
/* Start the counter */
hpet_start_counter();
@@ -298,7 +343,7 @@ int __init hpet_enable(void)
if (t1 == read_hpet()) {
printk(KERN_WARNING
"HPET counter not counting. HPET disabled\n");
- goto out_nohpet;
+ return -ENODEV;
}
/* Initialize and register HPET clocksource
@@ -319,27 +364,84 @@ int __init hpet_enable(void)
clocksource_register(&clocksource_hpet);
+ return 0;
+}
+
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
+{
+ unsigned long id;
+
+ if (!is_hpet_capable())
+ return 0;
+
+ hpet_set_mapping();
+
+ /*
+ * Read the period and check for a sane value:
+ */
+ hpet_period = hpet_readl(HPET_PERIOD);
+ if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+ goto out_nohpet;
+
+ /*
+ * Read the HPET ID register to retrieve the IRQ routing
+ * information and the number of channels
+ */
+ id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+ /*
+ * The legacy routing mode needs at least two channels, tick timer
+ * and the rtc emulation channel.
+ */
+ if (!(id & HPET_ID_NUMBER))
+ goto out_nohpet;
+#endif
+
+ if (hpet_clocksource_register())
+ goto out_nohpet;
+
if (id & HPET_ID_LEGSUP) {
- hpet_enable_int();
- hpet_reserve_platform_timers(id);
- /*
- * Start hpet with the boot cpu mask and make it
- * global after the IO_APIC has been initialized.
- */
- hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
- clockevents_register_device(&hpet_clockevent);
- global_clock_event = &hpet_clockevent;
+ hpet_legacy_clockevent_register();
return 1;
}
return 0;
out_nohpet:
- iounmap(hpet_virt_address);
- hpet_virt_address = NULL;
+ hpet_clear_mapping();
boot_hpet_disable = 1;
return 0;
}
+/*
+ * Needs to be late, as the reserve_timer code calls kalloc !
+ *
+ * Not a problem on i386 as hpet_enable is called from late_time_init,
+ * but on x86_64 it is necessary !
+ */
+static __init int hpet_late_init(void)
+{
+ if (boot_hpet_disable)
+ return -ENODEV;
+
+ if (!hpet_address) {
+ if (!force_hpet_address)
+ return -ENODEV;
+
+ hpet_address = force_hpet_address;
+ hpet_enable();
+ if (!hpet_virt_address)
+ return -ENODEV;
+ }
+
+ hpet_reserve_platform_timers(hpet_readl(HPET_ID));
+
+ return 0;
+}
+fs_initcall(hpet_late_init);
#ifdef CONFIG_HPET_EMULATE_RTC
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c
deleted file mode 100644
index e2d1b912e15..00000000000
--- a/arch/x86/kernel/hpet_64.c
+++ /dev/null
@@ -1,493 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/hpet.h>
-#include <asm/pgtable.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/hpet.h>
-
-#define HPET_MASK 0xFFFFFFFF
-#define HPET_SHIFT 22
-
-/* FSEC = 10^-15 NSEC = 10^-9 */
-#define FSEC_PER_NSEC 1000000
-
-int nohpet __initdata;
-
-unsigned long hpet_address;
-unsigned long hpet_period; /* fsecs / HPET clock */
-unsigned long hpet_tick; /* HPET clocks / interrupt */
-
-int hpet_use_timer; /* Use counter of hpet for time keeping,
- * otherwise PIT
- */
-
-#ifdef CONFIG_HPET
-static __init int late_hpet_init(void)
-{
- struct hpet_data hd;
- unsigned int ntimer;
-
- if (!hpet_address)
- return 0;
-
- memset(&hd, 0, sizeof(hd));
-
- ntimer = hpet_readl(HPET_ID);
- ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
- ntimer++;
-
- /*
- * Register with driver.
- * Timer0 and Timer1 is used by platform.
- */
- hd.hd_phys_address = hpet_address;
- hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
- hd.hd_nirqs = ntimer;
- hd.hd_flags = HPET_DATA_PLATFORM;
- hpet_reserve_timer(&hd, 0);
-#ifdef CONFIG_HPET_EMULATE_RTC
- hpet_reserve_timer(&hd, 1);
-#endif
- hd.hd_irq[0] = HPET_LEGACY_8254;
- hd.hd_irq[1] = HPET_LEGACY_RTC;
- if (ntimer > 2) {
- struct hpet *hpet;
- struct hpet_timer *timer;
- int i;
-
- hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
- timer = &hpet->hpet_timers[2];
- for (i = 2; i < ntimer; timer++, i++)
- hd.hd_irq[i] = (timer->hpet_config &
- Tn_INT_ROUTE_CNF_MASK) >>
- Tn_INT_ROUTE_CNF_SHIFT;
-
- }
-
- hpet_alloc(&hd);
- return 0;
-}
-fs_initcall(late_hpet_init);
-#endif
-
-int hpet_timer_stop_set_go(unsigned long tick)
-{
- unsigned int cfg;
-
-/*
- * Stop the timers and reset the main counter.
- */
-
- cfg = hpet_readl(HPET_CFG);
- cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
- hpet_writel(cfg, HPET_CFG);
- hpet_writel(0, HPET_COUNTER);
- hpet_writel(0, HPET_COUNTER + 4);
-
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
- if (hpet_use_timer) {
- hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
- HPET_TN_32BIT, HPET_T0_CFG);
- hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
- hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
- cfg |= HPET_CFG_LEGACY;
- }
-/*
- * Go!
- */
-
- cfg |= HPET_CFG_ENABLE;
- hpet_writel(cfg, HPET_CFG);
-
- return 0;
-}
-
-static cycle_t read_hpet(void)
-{
- return (cycle_t)hpet_readl(HPET_COUNTER);
-}
-
-static cycle_t __vsyscall_fn vread_hpet(void)
-{
- return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
-}
-
-struct clocksource clocksource_hpet = {
- .name = "hpet",
- .rating = 250,
- .read = read_hpet,
- .mask = (cycle_t)HPET_MASK,
- .mult = 0, /* set below */
- .shift = HPET_SHIFT,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .vread = vread_hpet,
-};
-
-int __init hpet_arch_init(void)
-{
- unsigned int id;
- u64 tmp;
-
- if (!hpet_address)
- return -1;
- set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
- __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
-
-/*
- * Read the period, compute tick and quotient.
- */
-
- id = hpet_readl(HPET_ID);
-
- if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
- return -1;
-
- hpet_period = hpet_readl(HPET_PERIOD);
- if (hpet_period < 100000 || hpet_period > 100000000)
- return -1;
-
- hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
-
- hpet_use_timer = (id & HPET_ID_LEGSUP);
-
- /*
- * hpet period is in femto seconds per cycle
- * so we need to convert this to ns/cyc units
- * aproximated by mult/2^shift
- *
- * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
- * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
- * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
- * (fsec/cyc << shift)/1000000 = mult
- * (hpet_period << shift)/FSEC_PER_NSEC = mult
- */
- tmp = (u64)hpet_period << HPET_SHIFT;
- do_div(tmp, FSEC_PER_NSEC);
- clocksource_hpet.mult = (u32)tmp;
- clocksource_register(&clocksource_hpet);
-
- return hpet_timer_stop_set_go(hpet_tick);
-}
-
-int hpet_reenable(void)
-{
- return hpet_timer_stop_set_go(hpet_tick);
-}
-
-/*
- * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
- * it to the HPET timer of known frequency.
- */
-
-#define TICK_COUNT 100000000
-#define SMI_THRESHOLD 50000
-#define MAX_TRIES 5
-
-/*
- * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
- * occurs between the reads of the hpet & TSC.
- */
-static void __init read_hpet_tsc(int *hpet, int *tsc)
-{
- int tsc1, tsc2, hpet1, i;
-
- for (i = 0; i < MAX_TRIES; i++) {
- tsc1 = get_cycles_sync();
- hpet1 = hpet_readl(HPET_COUNTER);
- tsc2 = get_cycles_sync();
- if ((tsc2 - tsc1) < SMI_THRESHOLD)
- break;
- }
- *hpet = hpet1;
- *tsc = tsc2;
-}
-
-unsigned int __init hpet_calibrate_tsc(void)
-{
- int tsc_start, hpet_start;
- int tsc_now, hpet_now;
- unsigned long flags;
-
- local_irq_save(flags);
-
- read_hpet_tsc(&hpet_start, &tsc_start);
-
- do {
- local_irq_disable();
- read_hpet_tsc(&hpet_now, &tsc_now);
- local_irq_restore(flags);
- } while ((tsc_now - tsc_start) < TICK_COUNT &&
- (hpet_now - hpet_start) < TICK_COUNT);
-
- return (tsc_now - tsc_start) * 1000000000L
- / ((hpet_now - hpet_start) * hpet_period / 1000);
-}
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
- * is enabled, we support RTC interrupt functionality in software.
- * RTC has 3 kinds of interrupts:
- * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
- * is updated
- * 2) Alarm Interrupt - generate an interrupt at a specific time of day
- * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
- * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
- * (1) and (2) above are implemented using polling at a frequency of
- * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
- * overhead. (DEFAULT_RTC_INT_FREQ)
- * For (3), we use interrupts at 64Hz or user specified periodic
- * frequency, whichever is higher.
- */
-#include <linux/rtc.h>
-
-#define DEFAULT_RTC_INT_FREQ 64
-#define RTC_NUM_INTS 1
-
-static unsigned long UIE_on;
-static unsigned long prev_update_sec;
-
-static unsigned long AIE_on;
-static struct rtc_time alarm_time;
-
-static unsigned long PIE_on;
-static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
-static unsigned long PIE_count;
-
-static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
-static unsigned int hpet_t1_cmp; /* cached comparator register */
-
-int is_hpet_enabled(void)
-{
- return hpet_address != 0;
-}
-
-/*
- * Timer 1 for RTC, we do not use periodic interrupt feature,
- * even if HPET supports periodic interrupts on Timer 1.
- * The reason being, to set up a periodic interrupt in HPET, we need to
- * stop the main counter. And if we do that everytime someone diables/enables
- * RTC, we will have adverse effect on main kernel timer running on Timer 0.
- * So, for the time being, simulate the periodic interrupt in software.
- *
- * hpet_rtc_timer_init() is called for the first time and during subsequent
- * interuppts reinit happens through hpet_rtc_timer_reinit().
- */
-int hpet_rtc_timer_init(void)
-{
- unsigned int cfg, cnt;
- unsigned long flags;
-
- if (!is_hpet_enabled())
- return 0;
- /*
- * Set the counter 1 and enable the interrupts.
- */
- if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
- hpet_rtc_int_freq = PIE_freq;
- else
- hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
- local_irq_save(flags);
-
- cnt = hpet_readl(HPET_COUNTER);
- cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
- hpet_writel(cnt, HPET_T1_CMP);
- hpet_t1_cmp = cnt;
-
- cfg = hpet_readl(HPET_T1_CFG);
- cfg &= ~HPET_TN_PERIODIC;
- cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
- hpet_writel(cfg, HPET_T1_CFG);
-
- local_irq_restore(flags);
-
- return 1;
-}
-
-static void hpet_rtc_timer_reinit(void)
-{
- unsigned int cfg, cnt, ticks_per_int, lost_ints;
-
- if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
- cfg = hpet_readl(HPET_T1_CFG);
- cfg &= ~HPET_TN_ENABLE;
- hpet_writel(cfg, HPET_T1_CFG);
- return;
- }
-
- if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
- hpet_rtc_int_freq = PIE_freq;
- else
- hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
- /* It is more accurate to use the comparator value than current count.*/
- ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
- hpet_t1_cmp += ticks_per_int;
- hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
- /*
- * If the interrupt handler was delayed too long, the write above tries
- * to schedule the next interrupt in the past and the hardware would
- * not interrupt until the counter had wrapped around.
- * So we have to check that the comparator wasn't set to a past time.
- */
- cnt = hpet_readl(HPET_COUNTER);
- if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
- lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
- /* Make sure that, even with the time needed to execute
- * this code, the next scheduled interrupt has been moved
- * back to the future: */
- lost_ints++;
-
- hpet_t1_cmp += lost_ints * ticks_per_int;
- hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
- if (PIE_on)
- PIE_count += lost_ints;
-
- if (printk_ratelimit())
- printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
- hpet_rtc_int_freq);
- }
-}
-
-/*
- * The functions below are called from rtc driver.
- * Return 0 if HPET is not being used.
- * Otherwise do the necessary changes and return 1.
- */
-int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
-{
- if (!is_hpet_enabled())
- return 0;
-
- if (bit_mask & RTC_UIE)
- UIE_on = 0;
- if (bit_mask & RTC_PIE)
- PIE_on = 0;
- if (bit_mask & RTC_AIE)
- AIE_on = 0;
-
- return 1;
-}
-
-int hpet_set_rtc_irq_bit(unsigned long bit_mask)
-{
- int timer_init_reqd = 0;
-
- if (!is_hpet_enabled())
- return 0;
-
- if (!(PIE_on | AIE_on | UIE_on))
- timer_init_reqd = 1;
-
- if (bit_mask & RTC_UIE) {
- UIE_on = 1;
- }
- if (bit_mask & RTC_PIE) {
- PIE_on = 1;
- PIE_count = 0;
- }
- if (bit_mask & RTC_AIE) {
- AIE_on = 1;
- }
-
- if (timer_init_reqd)
- hpet_rtc_timer_init();
-
- return 1;
-}
-
-int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
-{
- if (!is_hpet_enabled())
- return 0;
-
- alarm_time.tm_hour = hrs;
- alarm_time.tm_min = min;
- alarm_time.tm_sec = sec;
-
- return 1;
-}
-
-int hpet_set_periodic_freq(unsigned long freq)
-{
- if (!is_hpet_enabled())
- return 0;
-
- PIE_freq = freq;
- PIE_count = 0;
-
- return 1;
-}
-
-int hpet_rtc_dropped_irq(void)
-{
- if (!is_hpet_enabled())
- return 0;
-
- return 1;
-}
-
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
-{
- struct rtc_time curr_time;
- unsigned long rtc_int_flag = 0;
- int call_rtc_interrupt = 0;
-
- hpet_rtc_timer_reinit();
-
- if (UIE_on | AIE_on) {
- rtc_get_rtc_time(&curr_time);
- }
- if (UIE_on) {
- if (curr_time.tm_sec != prev_update_sec) {
- /* Set update int info, call real rtc int routine */
- call_rtc_interrupt = 1;
- rtc_int_flag = RTC_UF;
- prev_update_sec = curr_time.tm_sec;
- }
- }
- if (PIE_on) {
- PIE_count++;
- if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
- /* Set periodic int info, call real rtc int routine */
- call_rtc_interrupt = 1;
- rtc_int_flag |= RTC_PF;
- PIE_count = 0;
- }
- }
- if (AIE_on) {
- if ((curr_time.tm_sec == alarm_time.tm_sec) &&
- (curr_time.tm_min == alarm_time.tm_min) &&
- (curr_time.tm_hour == alarm_time.tm_hour)) {
- /* Set alarm int info, call real rtc int routine */
- call_rtc_interrupt = 1;
- rtc_int_flag |= RTC_AF;
- }
- }
- if (call_rtc_interrupt) {
- rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
- rtc_interrupt(rtc_int_flag, dev_id);
- }
- return IRQ_HANDLED;
-}
-#endif
-
-static int __init nohpet_setup(char *s)
-{
- nohpet = 1;
- return 1;
-}
-
-__setup("nohpet", nohpet_setup);
diff --git a/arch/x86/kernel/i387_32.c b/arch/x86/kernel/i387_32.c
index 665847281ed..7d2e12f6c78 100644
--- a/arch/x86/kernel/i387_32.c
+++ b/arch/x86/kernel/i387_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/i387.c
- *
* Copyright (C) 1994 Linus Torvalds
*
* Pentium III FXSR, SSE support
diff --git a/arch/x86/kernel/i387_64.c b/arch/x86/kernel/i387_64.c
index 1d58c13bc6b..56c1f114710 100644
--- a/arch/x86/kernel/i387_64.c
+++ b/arch/x86/kernel/i387_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/i387.c
- *
* Copyright (C) 1994 Linus Torvalds
* Copyright (C) 2002 Andi Kleen, SuSE Labs
*
diff --git a/arch/x86/kernel/i8237.c b/arch/x86/kernel/i8237.c
index 6f508e8d7c5..29313832df0 100644
--- a/arch/x86/kernel/i8237.c
+++ b/arch/x86/kernel/i8237.c
@@ -1,5 +1,5 @@
/*
- * i8237.c: 8237A DMA controller suspend functions.
+ * 8237A DMA controller suspend functions.
*
* Written by Pierre Ossman, 2005.
*
diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253.c
index 6d839f2f1b1..5cc8841ca2c 100644
--- a/arch/x86/kernel/i8253_32.c
+++ b/arch/x86/kernel/i8253.c
@@ -1,5 +1,5 @@
/*
- * i8253.c 8253/PIT functions
+ * 8253/PIT functions
*
*/
#include <linux/clockchips.h>
@@ -13,7 +13,6 @@
#include <asm/delay.h>
#include <asm/i8253.h>
#include <asm/io.h>
-#include <asm/timer.h>
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
@@ -120,6 +119,7 @@ void __init setup_pit_timer(void)
global_clock_event = &pit_clockevent;
}
+#ifndef CONFIG_X86_64
/*
* Since the PIT overflows every tick, its not very useful
* to just read by itself. So use jiffies to emulate a free
@@ -204,3 +204,5 @@ static int __init init_pit_clocksource(void)
return clocksource_register(&clocksource_pit);
}
arch_initcall(init_pit_clocksource);
+
+#endif
diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c
index 0499cbe9871..679bb33acbf 100644
--- a/arch/x86/kernel/i8259_32.c
+++ b/arch/x86/kernel/i8259_32.c
@@ -10,7 +10,6 @@
#include <linux/sysdev.h>
#include <linux/bitops.h>
-#include <asm/8253pit.h>
#include <asm/atomic.h>
#include <asm/system.h>
#include <asm/io.h>
diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c
index 948cae64609..eb72976cc13 100644
--- a/arch/x86/kernel/i8259_64.c
+++ b/arch/x86/kernel/i8259_64.c
@@ -444,46 +444,6 @@ void __init init_ISA_irqs (void)
}
}
-static void setup_timer_hardware(void)
-{
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- udelay(10);
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- udelay(10);
- outb(LATCH >> 8 , 0x40); /* MSB */
-}
-
-static int timer_resume(struct sys_device *dev)
-{
- setup_timer_hardware();
- return 0;
-}
-
-void i8254_timer_resume(void)
-{
- setup_timer_hardware();
-}
-
-static struct sysdev_class timer_sysclass = {
- set_kset_name("timer_pit"),
- .resume = timer_resume,
-};
-
-static struct sys_device device_timer = {
- .id = 0,
- .cls = &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
- int error = sysdev_class_register(&timer_sysclass);
- if (!error)
- error = sysdev_register(&device_timer);
- return error;
-}
-
-device_initcall(init_timer_sysfs);
-
void __init init_IRQ(void)
{
int i;
@@ -533,12 +493,6 @@ void __init init_IRQ(void)
set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
- /*
- * Set the clock to HZ Hz, we already have a valid
- * vector now:
- */
- setup_timer_hardware();
-
if (!acpi_ioapic)
setup_irq(2, &irq2);
}
diff --git a/arch/x86/kernel/ioport_32.c b/arch/x86/kernel/ioport_32.c
index 3d310a946d7..4ed48dc8df1 100644
--- a/arch/x86/kernel/ioport_32.c
+++ b/arch/x86/kernel/ioport_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/ioport.c
- *
* This contains the io-permission bitmap code - written by obz, with changes
* by Linus.
*/
diff --git a/arch/x86/kernel/ioport_64.c b/arch/x86/kernel/ioport_64.c
index 653efa30b0f..5f62fad64da 100644
--- a/arch/x86/kernel/ioport_64.c
+++ b/arch/x86/kernel/ioport_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/ioport.c
- *
* This contains the io-permission bitmap code - written by obz, with changes
* by Linus.
*/
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 4f681bcdb1f..e173b763f14 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/irq.c
- *
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
* This file contains the lowest level x86-specific interrupt
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index bd11e42b22b..865669efc54 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/irq.c
- *
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
* This file contains the lowest level x86_64-specific interrupt
diff --git a/arch/x86/kernel/kprobes_32.c b/arch/x86/kernel/kprobes_32.c
index 448a50b1324..e7d0d3c2ef6 100644
--- a/arch/x86/kernel/kprobes_32.c
+++ b/arch/x86/kernel/kprobes_32.c
@@ -1,6 +1,5 @@
/*
* Kernel Probes (KProbes)
- * arch/i386/kernel/kprobes.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -558,6 +557,12 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
resume_execution(cur, regs, kcb);
regs->eflags |= kcb->kprobe_saved_eflags;
+#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
+ if (raw_irqs_disabled_flags(regs->eflags))
+ trace_hardirqs_off();
+ else
+ trace_hardirqs_on();
+#endif
/*Restore back the original saved kprobes variables and continue. */
if (kcb->kprobe_status == KPROBE_REENTER) {
@@ -695,6 +700,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
MIN_STACK_SIZE(addr));
regs->eflags &= ~IF_MASK;
+ trace_hardirqs_off();
regs->eip = (unsigned long)(jp->entry);
return 1;
}
diff --git a/arch/x86/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c
index a30e004682e..62e28e52d78 100644
--- a/arch/x86/kernel/kprobes_64.c
+++ b/arch/x86/kernel/kprobes_64.c
@@ -1,6 +1,5 @@
/*
* Kernel Probes (KProbes)
- * arch/x86_64/kernel/kprobes.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -545,6 +544,12 @@ int __kprobes post_kprobe_handler(struct pt_regs *regs)
resume_execution(cur, regs, kcb);
regs->eflags |= kcb->kprobe_saved_rflags;
+#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
+ if (raw_irqs_disabled_flags(regs->eflags))
+ trace_hardirqs_off();
+ else
+ trace_hardirqs_on();
+#endif
/* Restore the original saved kprobes variables and continue. */
if (kcb->kprobe_status == KPROBE_REENTER) {
@@ -685,6 +690,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
MIN_STACK_SIZE(addr));
regs->eflags &= ~IF_MASK;
+ trace_hardirqs_off();
regs->rip = (unsigned long)(jp->entry);
return 1;
}
diff --git a/arch/x86/kernel/ldt_32.c b/arch/x86/kernel/ldt_32.c
index e0b2d17f4f1..a8b18421863 100644
--- a/arch/x86/kernel/ldt_32.c
+++ b/arch/x86/kernel/ldt_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/ldt.c
- *
* Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
*/
diff --git a/arch/x86/kernel/ldt_64.c b/arch/x86/kernel/ldt_64.c
index bc9ffd5c19c..3796523d616 100644
--- a/arch/x86/kernel/ldt_64.c
+++ b/arch/x86/kernel/ldt_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/ldt.c
- *
* Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2002 Andi Kleen
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index 91966bafb3d..deda9a221cf 100644
--- a/arch/x86/kernel/machine_kexec_32.c
+++ b/arch/x86/kernel/machine_kexec_32.c
@@ -1,5 +1,5 @@
/*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * handle transition of Linux booting another kernel
* Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
*
* This source code is licensed under the GNU General Public License,
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index c3a55470367..cd1899a2f0c 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -1,5 +1,5 @@
/*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * handle transition of Linux booting another kernel
* Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
*
* This source code is licensed under the GNU General Public License,
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c
index b83672b8952..9482033ed0f 100644
--- a/arch/x86/kernel/mca_32.c
+++ b/arch/x86/kernel/mca_32.c
@@ -1,5 +1,4 @@
/*
- * linux/arch/i386/kernel/mca.c
* Written by Martin Kolinek, February 1996
*
* Changes:
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
new file mode 100644
index 00000000000..0ab680f2d9d
--- /dev/null
+++ b/arch/x86/kernel/mfgpt_32.c
@@ -0,0 +1,362 @@
+/*
+ * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
+ *
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
+ *
+ * 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.
+ *
+ * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
+ */
+
+/*
+ * We are using the 32Khz input clock - its the only one that has the
+ * ranges we find desirable. The following table lists the suitable
+ * divisors and the associated hz, minimum interval
+ * and the maximum interval:
+ *
+ * Divisor Hz Min Delta (S) Max Delta (S)
+ * 1 32000 .0005 2.048
+ * 2 16000 .001 4.096
+ * 4 8000 .002 8.192
+ * 8 4000 .004 16.384
+ * 16 2000 .008 32.768
+ * 32 1000 .016 65.536
+ * 64 500 .032 131.072
+ * 128 250 .064 262.144
+ * 256 125 .128 524.288
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/geode.h>
+
+#define F_AVAIL 0x01
+
+static struct mfgpt_timer_t {
+ int flags;
+ struct module *owner;
+} mfgpt_timers[MFGPT_MAX_TIMERS];
+
+/* Selected from the table above */
+
+#define MFGPT_DIVISOR 16
+#define MFGPT_SCALE 4 /* divisor = 2^(scale) */
+#define MFGPT_HZ (32000 / MFGPT_DIVISOR)
+#define MFGPT_PERIODIC (MFGPT_HZ / HZ)
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+static int __init mfgpt_timer_setup(void);
+#else
+#define mfgpt_timer_setup() (0)
+#endif
+
+/* Allow for disabling of MFGPTs */
+static int disable;
+static int __init mfgpt_disable(char *s)
+{
+ disable = 1;
+ return 1;
+}
+__setup("nomfgpt", mfgpt_disable);
+
+/*
+ * Check whether any MFGPTs are available for the kernel to use. In most
+ * cases, firmware that uses AMD's VSA code will claim all timers during
+ * bootup; we certainly don't want to take them if they're already in use.
+ * In other cases (such as with VSAless OpenFirmware), the system firmware
+ * leaves timers available for us to use.
+ */
+int __init geode_mfgpt_detect(void)
+{
+ int count = 0, i;
+ u16 val;
+
+ if (disable) {
+ printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n");
+ return 0;
+ }
+
+ for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+ val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
+ if (!(val & MFGPT_SETUP_SETUP)) {
+ mfgpt_timers[i].flags = F_AVAIL;
+ count++;
+ }
+ }
+
+ /* set up clock event device, if desired */
+ i = mfgpt_timer_setup();
+
+ return count;
+}
+
+int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
+{
+ u32 msr, mask, value, dummy;
+ int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
+
+ if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+ return -EIO;
+
+ /*
+ * The register maps for these are described in sections 6.17.1.x of
+ * the AMD Geode CS5536 Companion Device Data Book.
+ */
+ switch (event) {
+ case MFGPT_EVENT_RESET:
+ /*
+ * XXX: According to the docs, we cannot reset timers above
+ * 6; that is, resets for 7 and 8 will be ignored. Is this
+ * a problem? -dilinger
+ */
+ msr = MFGPT_NR_MSR;
+ mask = 1 << (timer + 24);
+ break;
+
+ case MFGPT_EVENT_NMI:
+ msr = MFGPT_NR_MSR;
+ mask = 1 << (timer + shift);
+ break;
+
+ case MFGPT_EVENT_IRQ:
+ msr = MFGPT_IRQ_MSR;
+ mask = 1 << (timer + shift);
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ rdmsr(msr, value, dummy);
+
+ if (enable)
+ value |= mask;
+ else
+ value &= ~mask;
+
+ wrmsr(msr, value, dummy);
+ return 0;
+}
+
+int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
+{
+ u32 val, dummy;
+ int offset;
+
+ if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+ return -EIO;
+
+ if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
+ return -EIO;
+
+ rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+
+ offset = (timer % 4) * 4;
+
+ val &= ~((0xF << offset) | (0xF << (offset + 16)));
+
+ if (enable) {
+ val |= (irq & 0x0F) << (offset);
+ val |= (irq & 0x0F) << (offset + 16);
+ }
+
+ wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+ return 0;
+}
+
+static int mfgpt_get(int timer, struct module *owner)
+{
+ mfgpt_timers[timer].flags &= ~F_AVAIL;
+ mfgpt_timers[timer].owner = owner;
+ printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer);
+ return timer;
+}
+
+int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
+{
+ int i;
+
+ if (!geode_get_dev_base(GEODE_DEV_MFGPT))
+ return -ENODEV;
+ if (timer >= MFGPT_MAX_TIMERS)
+ return -EIO;
+
+ if (timer < 0) {
+ /* Try to find an available timer */
+ for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+ if (mfgpt_timers[i].flags & F_AVAIL)
+ return mfgpt_get(i, owner);
+
+ if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
+ break;
+ }
+ } else {
+ /* If they requested a specific timer, try to honor that */
+ if (mfgpt_timers[timer].flags & F_AVAIL)
+ return mfgpt_get(timer, owner);
+ }
+
+ /* No timers available - too bad */
+ return -1;
+}
+
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+
+/*
+ * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * as clock event sources - not as good as a HPET or APIC, but certainly
+ * better then the PIT. This isn't a general purpose MFGPT driver, but
+ * a simplified one designed specifically to act as a clock event source.
+ * For full details about the MFGPT, please consult the CS5536 data sheet.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
+static u16 mfgpt_event_clock;
+
+static int irq = 7;
+static int __init mfgpt_setup(char *str)
+{
+ get_option(&str, &irq);
+ return 1;
+}
+__setup("mfgpt_irq=", mfgpt_setup);
+
+static inline void mfgpt_disable_timer(u16 clock)
+{
+ u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP);
+ geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN);
+}
+
+static int mfgpt_next_event(unsigned long, struct clock_event_device *);
+static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *);
+
+static struct clock_event_device mfgpt_clockevent = {
+ .name = "mfgpt-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = mfgpt_set_mode,
+ .set_next_event = mfgpt_next_event,
+ .rating = 250,
+ .cpumask = CPU_MASK_ALL,
+ .shift = 32
+};
+
+static inline void mfgpt_start_timer(u16 clock, u16 delta)
+{
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+ MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+}
+
+static void mfgpt_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ mfgpt_disable_timer(mfgpt_event_clock);
+
+ if (mode == CLOCK_EVT_MODE_PERIODIC)
+ mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC);
+
+ mfgpt_tick_mode = mode;
+}
+
+static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+ mfgpt_start_timer(mfgpt_event_clock, delta);
+ return 0;
+}
+
+/* Assume (foolishly?), that this interrupt was due to our tick */
+
+static irqreturn_t mfgpt_tick(int irq, void *dev_id)
+{
+ if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
+ return IRQ_HANDLED;
+
+ /* Turn off the clock */
+ mfgpt_disable_timer(mfgpt_event_clock);
+
+ /* Clear the counter */
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+ /* Restart the clock in periodic mode */
+
+ if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+ MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+ }
+
+ mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mfgptirq = {
+ .handler = mfgpt_tick,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .mask = CPU_MASK_NONE,
+ .name = "mfgpt-timer"
+};
+
+static int __init mfgpt_timer_setup(void)
+{
+ int timer, ret;
+ u16 val;
+
+ timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING,
+ THIS_MODULE);
+ if (timer < 0) {
+ printk(KERN_ERR
+ "mfgpt-timer: Could not allocate a MFPGT timer\n");
+ return -ENODEV;
+ }
+
+ mfgpt_event_clock = timer;
+ /* Set the clock scale and enable the event mode for CMP2 */
+ val = MFGPT_SCALE | (3 << 8);
+
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
+ /* Set up the IRQ on the MFGPT side */
+ if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
+ printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq);
+ return -EIO;
+ }
+
+ /* And register it with the kernel */
+ ret = setup_irq(irq, &mfgptirq);
+
+ if (ret) {
+ printk(KERN_ERR
+ "mfgpt-timer: Unable to set up the interrupt.\n");
+ goto err;
+ }
+
+ /* Set up the clock event */
+ mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
+ mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
+ &mfgpt_clockevent);
+ mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
+ &mfgpt_clockevent);
+
+ printk(KERN_INFO
+ "mfgpt-timer: registering the MFGT timer as a clock event.\n");
+ clockevents_register_device(&mfgpt_clockevent);
+
+ return 0;
+
+err:
+ geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+ printk(KERN_ERR
+ "mfgpt-timer: Unable to set up the MFGPT clock source\n");
+ return -EIO;
+}
+
+#endif
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 0c1069b8d63..c044de310b6 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -11,8 +11,6 @@
* ----------------------------------------------------------------------- */
/*
- * msr.c
- *
* x86 MSR access device
*
* This device is accessed by lseek() to the appropriate register number
diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c
index c7227e2180f..f803ed0ed1c 100644
--- a/arch/x86/kernel/nmi_32.c
+++ b/arch/x86/kernel/nmi_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/nmi.c
- *
* NMI watchdog support on APIC systems
*
* Started by Ingo Molnar <mingo@redhat.com>
@@ -353,7 +351,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
* Take the local apic timer and PIT/HPET into account. We don't
* know which one is active, when we have highres/dyntick on
*/
- sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
+ sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
+ per_cpu(irq_stat, cpu).irq0_irqs;
/* if the none of the timers isn't firing, this cpu isn't doing much */
if (!touched && last_irq_sums[cpu] == sum) {
diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c
index 0ec6d2ddb93..a576fd74006 100644
--- a/arch/x86/kernel/nmi_64.c
+++ b/arch/x86/kernel/nmi_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/nmi.c
- *
* NMI watchdog support on APIC systems
*
* Started by Ingo Molnar <mingo@redhat.com>
@@ -329,7 +327,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
touched = 1;
}
- sum = read_pda(apic_timer_irqs);
+ sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
if (__get_cpu_var(nmi_touch)) {
__get_cpu_var(nmi_touch) = 0;
touched = 1;
diff --git a/arch/x86/kernel/pci-dma_32.c b/arch/x86/kernel/pci-dma_32.c
index 048f09b6255..0aae2f3847a 100644
--- a/arch/x86/kernel/pci-dma_32.c
+++ b/arch/x86/kernel/pci-dma_32.c
@@ -63,7 +63,8 @@ void dma_free_coherent(struct device *dev, size_t size,
{
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
int order = get_order(size);
-
+
+ WARN_ON(irqs_disabled()); /* for portability */
if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
diff --git a/arch/x86/kernel/pci-dma_64.c b/arch/x86/kernel/pci-dma_64.c
index 29711445c81..9576a2eb375 100644
--- a/arch/x86/kernel/pci-dma_64.c
+++ b/arch/x86/kernel/pci-dma_64.c
@@ -167,6 +167,7 @@ EXPORT_SYMBOL(dma_alloc_coherent);
void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t bus)
{
+ WARN_ON(irqs_disabled()); /* for portability */
if (dma_ops->unmap_single)
dma_ops->unmap_single(dev, bus, size, 0);
free_pages((unsigned long)vaddr, get_order(size));
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 84664710b78..097aeafce5f 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/process.c
- *
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 98956555450..7352d4b377e 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86-64/kernel/process.c
- *
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
@@ -38,6 +36,7 @@
#include <linux/notifier.h>
#include <linux/kprobes.h>
#include <linux/kdebug.h>
+#include <linux/tick.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -208,6 +207,8 @@ void cpu_idle (void)
if (__get_cpu_var(cpu_idle_state))
__get_cpu_var(cpu_idle_state) = 0;
+ tick_nohz_stop_sched_tick();
+
rmb();
idle = pm_idle;
if (!idle)
@@ -228,6 +229,7 @@ void cpu_idle (void)
__exit_idle();
}
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 7c1b92522e9..0cecd7513c9 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -1,4 +1,3 @@
-/* ptrace.c */
/* By Ross Biro 1/23/92 */
/*
* Pentium III FXSR, SSE support
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index eea3702427b..c0cac42df3b 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -1,4 +1,3 @@
-/* ptrace.c */
/* By Ross Biro 1/23/92 */
/*
* Pentium III FXSR, SSE support
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 6722469c263..d769e204f94 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -4,6 +4,8 @@
#include <linux/pci.h>
#include <linux/irq.h>
+#include <asm/hpet.h>
+
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
@@ -47,3 +49,206 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quir
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
#endif
+
+#if defined(CONFIG_HPET_TIMER)
+unsigned long force_hpet_address;
+
+static enum {
+ NONE_FORCE_HPET_RESUME,
+ OLD_ICH_FORCE_HPET_RESUME,
+ ICH_FORCE_HPET_RESUME
+} force_hpet_resume_type;
+
+static void __iomem *rcba_base;
+
+static void ich_force_hpet_resume(void)
+{
+ u32 val;
+
+ if (!force_hpet_address)
+ return;
+
+ if (rcba_base == NULL)
+ BUG();
+
+ /* read the Function Disable register, dword mode only */
+ val = readl(rcba_base + 0x3404);
+ if (!(val & 0x80)) {
+ /* HPET disabled in HPTC. Trying to enable */
+ writel(val | 0x80, rcba_base + 0x3404);
+ }
+
+ val = readl(rcba_base + 0x3404);
+ if (!(val & 0x80))
+ BUG();
+ else
+ printk(KERN_DEBUG "Force enabled HPET at resume\n");
+
+ return;
+}
+
+static void ich_force_enable_hpet(struct pci_dev *dev)
+{
+ u32 val;
+ u32 uninitialized_var(rcba);
+ int err = 0;
+
+ if (hpet_address || force_hpet_address)
+ return;
+
+ pci_read_config_dword(dev, 0xF0, &rcba);
+ rcba &= 0xFFFFC000;
+ if (rcba == 0) {
+ printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+ return;
+ }
+
+ /* use bits 31:14, 16 kB aligned */
+ rcba_base = ioremap_nocache(rcba, 0x4000);
+ if (rcba_base == NULL) {
+ printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+ return;
+ }
+
+ /* read the Function Disable register, dword mode only */
+ val = readl(rcba_base + 0x3404);
+
+ if (val & 0x80) {
+ /* HPET is enabled in HPTC. Just not reported by BIOS */
+ val = val & 0x3;
+ force_hpet_address = 0xFED00000 | (val << 12);
+ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+ force_hpet_address);
+ iounmap(rcba_base);
+ return;
+ }
+
+ /* HPET disabled in HPTC. Trying to enable */
+ writel(val | 0x80, rcba_base + 0x3404);
+
+ val = readl(rcba_base + 0x3404);
+ if (!(val & 0x80)) {
+ err = 1;
+ } else {
+ val = val & 0x3;
+ force_hpet_address = 0xFED00000 | (val << 12);
+ }
+
+ if (err) {
+ force_hpet_address = 0;
+ iounmap(rcba_base);
+ printk(KERN_DEBUG "Failed to force enable HPET\n");
+ } else {
+ force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
+ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+ force_hpet_address);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+ ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
+ ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
+ ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
+ ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
+ ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
+ ich_force_enable_hpet);
+
+
+static struct pci_dev *cached_dev;
+
+static void old_ich_force_hpet_resume(void)
+{
+ u32 val;
+ u32 uninitialized_var(gen_cntl);
+
+ if (!force_hpet_address || !cached_dev)
+ return;
+
+ pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+ gen_cntl &= (~(0x7 << 15));
+ gen_cntl |= (0x4 << 15);
+
+ pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
+ pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+ val = gen_cntl >> 15;
+ val &= 0x7;
+ if (val == 0x4)
+ printk(KERN_DEBUG "Force enabled HPET at resume\n");
+ else
+ BUG();
+}
+
+static void old_ich_force_enable_hpet(struct pci_dev *dev)
+{
+ u32 val;
+ u32 uninitialized_var(gen_cntl);
+
+ if (hpet_address || force_hpet_address)
+ return;
+
+ pci_read_config_dword(dev, 0xD0, &gen_cntl);
+ /*
+ * Bit 17 is HPET enable bit.
+ * Bit 16:15 control the HPET base address.
+ */
+ val = gen_cntl >> 15;
+ val &= 0x7;
+ if (val & 0x4) {
+ val &= 0x3;
+ force_hpet_address = 0xFED00000 | (val << 12);
+ printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+ force_hpet_address);
+ return;
+ }
+
+ /*
+ * HPET is disabled. Trying enabling at FED00000 and check
+ * whether it sticks
+ */
+ gen_cntl &= (~(0x7 << 15));
+ gen_cntl |= (0x4 << 15);
+ pci_write_config_dword(dev, 0xD0, gen_cntl);
+
+ pci_read_config_dword(dev, 0xD0, &gen_cntl);
+
+ val = gen_cntl >> 15;
+ val &= 0x7;
+ if (val & 0x4) {
+ /* HPET is enabled in HPTC. Just not reported by BIOS */
+ val &= 0x3;
+ force_hpet_address = 0xFED00000 | (val << 12);
+ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+ force_hpet_address);
+ cached_dev = dev;
+ force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
+ return;
+ }
+
+ printk(KERN_DEBUG "Failed to force enable HPET\n");
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+ old_ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
+ old_ich_force_enable_hpet);
+
+void force_hpet_resume(void)
+{
+ switch (force_hpet_resume_type) {
+ case ICH_FORCE_HPET_RESUME:
+ return ich_force_hpet_resume();
+
+ case OLD_ICH_FORCE_HPET_RESUME:
+ return old_ich_force_hpet_resume();
+
+ default:
+ break;
+ }
+}
+
+#endif
diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c
index b37ed226830..9e2269d0091 100644
--- a/arch/x86/kernel/reboot_32.c
+++ b/arch/x86/kernel/reboot_32.c
@@ -1,7 +1,3 @@
-/*
- * linux/arch/i386/kernel/reboot.c
- */
-
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/arch/x86/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c
index 03e1cce58f4..8b30b26ad06 100644
--- a/arch/x86/kernel/reboot_fixups_32.c
+++ b/arch/x86/kernel/reboot_fixups_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/reboot_fixups.c
- *
* This is a good place to put board specific reboot fixups.
*
* List of supported fixups:
@@ -11,6 +9,7 @@
#include <asm/delay.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
#include <asm/reboot_fixups.h>
#include <asm/msr.h>
@@ -56,6 +55,11 @@ void mach_reboot_fixups(void)
struct pci_dev *dev;
int i;
+ /* we can be called from sysrq-B code. In such a case it is
+ * prohibited to dig PCI */
+ if (in_interrupt())
+ return;
+
for (i=0; i < ARRAY_SIZE(fixups_table); i++) {
cur = &(fixups_table[i]);
dev = pci_get_device(cur->vendor, cur->device, NULL);
diff --git a/arch/x86/kernel/scx200_32.c b/arch/x86/kernel/scx200_32.c
index c7d3df23f58..87bc159d29d 100644
--- a/arch/x86/kernel/scx200_32.c
+++ b/arch/x86/kernel/scx200_32.c
@@ -1,8 +1,8 @@
-/* linux/arch/i386/kernel/scx200.c
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 support. */
+/*
+ * Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+ *
+ * National Semiconductor SCx200 support.
+ */
#include <linux/module.h>
#include <linux/errno.h>
@@ -24,7 +24,7 @@ MODULE_DESCRIPTION("NatSemi SCx200 Driver");
MODULE_LICENSE("GPL");
unsigned scx200_gpio_base = 0;
-long scx200_gpio_shadow[2];
+unsigned long scx200_gpio_shadow[2];
unsigned scx200_cb_base = 0;
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index d474cd639bc..c8e1bc38d42 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/setup.c
- *
* Copyright (C) 1995 Linus Torvalds
*
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index af838f6b0b7..b7da90e79c7 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -1,10 +1,5 @@
/*
- * linux/arch/x86-64/kernel/setup.c
- *
* Copyright (C) 1995 Linus Torvalds
- *
- * Nov 2001 Dave Jones <davej@suse.de>
- * Forked from i386 setup code.
*/
/*
@@ -546,6 +541,37 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
#endif
}
+#define ENABLE_C1E_MASK 0x18000000
+#define CPUID_PROCESSOR_SIGNATURE 1
+#define CPUID_XFAM 0x0ff00000
+#define CPUID_XFAM_K8 0x00000000
+#define CPUID_XFAM_10H 0x00100000
+#define CPUID_XFAM_11H 0x00200000
+#define CPUID_XMOD 0x000f0000
+#define CPUID_XMOD_REV_F 0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+ u32 lo, hi;
+ u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+ switch (eax & CPUID_XFAM) {
+ case CPUID_XFAM_K8:
+ if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+ break;
+ case CPUID_XFAM_10H:
+ case CPUID_XFAM_11H:
+ rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+ if (lo & ENABLE_C1E_MASK)
+ return 1;
+ break;
+ default:
+ /* err on the side of caution */
+ return 1;
+ }
+ return 0;
+}
+
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
unsigned level;
@@ -617,6 +643,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
/* Family 10 doesn't support C states in MWAIT so don't use it */
if (c->x86 == 0x10 && !force_mwait)
clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
+
+ if (amd_apic_timer_broken())
+ disable_apic_timer = 1;
}
static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index c03570f7fe8..d01d51fcce2 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/signal.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 739175b01e0..683802bec41 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/signal.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
*
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 32f50783edc..720a7d1f886 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -223,8 +223,6 @@ void __cpuinit smp_callin(void)
local_irq_disable();
Dprintk("Stack at about %p\n",&cpuid);
- disable_APIC_timer();
-
/*
* Save our processor parameters
*/
@@ -337,19 +335,12 @@ void __cpuinit start_secondary(void)
*/
check_tsc_sync_target();
- Dprintk("cpu %d: setting up apic clock\n", smp_processor_id());
- setup_secondary_APIC_clock();
-
- Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
-
if (nmi_watchdog == NMI_IO_APIC) {
disable_8259A_irq(0);
enable_NMI_through_LVT0(NULL);
enable_8259A_irq(0);
}
- enable_APIC_timer();
-
/*
* The sibling maps must be set before turing the online map on for
* this cpu
@@ -378,6 +369,8 @@ void __cpuinit start_secondary(void)
unlock_ipi_call_lock();
+ setup_secondary_APIC_clock();
+
cpu_idle();
}
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index cb910911358..413e527cdeb 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -1,6 +1,4 @@
/*
- * arch/x86_64/kernel/stacktrace.c
- *
* Stack trace management functions
*
* Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
diff --git a/arch/x86/kernel/summit_32.c b/arch/x86/kernel/summit_32.c
index d0e01a3acf3..91c7acc8d99 100644
--- a/arch/x86/kernel/summit_32.c
+++ b/arch/x86/kernel/summit_32.c
@@ -1,5 +1,5 @@
/*
- * arch/i386/kernel/summit.c - IBM Summit-Specific Code
+ * IBM Summit-Specific Code
*
* Written By: Matthew Dobson, IBM Corporation
*
diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c
index 42147304de8..f8bae9ba032 100644
--- a/arch/x86/kernel/sys_i386_32.c
+++ b/arch/x86/kernel/sys_i386_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/sys_i386.c
- *
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/i386
* platform.
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 4770b7a2052..907942ee6e7 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -1,7 +1,3 @@
-/*
- * linux/arch/x86_64/kernel/sys_x86_64.c
- */
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
diff --git a/arch/x86/kernel/sysenter_32.c b/arch/x86/kernel/sysenter_32.c
index 4eb2e408764..5a2d951e260 100644
--- a/arch/x86/kernel/sysenter_32.c
+++ b/arch/x86/kernel/sysenter_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/sysenter.c
- *
* (C) Copyright 2002 Linus Torvalds
* Portions based on the vdso-randomization code from exec-shield:
* Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index 19a6c678d02..8a322c96bc2 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/kernel/time.c
- *
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*
* This file contains the PC-specific time handling details:
@@ -157,6 +155,9 @@ EXPORT_SYMBOL(profile_pc);
*/
irqreturn_t timer_interrupt(int irq, void *dev_id)
{
+ /* Keep nmi watchdog up to date */
+ per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
+
#ifdef CONFIG_X86_IO_APIC
if (timer_ack) {
/*
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index 6d48a4e826d..c821edc3221 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86-64/kernel/time.c
- *
* "High Precision Event Timer" based timekeeping.
*
* Copyright (c) 1991,1992,1995 Linus Torvalds
@@ -28,11 +26,12 @@
#include <linux/cpu.h>
#include <linux/kallsyms.h>
#include <linux/acpi.h>
+#include <linux/clockchips.h>
+
#ifdef CONFIG_ACPI
#include <acpi/achware.h> /* for PM timer frequency */
#include <acpi/acpi_bus.h>
#endif
-#include <asm/8253pit.h>
#include <asm/i8253.h>
#include <asm/pgtable.h>
#include <asm/vsyscall.h>
@@ -47,12 +46,8 @@
#include <asm/nmi.h>
#include <asm/vgtod.h>
-static char *timename = NULL;
-
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
@@ -153,45 +148,12 @@ int update_persistent_clock(struct timespec now)
return set_rtc_mmss(now.tv_sec);
}
-void main_timer_handler(void)
+static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
{
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
-
- write_seqlock(&xtime_lock);
-
-/*
- * Do the timer stuff.
- */
+ add_pda(irq0_irqs, 1);
- do_timer(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
-
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
- if (!using_apic_timer)
- smp_local_timer_interrupt();
+ global_clock_event->event_handler(global_clock_event);
- write_sequnlock(&xtime_lock);
-}
-
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
- if (apic_runs_main_timer > 1)
- return IRQ_HANDLED;
- main_timer_handler();
- if (using_apic_timer)
- smp_send_timer_broadcast_ipi();
return IRQ_HANDLED;
}
@@ -292,97 +254,21 @@ static unsigned int __init tsc_calibrate_cpu_khz(void)
return pmc_now * tsc_khz / (tsc_now - tsc_start);
}
-/*
- * pit_calibrate_tsc() uses the speaker output (channel 2) of
- * the PIT. This is better than using the timer interrupt output,
- * because we can read the value of the speaker with just one inb(),
- * where we need three i/o operations for the interrupt channel.
- * We count how many ticks the TSC does in 50 ms.
- */
-
-static unsigned int __init pit_calibrate_tsc(void)
-{
- unsigned long start, end;
- unsigned long flags;
-
- spin_lock_irqsave(&i8253_lock, flags);
-
- outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
- outb(0xb0, 0x43);
- outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
- outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
- start = get_cycles_sync();
- while ((inb(0x61) & 0x20) == 0);
- end = get_cycles_sync();
-
- spin_unlock_irqrestore(&i8253_lock, flags);
-
- return (end - start) / 50;
-}
-
-#define PIT_MODE 0x43
-#define PIT_CH0 0x40
-
-static void __pit_init(int val, u8 mode)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&i8253_lock, flags);
- outb_p(mode, PIT_MODE);
- outb_p(val & 0xff, PIT_CH0); /* LSB */
- outb_p(val >> 8, PIT_CH0); /* MSB */
- spin_unlock_irqrestore(&i8253_lock, flags);
-}
-
-void __init pit_init(void)
-{
- __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
-}
-
-void pit_stop_interrupt(void)
-{
- __pit_init(0, 0x30); /* mode 0 */
-}
-
-void stop_timer_interrupt(void)
-{
- char *name;
- if (hpet_address) {
- name = "HPET";
- hpet_timer_stop_set_go(0);
- } else {
- name = "PIT";
- pit_stop_interrupt();
- }
- printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
-}
-
static struct irqaction irq0 = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_IRQPOLL,
+ .handler = timer_event_interrupt,
+ .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
.mask = CPU_MASK_NONE,
.name = "timer"
};
void __init time_init(void)
{
- if (nohpet)
- hpet_address = 0;
+ if (!hpet_enable())
+ setup_pit_timer();
- if (hpet_arch_init())
- hpet_address = 0;
+ setup_irq(0, &irq0);
- if (hpet_use_timer) {
- /* set tick_nsec to use the proper rate for HPET */
- tick_nsec = TICK_NSEC_HPET;
- tsc_khz = hpet_calibrate_tsc();
- timename = "HPET";
- } else {
- pit_init();
- tsc_khz = pit_calibrate_tsc();
- timename = "PIT";
- }
+ tsc_calibrate();
cpu_khz = tsc_khz;
if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -398,50 +284,7 @@ void __init time_init(void)
else
vgetcpu_mode = VGETCPU_LSL;
- set_cyc2ns_scale(tsc_khz);
printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
init_tsc_clocksource();
-
- setup_irq(0, &irq0);
-}
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
- return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
- if (hpet_address)
- hpet_reenable();
- else
- i8254_timer_resume();
- return 0;
}
-
-static struct sysdev_class timer_sysclass = {
- .resume = timer_resume,
- .suspend = timer_suspend,
- set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-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/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index 45782356a61..c25f23eb397 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -1,5 +1,5 @@
/*
- * arch/i386/kernel/topology.c - Populate sysfs with topology information
+ * Populate sysfs with topology information
*
* Written by: Matthew Dobson, IBM Corporation
* Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index 47b0bef335b..05c27ecaf2a 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/i386/traps.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Pentium III FXSR, SSE support
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index 03888420775..bc7116acf8f 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86-64/traps.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
*
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c
index 3ed0ae8c918..b85ad754f70 100644
--- a/arch/x86/kernel/tsc_32.c
+++ b/arch/x86/kernel/tsc_32.c
@@ -1,9 +1,3 @@
-/*
- * This code largely moved from arch/i386/kernel/timer/timer_tsc.c
- * which was originally moved from arch/i386/kernel/time.c.
- * See comments there for proper credits.
- */
-
#include <linux/sched.h>
#include <linux/clocksource.h>
#include <linux/workqueue.h>
diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c
index 2a59bde663f..9f22e542c37 100644
--- a/arch/x86/kernel/tsc_64.c
+++ b/arch/x86/kernel/tsc_64.c
@@ -6,7 +6,9 @@
#include <linux/time.h>
#include <linux/acpi.h>
#include <linux/cpufreq.h>
+#include <linux/acpi_pmtmr.h>
+#include <asm/hpet.h>
#include <asm/timex.h>
static int notsc __initdata = 0;
@@ -18,7 +20,7 @@ EXPORT_SYMBOL(tsc_khz);
static unsigned int cyc2ns_scale __read_mostly;
-void set_cyc2ns_scale(unsigned long khz)
+static inline void set_cyc2ns_scale(unsigned long khz)
{
cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz;
}
@@ -118,6 +120,95 @@ core_initcall(cpufreq_tsc);
#endif
+#define MAX_RETRIES 5
+#define SMI_TRESHOLD 50000
+
+/*
+ * Read TSC and the reference counters. Take care of SMI disturbance
+ */
+static unsigned long __init tsc_read_refs(unsigned long *pm,
+ unsigned long *hpet)
+{
+ unsigned long t1, t2;
+ int i;
+
+ for (i = 0; i < MAX_RETRIES; i++) {
+ t1 = get_cycles_sync();
+ if (hpet)
+ *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+ else
+ *pm = acpi_pm_read_early();
+ t2 = get_cycles_sync();
+ if ((t2 - t1) < SMI_TRESHOLD)
+ return t2;
+ }
+ return ULONG_MAX;
+}
+
+/**
+ * tsc_calibrate - calibrate the tsc on boot
+ */
+void __init tsc_calibrate(void)
+{
+ unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
+ int hpet = is_hpet_enabled();
+
+ local_irq_save(flags);
+
+ tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
+
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ outb(0xb0, 0x43);
+ outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+ outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+ tr1 = get_cycles_sync();
+ while ((inb(0x61) & 0x20) == 0);
+ tr2 = get_cycles_sync();
+
+ tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+
+ local_irq_restore(flags);
+
+ /*
+ * Preset the result with the raw and inaccurate PIT
+ * calibration value
+ */
+ tsc_khz = (tr2 - tr1) / 50;
+
+ /* hpet or pmtimer available ? */
+ if (!hpet && !pm1 && !pm2) {
+ printk(KERN_INFO "TSC calibrated against PIT\n");
+ return;
+ }
+
+ /* Check, whether the sampling was disturbed by an SMI */
+ if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
+ printk(KERN_WARNING "TSC calibration disturbed by SMI, "
+ "using PIT calibration result\n");
+ return;
+ }
+
+ tsc2 = (tsc2 - tsc1) * 1000000L;
+
+ if (hpet) {
+ printk(KERN_INFO "TSC calibrated against HPET\n");
+ if (hpet2 < hpet1)
+ hpet2 += 0x100000000;
+ hpet2 -= hpet1;
+ tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
+ } else {
+ printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
+ if (pm2 < pm1)
+ pm2 += ACPI_PM_OVRRUN;
+ pm2 -= pm1;
+ tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
+ }
+
+ tsc_khz = tsc2 / tsc1;
+ set_cyc2ns_scale(tsc_khz);
+}
+
/*
* Make an educated guess if the TSC is trustworthy and synchronized
* over all CPUs.
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
index 355f5f506c8..9125efe66a0 100644
--- a/arch/x86/kernel/tsc_sync.c
+++ b/arch/x86/kernel/tsc_sync.c
@@ -1,5 +1,5 @@
/*
- * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization.
+ * check TSC synchronization.
*
* Copyright (C) 2006, Red Hat, Inc., Ingo Molnar
*
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index f2dcd1d27c0..157e4bedd3c 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -1,6 +1,4 @@
/*
- * linux/kernel/vm86.c
- *
* Copyright (C) 1994 Linus Torvalds
*
* 29 dec 2001 - Fixed oopses caused by unchecked access to the vm86
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 06c34949bfd..93847d84815 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/x86_64/kernel/vsyscall.c
- *
* Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
* Copyright 2003 Andi Kleen, SuSE Labs.
*
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
index 4620efb12f1..5196762b3b0 100644
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ b/arch/x86/lib/copy_user_nocache_64.S
@@ -117,6 +117,7 @@ ENTRY(__copy_user_nocache)
popq %rbx
CFI_ADJUST_CFA_OFFSET -8
CFI_RESTORE rbx
+ sfence
ret
CFI_RESTORE_STATE
diff --git a/arch/x86/lib/thunk_64.S b/arch/x86/lib/thunk_64.S
index 55e586d352d..6ea73f3de56 100644
--- a/arch/x86/lib/thunk_64.S
+++ b/arch/x86/lib/thunk_64.S
@@ -50,6 +50,10 @@
thunk trace_hardirqs_on_thunk,trace_hardirqs_on
thunk trace_hardirqs_off_thunk,trace_hardirqs_off
#endif
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ thunk lockdep_sys_exit_thunk,lockdep_sys_exit
+#endif
/* SAVE_ARGS below is used only for the .cfi directives it contains. */
CFI_STARTPROC
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index bc8a44bddaa..2d88f7c6d6a 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -2,15 +2,199 @@
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/dmi.h>
#include <asm/numa.h>
#include "pci.h"
+static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
+{
+ pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
+ printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
+ return 0;
+}
+
+static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
+/*
+ * Systems where PCI IO resource ISA alignment can be skipped
+ * when the ISA enable bit in the bridge control is not set
+ */
+ {
+ .callback = can_skip_ioresource_align,
+ .ident = "IBM System x3800",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
+ },
+ },
+ {
+ .callback = can_skip_ioresource_align,
+ .ident = "IBM System x3850",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "x3850"),
+ },
+ },
+ {
+ .callback = can_skip_ioresource_align,
+ .ident = "IBM System x3950",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "x3950"),
+ },
+ },
+ {}
+};
+
+struct pci_root_info {
+ char *name;
+ unsigned int res_num;
+ struct resource *res;
+ struct pci_bus *bus;
+ int busnum;
+};
+
+static acpi_status
+resource_to_addr(struct acpi_resource *resource,
+ struct acpi_resource_address64 *addr)
+{
+ acpi_status status;
+
+ status = acpi_resource_to_address64(resource, addr);
+ if (ACPI_SUCCESS(status) &&
+ (addr->resource_type == ACPI_MEMORY_RANGE ||
+ addr->resource_type == ACPI_IO_RANGE) &&
+ addr->address_length > 0 &&
+ addr->producer_consumer == ACPI_PRODUCER) {
+ return AE_OK;
+ }
+ return AE_ERROR;
+}
+
+static acpi_status
+count_resource(struct acpi_resource *acpi_res, void *data)
+{
+ struct pci_root_info *info = data;
+ struct acpi_resource_address64 addr;
+ acpi_status status;
+
+ status = resource_to_addr(acpi_res, &addr);
+ if (ACPI_SUCCESS(status))
+ info->res_num++;
+ return AE_OK;
+}
+
+static acpi_status
+setup_resource(struct acpi_resource *acpi_res, void *data)
+{
+ struct pci_root_info *info = data;
+ struct resource *res;
+ struct acpi_resource_address64 addr;
+ acpi_status status;
+ unsigned long flags;
+ struct resource *root;
+
+ status = resource_to_addr(acpi_res, &addr);
+ if (!ACPI_SUCCESS(status))
+ return AE_OK;
+
+ if (addr.resource_type == ACPI_MEMORY_RANGE) {
+ root = &iomem_resource;
+ flags = IORESOURCE_MEM;
+ if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+ flags |= IORESOURCE_PREFETCH;
+ } else if (addr.resource_type == ACPI_IO_RANGE) {
+ root = &ioport_resource;
+ flags = IORESOURCE_IO;
+ } else
+ return AE_OK;
+
+ res = &info->res[info->res_num];
+ res->name = info->name;
+ res->flags = flags;
+ res->start = addr.minimum + addr.translation_offset;
+ res->end = res->start + addr.address_length - 1;
+ res->child = NULL;
+
+ if (insert_resource(root, res)) {
+ printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
+ "from %s for %s\n", (unsigned long) res->start,
+ (unsigned long) res->end, root->name, info->name);
+ } else {
+ info->bus->resource[info->res_num] = res;
+ info->res_num++;
+ }
+ return AE_OK;
+}
+
+static void
+adjust_transparent_bridge_resources(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ int i;
+ u16 class = dev->class >> 8;
+
+ if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) {
+ for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
+ dev->subordinate->resource[i] =
+ dev->bus->resource[i - 3];
+ }
+ }
+}
+
+static void
+get_current_resources(struct acpi_device *device, int busnum,
+ struct pci_bus *bus)
+{
+ struct pci_root_info info;
+ size_t size;
+
+ info.bus = bus;
+ info.res_num = 0;
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
+ &info);
+ if (!info.res_num)
+ return;
+
+ size = sizeof(*info.res) * info.res_num;
+ info.res = kmalloc(size, GFP_KERNEL);
+ if (!info.res)
+ goto res_alloc_fail;
+
+ info.name = kmalloc(12, GFP_KERNEL);
+ if (!info.name)
+ goto name_alloc_fail;
+ sprintf(info.name, "PCI Bus #%02x", busnum);
+
+ info.res_num = 0;
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
+ &info);
+ if (info.res_num)
+ adjust_transparent_bridge_resources(bus);
+
+ return;
+
+name_alloc_fail:
+ kfree(info.res);
+res_alloc_fail:
+ return;
+}
+
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{
struct pci_bus *bus;
struct pci_sysdata *sd;
int pxm;
+ dmi_check_system(acpi_pciprobe_dmi_table);
+
+ if (domain && !pci_domains_supported) {
+ printk(KERN_WARNING "PCI: Multiple domains not supported "
+ "(dom %d, bus %d)\n", domain, busnum);
+ return NULL;
+ }
+
/* Allocate per-root-bus (not per bus) arch-specific data.
* TODO: leak; this memory is never freed.
* It's arguable whether it's worth the trouble to care.
@@ -21,12 +205,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
return NULL;
}
- if (domain != 0) {
- printk(KERN_WARNING "PCI: Multiple domains not supported\n");
- kfree(sd);
- return NULL;
- }
-
+ sd->domain = domain;
sd->node = -1;
pxm = acpi_get_pxm(device->handle);
@@ -47,6 +226,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
}
}
#endif
+
+ if (bus && (pci_probe & PCI_USE__CRS))
+ get_current_resources(device, busnum, bus);
return bus;
}
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 07d5223442b..2d71bbc411d 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
- return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
- return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}
struct pci_ops pci_root_ops = {
@@ -287,6 +289,16 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"),
},
},
+#ifdef __i386__
+ {
+ .callback = assign_all_busses,
+ .ident = "Compaq EVO N800c",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"),
+ },
+ },
+#endif
{}
};
@@ -426,6 +438,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
+ } else if (!strcmp(str, "use_crs")) {
+ pci_probe |= PCI_USE__CRS;
+ return NULL;
} else if (!strcmp(str, "routeirq")) {
pci_routeirq = 1;
return NULL;
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index c82cbf4c722..6cff66dd0c9 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -353,6 +353,53 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+
+static struct dmi_system_id __devinitdata msi_k8t_dmi_table[] = {
+ {
+ .ident = "MSI-K8T-Neo2Fir",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"),
+ },
+ },
+ {}
+};
+
+/*
+ * The AMD-Athlon64 board MSI "K8T Neo2-FIR" disables the onboard sound
+ * card if a PCI-soundcard is added.
+ *
+ * The BIOS only gives options "DISABLED" and "AUTO". This code sets
+ * the corresponding register-value to enable the soundcard.
+ *
+ * The soundcard is only enabled, if the mainborad is identified
+ * via DMI-tables and the soundcard is detected to be off.
+ */
+static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
+{
+ unsigned char val;
+ if (!dmi_check_system(msi_k8t_dmi_table))
+ return; /* only applies to MSI K8T Neo2-FIR */
+
+ pci_read_config_byte(dev, 0x50, &val);
+ if (val & 0x40) {
+ pci_write_config_byte(dev, 0x50, val & (~0x40));
+
+ /* verify the change for status output */
+ pci_read_config_byte(dev, 0x50, &val);
+ if (val & 0x40)
+ printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+ "can't enable onboard soundcard!\n");
+ else
+ printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+ "enabled onboard soundcard.\n");
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
+ pci_fixup_msi_k8t_onboard_sound);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
+ pci_fixup_msi_k8t_onboard_sound);
+
/*
* Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
*
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index bcd2f94b732..42ba0e2da1a 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -33,6 +33,15 @@
#include "pci.h"
+static int
+skip_isa_ioresource_align(struct pci_dev *dev) {
+
+ if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) &&
+ !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
+ return 1;
+ return 0;
+}
+
/*
* We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the
@@ -50,9 +59,13 @@ void
pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align)
{
+ struct pci_dev *dev = data;
+
if (res->flags & IORESOURCE_IO) {
resource_size_t start = res->start;
+ if (skip_isa_ioresource_align(dev))
+ return;
if (start & 0x300) {
start = (start + 0x3ff) & ~0x3ff;
res->start = start;
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index d98c6b096f8..c52150fdf82 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -492,6 +492,26 @@ static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq
return 1;
}
+/*
+ * PicoPower PT86C523
+ */
+static int pirq_pico_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ outb(0x10 + ((pirq - 1) >> 1), 0x24);
+ return ((pirq - 1) & 1) ? (inb(0x26) >> 4) : (inb(0x26) & 0xf);
+}
+
+static int pirq_pico_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
+ int irq)
+{
+ unsigned int x;
+ outb(0x10 + ((pirq - 1) >> 1), 0x24);
+ x = inb(0x26);
+ x = ((pirq - 1) & 1) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | (irq));
+ outb(x, 0x26);
+ return 1;
+}
+
#ifdef CONFIG_PCI_BIOS
static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -721,6 +741,24 @@ static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router,
return 1;
}
+static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+ switch (device) {
+ case PCI_DEVICE_ID_PICOPOWER_PT86C523:
+ r->name = "PicoPower PT86C523";
+ r->get = pirq_pico_get;
+ r->set = pirq_pico_set;
+ return 1;
+
+ case PCI_DEVICE_ID_PICOPOWER_PT86C523BBP:
+ r->name = "PicoPower PT86C523 rev. BB+";
+ r->get = pirq_pico_get;
+ r->set = pirq_pico_set;
+ return 1;
+ }
+ return 0;
+}
+
static __initdata struct irq_router_handler pirq_routers[] = {
{ PCI_VENDOR_ID_INTEL, intel_router_probe },
{ PCI_VENDOR_ID_AL, ali_router_probe },
@@ -732,6 +770,7 @@ static __initdata struct irq_router_handler pirq_routers[] = {
{ PCI_VENDOR_ID_VLSI, vlsi_router_probe },
{ PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
{ PCI_VENDOR_ID_AMD, amd_router_probe },
+ { PCI_VENDOR_ID_PICOPOWER, pico_router_probe },
/* Someone with docs needs to add the ATI Radeon IGP */
{ 0, NULL }
};
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index 8c66f275756..ac56d3916c5 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -26,6 +26,8 @@
#define PCI_ASSIGN_ROMS 0x1000
#define PCI_BIOS_IRQ_SCAN 0x2000
#define PCI_ASSIGN_ALL_BUSSES 0x4000
+#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
+#define PCI_USE__CRS 0x10000
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index b1b98e614f7..cf013cb85ea 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -36,6 +36,18 @@ config GENERIC_CMOS_UPDATE
bool
default y
+config CLOCKSOURCE_WATCHDOG
+ bool
+ default y
+
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+ default y
+
config ZONE_DMA32
bool
default y
@@ -130,6 +142,8 @@ source "init/Kconfig"
menu "Processor type and features"
+source "kernel/time/Kconfig"
+
choice
prompt "Subarchitecture Type"
default X86_PC
@@ -724,6 +738,11 @@ config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
depends on PCI && ACPI
+config PCI_DOMAINS
+ bool
+ depends on PCI
+ default y
+
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/Kconfig"
diff --git a/block/Kconfig b/block/Kconfig
index 2484e0e9d89..9bda7bc8030 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -64,4 +64,9 @@ config BLK_DEV_BSG
endif # BLOCK
+config BLOCK_COMPAT
+ bool
+ depends on BLOCK && COMPAT
+ default y
+
source block/Kconfig.iosched
diff --git a/block/Makefile b/block/Makefile
index 3cfe7cebaa6..826108190f0 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -11,4 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
-obj-$(CONFIG_COMPAT) += compat_ioctl.o
+obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
diff --git a/block/bsg.c b/block/bsg.c
index ed264682723..b8ddfc66f21 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -1010,10 +1010,7 @@ unlock:
}
EXPORT_SYMBOL_GPL(bsg_register_queue);
-static struct cdev bsg_cdev = {
- .kobj = {.name = "bsg", },
- .owner = THIS_MODULE,
-};
+static struct cdev bsg_cdev;
static int __init bsg_init(void)
{
diff --git a/block/elevator.c b/block/elevator.c
index c6d153de9fd..b9c518afe1f 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -186,7 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
eq->ops = &e->ops;
eq->elevator_type = e;
kobject_init(&eq->kobj);
- snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
+ kobject_set_name(&eq->kobj, "%s", "iosched");
eq->kobj.ktype = &elv_ktype;
mutex_init(&eq->sysfs_lock);
diff --git a/block/genhd.c b/block/genhd.c
index 3af1e7a378d..e609996f2e7 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
return ((ktype == &ktype_block) || (ktype == &ktype_part));
}
-static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int block_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct kobj_type *ktype = get_ktype(kobj);
struct device *physdev;
struct gendisk *disk;
struct hd_struct *part;
- int length = 0;
- int i = 0;
if (ktype == &ktype_block) {
disk = container_of(kobj, struct gendisk, kobj);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "MINOR=%u", disk->first_minor);
+ add_uevent_var(env, "MINOR=%u", disk->first_minor);
} else if (ktype == &ktype_part) {
disk = container_of(kobj->parent, struct gendisk, kobj);
part = container_of(kobj, struct hd_struct, kobj);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "MINOR=%u",
+ add_uevent_var(env, "MINOR=%u",
disk->first_minor + part->partno);
} else
return 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MAJOR=%u", disk->major);
+ add_uevent_var(env, "MAJOR=%u", disk->major);
/* add physical device, backing this device */
physdev = disk->driverfs_dev;
if (physdev) {
char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
if (physdev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s",
- physdev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
if (physdev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s",
- physdev->driver->name);
+ add_uevent_var(env, physdev->driver->name);
}
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
return 0;
}
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index cd9d2c5d91a..d875673e76c 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1854,7 +1854,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
init_timer(&q->unplug_timer);
- snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
+ kobject_set_name(&q->kobj, "%s", "queue");
q->kobj.ktype = &queue_ktype;
kobject_init(&q->kobj);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index feab124d8e0..cbfc81579c9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->dev.kobj.name));
+ kobject_name(&device->dev.kobj)));
return -ENODEV;
}
/*
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 1e8287b4f40..1f6fb38de01 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
unsigned long reason;
reason = pr->power.timer_broadcast_on_state < INT_MAX ?
CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
clockevents_notify(reason, &pr->id);
-#else
- cpumask_t mask = cpumask_of_cpu(pr->id);
-
- if (pr->power.timer_broadcast_on_state < INT_MAX)
- on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
- else
- on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
}
/* Power(C) State timer broadcast control */
@@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
struct acpi_processor_cx *cx,
int broadcast)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
int state = cx - pr->power.states;
if (state >= pr->power.timer_broadcast_on_state) {
@@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
clockevents_notify(reason, &pr->id);
}
-#endif
}
#else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 64620d66874..5b4d462117c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int len;
- strcpy(buffer, "MODALIAS=");
- if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
- envp[0] = buffer;
- envp[1] = NULL;
- }
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 13369b45563..a736ef7bdee 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -362,7 +362,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
int crt_out = -1;
int tv_out = -1;
u32 hci_result;
- int video_out;
+ u32 video_out;
/* scan expression. Multiple expressions may be delimited with ;
*
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index d05891f1628..b8a2095cb5e 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od)
{
unsigned long state;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
acpi_video_device_get_state(vd, &state);
return (int)state;
}
@@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od)
{
unsigned long state = od->request_state;
struct acpi_video_device *vd=
- (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
return acpi_video_device_set_state(vd, state);
}
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 268e301775f..6b94fb7be5f 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct amba_device *pcdev = to_amba_device(dev);
- int retval = 0, i = 0, len = 0;
+ int retval = 0;
- retval = add_uevent_var(envp, nr_env, &i,
- buf, bufsz, &len,
- "AMBA_ID=%08x", pcdev->periphid);
- envp[i] = NULL;
+ retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
return retval;
}
#else
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index d8046a113c3..33f5eb03877 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -173,6 +173,15 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
+config PATA_ACPI
+ tristate "ACPI firmware driver for PATA"
+ depends on ATA_ACPI
+ help
+ This option enables an ACPI method driver which drives
+ motherboard PATA controller interfaces through the ACPI
+ firmware in the BIOS. This driver can sometimes handle
+ otherwise unsupported hardware.
+
config PATA_ALI
tristate "ALi PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
@@ -192,16 +201,25 @@ config PATA_AMD
If unsure, say N.
config PATA_ARTOP
- tristate "ARTOP 6210/6260 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ARTOP 6210/6260 PATA support"
+ depends on PCI
help
This option enables support for ARTOP PATA controllers.
If unsure, say N.
+config PATA_AT32
+ tristate "Atmel AVR32 PATA support (Experimental)"
+ depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+ help
+ This option enables support for the IDE devices on the
+ Atmel AT32AP platform.
+
+ If unsure, say N.
+
config PATA_ATIIXP
- tristate "ATI PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ATI PATA support"
+ depends on PCI
help
This option enables support for the ATI ATA interfaces
found on the many ATI chipsets.
@@ -219,8 +237,8 @@ config PATA_CMD640_PCI
If unsure, say N.
config PATA_CMD64X
- tristate "CMD64x PATA support (Very Experimental)"
- depends on PCI&& EXPERIMENTAL
+ tristate "CMD64x PATA support"
+ depends on PCI
help
This option enables support for the CMD64x series chips
except for the CMD640.
@@ -254,6 +272,15 @@ config PATA_CS5535
If unsure, say N.
+config PATA_CS5536
+ tristate "CS5536 PATA support (Experimental)"
+ depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ help
+ This option enables support for the AMD CS5536
+ companion chip used with the Geode LX processor family.
+
+ If unsure, say N.
+
config PATA_CYPRESS
tristate "Cypress CY82C693 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
@@ -282,8 +309,8 @@ config ATA_GENERIC
If unsure, say N.
config PATA_HPT366
- tristate "HPT 366/368 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "HPT 366/368 PATA support"
+ depends on PCI
help
This option enables support for the HPT 366 and 368
PATA controllers via the new ATA layer.
@@ -432,6 +459,15 @@ config PATA_NS87410
If unsure, say N.
+config PATA_NS87415
+ tristate "Nat Semi NS87415 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the National Semiconductor
+ NS87415 PCI-IDE controller.
+
+ If unsure, say N.
+
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
@@ -596,4 +632,20 @@ config PATA_SCC
If unsure, say N.
+config PATA_BF54X
+ tristate "Blackfin 54x ATAPI support"
+ depends on BF542 || BF548 || BF549
+ help
+ This option enables support for the built-in ATAPI controller on
+ Blackfin 54x family chips.
+
+ If unsure, say N.
+
+config PATA_BF54X_DMA
+ bool "DMA mode"
+ depends on PATA_BF54X
+ default y
+ help
+ Enable DMA mode for Blackfin ATAPI controller.
+
endif # ATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 8149c68ac2c..6bdc307649e 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -21,12 +21,14 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_AT32) += pata_at32.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
obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
+obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
@@ -39,6 +41,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
@@ -61,12 +64,16 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
+# Should be last but two libata driver
+obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
-libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+ libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c16820325d7..10bc3f64c45 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "3.0"
enum {
@@ -77,11 +77,10 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_pi = 1,
- board_ahci_vt8251 = 2,
- board_ahci_ign_iferr = 3,
- board_ahci_sb600 = 4,
- board_ahci_mv = 5,
+ board_ahci_vt8251 = 1,
+ board_ahci_ign_iferr = 2,
+ board_ahci_sb600 = 3,
+ board_ahci_mv = 4,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -97,6 +96,7 @@ enum {
/* HOST_CAP bits */
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */
@@ -144,7 +144,8 @@ enum {
PORT_IRQ_IF_ERR |
PORT_IRQ_CONNECT |
PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS |
+ PORT_IRQ_BAD_PMP,
PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
PORT_IRQ_TF_ERR |
PORT_IRQ_HBUS_DATA_ERR,
@@ -154,6 +155,7 @@ enum {
/* PORT_CMD bits */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_PMP = (1 << 17), /* PMP attached */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
@@ -167,19 +169,22 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ /* hpriv->flags bits */
+ AHCI_HFLAG_NO_NCQ = (1 << 0),
+ AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
+ AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
+ AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
+ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
+ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
+ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
+
/* ap->flags bits */
- AHCI_FLAG_NO_NCQ = (1 << 24),
- 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_32BIT_ONLY = (1 << 28), /* force 32bit */
- AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
- AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
+ AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
+ AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
};
struct ahci_cmd_hdr {
@@ -198,6 +203,7 @@ struct ahci_sg {
};
struct ahci_host_priv {
+ unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
@@ -205,6 +211,7 @@ struct ahci_host_priv {
};
struct ahci_port_priv {
+ struct ata_link *active_link;
struct ahci_cmd_hdr *cmd_slot;
dma_addr_t cmd_slot_dma;
void *cmd_tbl;
@@ -215,6 +222,7 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
+ u32 intr_mask; /* interrupts to enable */
};
static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
@@ -229,6 +237,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -262,20 +272,17 @@ static struct scsi_host_template ahci_sht = {
};
static const struct ata_port_operations ahci_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -286,6 +293,9 @@ static const struct ata_port_operations ahci_ops = {
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -296,20 +306,17 @@ static const struct ata_port_operations ahci_ops = {
};
static const struct ata_port_operations ahci_vt8251_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -320,6 +327,9 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.error_handler = ahci_vt8251_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -329,53 +339,52 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.port_stop = ahci_port_stop,
};
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
- },
- /* board_ahci_pi */
- {
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
{
- .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
- AHCI_FLAG_NO_NCQ,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
- .flags = AHCI_FLAG_COMMON |
- AHCI_FLAG_IGN_SERR_INTERNAL |
- AHCI_FLAG_32BIT_ONLY,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
+ AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_mv */
{
- .sht = &ahci_sht,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_MV_PATA),
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
- AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
- AHCI_FLAG_MV_PATA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
@@ -394,23 +403,25 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -474,6 +485,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
/* SiS */
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
@@ -524,7 +543,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
/**
* 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
@@ -538,7 +556,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
* None.
*/
static void ahci_save_initial_config(struct pci_dev *pdev,
- const struct ata_port_info *pi,
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
@@ -552,26 +569,22 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
/* some chips have errata preventing 64bit use */
- if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
- if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+ if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do NCQ, turning off CAP_NCQ\n");
cap &= ~HOST_CAP_NCQ;
}
- /* fixup zero port_map */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(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;
+ if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do PMP, turning off CAP_PMP\n");
+ cap &= ~HOST_CAP_PMP;
}
/*
@@ -579,7 +592,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
* is asserted through the standard AHCI port
* presence register, as bit 4 (counting from 0)
*/
- if (pi->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
dev_printk(KERN_ERR, &pdev->dev,
"MV_AHCI HACK: port_map %x -> %x\n",
hpriv->port_map,
@@ -589,7 +602,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
/* cross check port_map and cap.n_ports */
- if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ if (port_map) {
u32 tmp_port_map = port_map;
int n_ports = ahci_nr_ports(cap);
@@ -600,17 +613,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
}
- /* Whine if inconsistent. No need to update cap.
- * port_map is used to determine number of ports.
+ /* If n_ports and port_map are inconsistent, whine and
+ * clear port_map and let it be generated from n_ports.
*/
- if (n_ports || tmp_port_map)
+ 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",
+ "(0x%x) don't match, using nr_ports\n",
ahci_nr_ports(cap), port_map);
- } else {
- /* fabricate port_map from cap.nr_ports */
+ port_map = 0;
+ }
+ }
+
+ /* fabricate port_map from cap.nr_ports */
+ if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
}
/* record values to use during operation */
@@ -836,8 +858,14 @@ static int ahci_reset_controller(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 tmp;
- /* global controller reset */
+ /* we must be in AHCI mode, before using anything
+ * AHCI-specific, such as HOST_RESET.
+ */
tmp = readl(mmio + HOST_CTL);
+ if (!(tmp & HOST_AHCI_EN))
+ writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL);
+
+ /* global controller reset */
if ((tmp & HOST_RESET) == 0) {
writel(tmp | HOST_RESET, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
@@ -904,13 +932,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
static void ahci_init_controller(struct ata_host *host)
{
+ 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];
int i;
void __iomem *port_mmio;
u32 tmp;
- if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
port_mmio = __ahci_port_base(host, 4);
writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1042,9 +1071,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}
-static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
@@ -1052,7 +1082,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
return 0;
@@ -1061,10 +1091,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
/* prepare for SRST (AHCI-1.1 10.4.1) */
rc = ahci_kick_engine(ap, 1);
if (rc)
- ata_port_printk(ap, KERN_WARNING,
+ ata_link_printk(link, KERN_WARNING,
"failed to reset engine (errno=%d)", rc);
- ata_tf_init(ap->device, &tf);
+ ata_tf_init(link->device, &tf);
/* issue the first D2H Register FIS */
msecs = 0;
@@ -1109,19 +1139,25 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
return 0;
fail:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- return ahci_do_softreset(ap, class, 0, deadline);
+ int pmp = 0;
+
+ if (link->ap->flags & ATA_FLAG_PMP)
+ pmp = SATA_PMP_CTRL_PORT;
+
+ return ahci_do_softreset(link, class, pmp, deadline);
}
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
@@ -1132,26 +1168,27 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(ap->device, &tf);
+ ata_tf_init(link->device, &tf);
tf.command = 0x80;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
- rc = sata_std_hardreset(ap, class, deadline);
+ rc = sata_std_hardreset(link, class, deadline);
ahci_start_engine(ap);
- if (rc == 0 && ata_port_online(ap))
+ if (rc == 0 && ata_link_online(link))
*class = ahci_dev_classify(ap);
- if (*class == ATA_DEV_UNKNOWN)
+ if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
return rc;
}
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
u32 serror;
int rc;
@@ -1159,7 +1196,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
ahci_stop_engine(ap);
- rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline);
/* vt8251 needs SError cleared for the port to operate */
@@ -1176,12 +1213,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
return rc ?: -EAGAIN;
}
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
u32 new_tmp, tmp;
- ata_std_postreset(ap, class);
+ ata_std_postreset(link, class);
/* Make sure port's ATAPI bit is set appropriately */
new_tmp = tmp = readl(port_mmio + PORT_CMD);
@@ -1195,6 +1233,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
}
}
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
static u8 ahci_check_status(struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1253,7 +1297,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1266,7 +1310,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
/*
* Fill in command slot information.
*/
- opts = cmd_fis_len | n_elem << 16;
+ opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
if (qc->tf.flags & ATA_TFLAG_WRITE)
opts |= AHCI_CMD_WRITE;
if (is_atapi)
@@ -1277,66 +1321,87 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
+ struct ata_eh_info *host_ehi = &ap->link.eh_info;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *active_qc;
+ struct ata_eh_info *active_ehi;
u32 serror;
- ata_ehi_clear_desc(ehi);
+ /* determine active link */
+ ata_port_for_each_link(link, ap)
+ if (ata_link_active(link))
+ break;
+ if (!link)
+ link = &ap->link;
+
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ active_ehi = &link->eh_info;
+
+ /* record irq stat */
+ ata_ehi_clear_desc(host_ehi);
+ ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */
ahci_scr_read(ap, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror);
-
- /* analyze @irq_stat */
- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
- if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+ if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
irq_stat &= ~PORT_IRQ_IF_ERR;
if (irq_stat & PORT_IRQ_TF_ERR) {
- err_mask |= AC_ERR_DEV;
- if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
- serror &= ~SERR_INTERNAL;
+ /* If qc is active, charge it; otherwise, the active
+ * link. There's no active qc on NCQ errors. It will
+ * be determined by EH by reading log page 10h.
+ */
+ if (active_qc)
+ active_qc->err_mask |= AC_ERR_DEV;
+ else
+ active_ehi->err_mask |= AC_ERR_DEV;
+
+ if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+ host_ehi->serror &= ~SERR_INTERNAL;
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi,
+ "unknown FIS %08x %08x %08x %08x" ,
+ unk[0], unk[1], unk[2], unk[3]);
+ }
+
+ if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi, "incorrect PMP");
}
if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- err_mask |= AC_ERR_HOST_BUS;
- action |= ATA_EH_SOFTRESET;
+ host_ehi->err_mask |= AC_ERR_HOST_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "host bus error");
}
if (irq_stat & PORT_IRQ_IF_ERR) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, "interface fatal error");
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+ ata_ehi_hotplugged(host_ehi);
+ ata_ehi_push_desc(host_ehi, "%s",
+ irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- err_mask |= AC_ERR_HSM;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
- unk[0], unk[1], unk[2], unk[3]);
- }
-
/* okay, let's hand over to EH */
- ehi->serror |= serror;
- ehi->action |= action;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc)
- qc->err_mask |= err_mask;
- else
- ehi->err_mask |= err_mask;
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
@@ -1347,25 +1412,64 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 status, qc_active;
int rc, known_irq = 0;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
+ /* ignore BAD_PMP while resetting */
+ if (unlikely(resetting))
+ status &= ~PORT_IRQ_BAD_PMP;
+
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
}
- if (ap->sactive)
+ if (status & PORT_IRQ_SDB_FIS) {
+ /* If SNotification is available, leave notification
+ * handling to sata_async_notification(). If not,
+ * emulate it by snooping SDB FIS RX area.
+ *
+ * Snooping FIS RX area is probably cheaper than
+ * poking SNotification but some constrollers which
+ * implement SNotification, ICH9 for example, don't
+ * store AN SDB FIS into receive area.
+ */
+ if (hpriv->cap & HOST_CAP_SNTF)
+ sata_async_notification(ap);
+ else {
+ /* If the 'N' bit in word 0 of the FIS is set,
+ * we just received asynchronous notification.
+ * Tell libata about it.
+ */
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
+ }
+
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
qc_active = readl(port_mmio + PORT_SCR_ACT);
else
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+ /* If resetting, spurious or invalid completions are expected,
+ * return unconditionally.
+ */
+ if (resetting)
+ return;
+
if (rc > 0)
return;
if (rc < 0) {
@@ -1380,7 +1484,7 @@ static void ahci_port_intr(struct ata_port *ap)
/* if !NCQ, ignore. No modern ATA device has broken HSM
* implementation for non-NCQ commands.
*/
- if (!ap->sactive)
+ if (!ap->link.sactive)
return;
if (status & PORT_IRQ_D2H_REG_FIS) {
@@ -1433,7 +1537,7 @@ static void ahci_port_intr(struct ata_port *ap)
if (!known_irq)
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
- status, ap->active_tag, ap->sactive);
+ status, ap->link.active_tag, ap->link.sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -1498,6 +1602,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* Keep track of the currently active link. It will be used
+ * in completion path to determine whether NCQ phase is in
+ * progress.
+ */
+ pp->active_link = qc->dev->link;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1520,6 +1631,7 @@ static void ahci_thaw(struct ata_port *ap)
void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
/* clear IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
@@ -1527,7 +1639,7 @@ static void ahci_thaw(struct ata_port *ap)
writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
/* turn IRQ back on */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static void ahci_error_handler(struct ata_port *ap)
@@ -1539,8 +1651,10 @@ static void ahci_error_handler(struct ata_port *ap)
}
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
- ahci_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+ ahci_hardreset, ahci_postreset,
+ sata_pmp_std_prereset, ahci_pmp_softreset,
+ sata_pmp_std_hardreset, sata_pmp_std_postreset);
}
static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1565,11 +1679,44 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
ahci_kick_engine(ap, 1);
}
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd |= PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask |= PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd &= ~PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
static int ahci_port_resume(struct ata_port *ap)
{
ahci_power_up(ap);
ahci_start_port(ap);
+ if (ap->nr_pmp_links)
+ ahci_pmp_attach(ap);
+ else
+ ahci_pmp_detach(ap);
+
return 0;
}
@@ -1681,6 +1828,12 @@ static int ahci_port_start(struct ata_port *ap)
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
+ /*
+ * Save off initial list of interrupts to be enabled.
+ * This could be changed later
+ */
+ pp->intr_mask = DEF_PORT_IRQ;
+
ap->private_data = pp;
/* engage engines, captain */
@@ -1830,20 +1983,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
-
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+ pci_intx(pdev, 1);
/* save initial config */
- ahci_save_initial_config(pdev, &pi, hpriv);
+ ahci_save_initial_config(pdev, hpriv);
/* prepare host */
if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
if (!host)
return -ENOMEM;
@@ -1854,6 +2011,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port *ap = host->ports[i];
void __iomem *port_mmio = ahci_port_base(ap);
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ 0x100 + ap->port_no * 0x80, "port");
+
/* standard SATA port setup */
if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 94546695472..90329982bef 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -34,7 +34,7 @@
/**
* generic_set_mode - mode setting
- * @ap: interface to set up
+ * @link: link to set up
* @unused: returned device on error
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -43,24 +43,24 @@
* and respect them.
*/
-static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
{
+ struct ata_port *ap = link->ap;
int dma_enabled = 0;
- int i;
+ struct ata_device *dev;
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
- if (dma_enabled & (1 << (5 + i))) {
+ if (dma_enabled & (1 << (5 + dev->devno))) {
ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
@@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = {
static struct ata_port_operations generic_port_ops = {
.set_mode = generic_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -121,9 +120,8 @@ static struct ata_port_operations generic_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int all_generic_ide; /* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 92c2d5082be..3c6f43e381f 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -123,7 +123,6 @@ enum {
ich_pata_33 = 1, /* ICH up to UDMA 33 only */
ich_pata_66 = 2, /* ICH up to 66 Mhz */
ich_pata_100 = 3, /* ICH up to UDMA 100 */
- ich_pata_133 = 4, /* ICH up to UDMA 133 */
ich5_sata = 5,
ich6_sata = 6,
ich6_sata_ahci = 7,
@@ -131,6 +130,7 @@ enum {
ich8_sata_ahci = 9,
piix_pata_mwdma = 10, /* PIIX3 MWDMA only */
tolapai_sata_ahci = 11,
+ ich9_2port_sata = 12,
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -199,7 +199,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH5 */
- { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* C-ICH (i810E2) */
{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ESB (855GME/875P + 6300ESB) UDMA 100 */
@@ -207,7 +207,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH6 (and 6) (i915) UDMA 100 */
{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH7/7-R (i945, i975) UDMA 100*/
- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH8 Mobile PATA Controller */
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -239,19 +239,19 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller 1 IDE (ICH8) */
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller 2 IDE (ICH8) */
- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* Mobile SATA Controller IDE (ICH8M) */
{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (ICH9) */
{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (ICH9) */
- { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9) */
- { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
- { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
- { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (Tolapai) */
@@ -290,7 +290,6 @@ static struct scsi_host_template piix_sht = {
};
static const struct ata_port_operations piix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -318,13 +317,11 @@ static const struct ata_port_operations piix_pata_ops = {
.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 const struct ata_port_operations ich_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = ich_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -352,14 +349,11 @@ static const struct ata_port_operations ich_pata_ops = {
.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 const struct ata_port_operations piix_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -382,7 +376,6 @@ static const struct ata_port_operations piix_sata_ops = {
.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,
};
@@ -445,15 +438,27 @@ static const struct piix_map_db ich8_map_db = {
};
static const struct piix_map_db tolapai_map_db = {
- .mask = 0x3,
- .port_enable = 0x3,
- .map = {
- /* PM PS SM SS MAP */
- { P0, NA, P1, NA }, /* 00b */
- { RV, RV, RV, RV }, /* 01b */
- { RV, RV, RV, RV }, /* 10b */
- { RV, RV, RV, RV },
- },
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b */
+ { RV, RV, RV, RV }, /* 01b */
+ { RV, RV, RV, RV }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich9_2port_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b */
+ { RV, RV, RV, RV }, /* 01b */
+ { RV, RV, RV, RV }, /* 10b */
+ { RV, RV, RV, RV },
+ },
};
static const struct piix_map_db *piix_map_db_table[] = {
@@ -463,10 +468,11 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich6m_sata_ahci] = &ich6m_map_db,
[ich8_sata_ahci] = &ich8_map_db,
[tolapai_sata_ahci] = &tolapai_map_db,
+ [ich9_2port_sata] = &ich9_2port_map_db,
};
static struct ata_port_info piix_port_info[] = {
- /* piix_pata_33: 0: PIIX4 at 33MHz */
+ [piix_pata_33] = /* PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -476,7 +482,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_pata_ops,
},
- /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
+ [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -485,7 +491,8 @@ static struct ata_port_info piix_port_info[] = {
.udma_mask = ATA_UDMA2, /* UDMA33 */
.port_ops = &ich_pata_ops,
},
- /* ich_pata_66: 2 ICH controllers up to 66MHz */
+
+ [ich_pata_66] = /* ICH controllers up to 66MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -495,7 +502,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_100: 3 */
+ [ich_pata_100] =
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
@@ -505,17 +512,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_133: 4 ICH with full UDMA6 */
- {
- .sht = &piix_sht,
- .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio 0-4 */
- .mwdma_mask = 0x06, /* Check: maybe 0x07 */
- .udma_mask = ATA_UDMA6, /* UDMA133 */
- .port_ops = &ich_pata_ops,
- },
-
- /* ich5_sata: 5 */
+ [ich5_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS,
@@ -525,7 +522,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata: 6 */
+ [ich6_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
@@ -535,7 +532,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata_ahci: 7 */
+ [ich6_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -546,7 +543,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6m_sata_ahci: 8 */
+ [ich6m_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -557,7 +554,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich8_sata_ahci: 9 */
+ [ich8_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -568,7 +565,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* piix_pata_mwdma: 10: PIIX3 MWDMA only */
+ [piix_pata_mwdma] = /* PIIX3 MWDMA only */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -577,7 +574,18 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_pata_ops,
},
- /* tolapai_sata_ahci: 11: */
+ [tolapai_sata_ahci] =
+ {
+ .sht = &piix_sht,
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich9_2port_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -615,6 +623,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
+ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
/* end marker */
{ 0, }
@@ -657,19 +666,20 @@ static int ich_pata_cable_detect(struct ata_port *ap)
/**
* piix_pata_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* LOCKING:
* None (inherited from caller).
*/
-static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->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;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void piix_pata_error_handler(struct ata_port *ap)
@@ -1137,7 +1147,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
const struct piix_map_db *map_db)
{
struct piix_host_priv *hpriv = pinfo[0].private_data;
- const unsigned int *map;
+ const int *map;
int i, invalid_map = 0;
u8 map_value;
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index c059f78ad94..3f753358904 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/pci.h>
+#include <scsi/scsi_device.h>
#include "libata.h"
#include <acpi/acpi_bus.h>
@@ -40,11 +41,40 @@ static int is_pci_dev(struct device *dev)
return (dev->bus == &pci_bus_type);
}
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
{
- acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+ WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
+
+ if (!ap->nr_pmp_links) {
+ acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+ ap->link.device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ } else {
+ struct ata_link *link;
+
+ ap->link.device->acpi_handle = NULL;
- ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr);
+ ata_port_for_each_link(link, ap) {
+ acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+
+ link->device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ }
+ }
}
static void ata_acpi_associate_ide_port(struct ata_port *ap)
@@ -60,12 +90,53 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
max_devices++;
for (i = 0; i < max_devices; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev = &ap->link.device[i];
dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
}
}
+static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj,
+ u32 event)
+{
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ if (event == 0 || event == 1) {
+ unsigned long flags;
+ spin_lock_irqsave(ap->lock, flags);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "ACPI event");
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ if (kobj) {
+ sprintf(event_string, "BAY_EVENT=%d", event);
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ }
+}
+
+static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+ struct kobject *kobj = NULL;
+
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+
+ ata_acpi_handle_hotplug (dev->link->ap, kobj, event);
+}
+
+static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_port *ap = data;
+
+ ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event);
+}
+
/**
* ata_acpi_associate - associate ATA host with ACPI objects
* @host: target ATA host
@@ -81,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
*/
void ata_acpi_associate(struct ata_host *host)
{
- int i;
+ int i, j;
if (!is_pci_dev(host->dev) || libata_noacpi)
return;
@@ -97,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_associate_sata_port(ap);
else
ata_acpi_associate_ide_port(ap);
+
+ if (ap->acpi_handle)
+ acpi_install_notify_handler (ap->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_ap_notify,
+ ap);
+
+ for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
+ struct ata_device *dev = &ap->link.device[j];
+
+ if (dev->acpi_handle)
+ acpi_install_notify_handler (dev->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_dev_notify,
+ dev);
+ }
}
}
@@ -113,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host)
* RETURNS:
* 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
*/
-static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
{
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
union acpi_object *out_obj;
@@ -157,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
return rc;
}
+EXPORT_SYMBOL_GPL(ata_acpi_gtm);
+
/**
* ata_acpi_stm - execute _STM
* @ap: target ATA port
@@ -170,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
* RETURNS:
* 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
*/
-static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
{
acpi_status status;
struct acpi_object_list input;
@@ -182,10 +271,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
/* Buffers for id may need byteswapping ? */
in_params[1].type = ACPI_TYPE_BUFFER;
in_params[1].buffer.length = 512;
- in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
+ in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id;
in_params[2].type = ACPI_TYPE_BUFFER;
in_params[2].buffer.length = 512;
- in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
+ in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id;
input.count = 3;
input.pointer = in_params;
@@ -202,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
return 0;
}
+EXPORT_SYMBOL_GPL(ata_acpi_stm);
+
/**
* ata_dev_get_GTF - get the drive bootup default taskfile settings
* @dev: target ATA device
@@ -226,7 +317,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
void **ptr_to_free)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
acpi_status status;
struct acpi_buffer output;
union acpi_object *out_obj;
@@ -296,6 +387,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
}
/**
+ * ata_acpi_cbl_80wire - Check for 80 wire cable
+ * @ap: Port to check
+ *
+ * Return 1 if the ACPI mode data for this port indicates the BIOS selected
+ * an 80wire mode.
+ */
+
+int ata_acpi_cbl_80wire(struct ata_port *ap)
+{
+ struct ata_acpi_gtm gtm;
+ int valid = 0;
+
+ /* No _GTM data, no information */
+ if (ata_acpi_gtm(ap, &gtm) < 0)
+ return 0;
+
+ /* Split timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55)
+ valid |= 2;
+ /* Shared timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55)
+ valid |= 2;
+
+ /* Drive check */
+ if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
+ return 1;
+ if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
+ return 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+
+/**
* taskfile_load_raw - send taskfile registers to host controller
* @dev: target ATA device
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
@@ -320,7 +449,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
static int taskfile_load_raw(struct ata_device *dev,
const struct ata_acpi_gtf *gtf)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf, rtf;
unsigned int err_mask;
@@ -349,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev,
tf.lbal, tf.lbam, tf.lbah, tf.device);
rtf = tf;
- err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR,
"ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed "
@@ -424,7 +553,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
*/
static int ata_acpi_push_id(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int err;
acpi_status status;
struct acpi_object_list input;
@@ -508,7 +637,7 @@ int ata_acpi_on_suspend(struct ata_port *ap)
*/
void ata_acpi_on_resume(struct ata_port *ap)
{
- int i;
+ struct ata_device *dev;
if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
@@ -518,8 +647,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
/* schedule _GTF */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
/**
@@ -538,8 +667,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
*/
int ata_acpi_on_devcfg(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
int rc;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 772be09b468..68699b3e799 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,8 +59,6 @@
#include "libata.h"
-#define DRV_VERSION "2.21" /* must be exactly four chars */
-
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
@@ -70,6 +68,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable);
static void ata_dev_xfermask(struct ata_device *dev);
static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
@@ -86,6 +85,10 @@ int atapi_dmadir = 0;
module_param(atapi_dmadir, int, 0444);
MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
@@ -94,13 +97,17 @@ 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 libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
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)");
-int libata_noacpi = 1;
+int libata_noacpi = 0;
module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
@@ -235,7 +242,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
if (dev->flags & ATA_DFLAG_PIO) {
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
- } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
+ } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) {
/* Unable to use DMA due to host limitation */
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
@@ -604,7 +611,7 @@ static const char *sata_spd_string(unsigned int spd)
void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev)) {
- if (ata_msg_drv(dev->ap))
+ if (ata_msg_drv(dev->link->ap))
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
ATA_DNXFER_QUIET);
@@ -667,37 +674,57 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
* None.
*
* RETURNS:
- * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- * the event of failure.
+ * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ * %ATA_DEV_UNKNOWN the event of failure.
*/
-
unsigned int ata_dev_classify(const struct ata_taskfile *tf)
{
/* Apple's open source Darwin code hints that some devices only
* put a proper signature into the LBA mid/high registers,
* So, we only check those. It's sufficient for uniqueness.
+ *
+ * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+ * signatures for ATA and ATAPI devices attached on SerialATA,
+ * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA
+ * spec has never mentioned about using different signatures
+ * for ATA/ATAPI devices. Then, Serial ATA II: Port
+ * Multiplier specification began to use 0x69/0x96 to identify
+ * port multpliers and 0x3c/0xc3 to identify SEMB device.
+ * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+ * 0x69/0x96 shortly and described them as reserved for
+ * SerialATA.
+ *
+ * We follow the current spec and consider that 0x69/0x96
+ * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
*/
-
- if (((tf->lbam == 0) && (tf->lbah == 0)) ||
- ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+ if ((tf->lbam == 0) && (tf->lbah == 0)) {
DPRINTK("found ATA device by sig\n");
return ATA_DEV_ATA;
}
- if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
- ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+ if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
DPRINTK("found ATAPI device by sig\n");
return ATA_DEV_ATAPI;
}
+ if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+ DPRINTK("found PMP device by sig\n");
+ return ATA_DEV_PMP;
+ }
+
+ if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+ printk("ata: SEMB device ignored\n");
+ return ATA_DEV_SEMB_UNSUP; /* not yet */
+ }
+
DPRINTK("unknown device\n");
return ATA_DEV_UNKNOWN;
}
/**
* ata_dev_try_classify - Parse returned ATA device signature
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
+ * @dev: ATA device to classify (starting at zero)
+ * @present: device seems present
* @r_err: Value of error register on completion
*
* After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
@@ -715,15 +742,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
* RETURNS:
* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-
-unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+ u8 *r_err)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
unsigned int class;
u8 err;
- ap->ops->dev_select(ap, device);
+ ap->ops->dev_select(ap, dev->devno);
memset(&tf, 0, sizeof(tf));
@@ -733,12 +760,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
*r_err = err;
/* see if device passed diags: if master then continue and warn later */
- if (err == 0 && device == 0)
+ if (err == 0 && dev->devno == 0)
/* diagnostic fail : do nothing _YET_ */
- ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
else if (err == 1)
/* do nothing */ ;
- else if ((device == 0) && (err == 0x81))
+ else if ((dev->devno == 0) && (err == 0x81))
/* do nothing */ ;
else
return ATA_DEV_NONE;
@@ -746,10 +773,20 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
/* determine if device is ATA or ATAPI */
class = ata_dev_classify(&tf);
- if (class == ATA_DEV_UNKNOWN)
- return ATA_DEV_NONE;
- if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
- return ATA_DEV_NONE;
+ if (class == ATA_DEV_UNKNOWN) {
+ /* If the device failed diagnostic, it's likely to
+ * have reported incorrect device signature too.
+ * Assume ATA device if the device seems present but
+ * device signature is invalid with diagnostic
+ * failure.
+ */
+ if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
+ class = ATA_DEV_ATA;
+ else
+ class = ATA_DEV_NONE;
+ } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+ class = ATA_DEV_NONE;
+
return class;
}
@@ -816,6 +853,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
*p = '\0';
}
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
{
u64 sectors = 0;
@@ -843,129 +895,110 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf)
}
/**
- * ata_read_native_max_address_ext - LBA48 native max query
- * @dev: Device to query
+ * ata_read_native_max_address - Read native max address
+ * @dev: target device
+ * @max_sectors: out parameter for the result native max address
*
- * 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
+ * Perform an LBA48 or LBA28 native size query upon the device in
+ * question.
*
- * Performa an LBA28 size query upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted by the drive.
+ * -EIO on other errors.
*/
-
-static u64 ata_read_native_max_address(struct ata_device *dev)
+static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_READ_NATIVE_MAX;
+ /* always clear all address registers */
tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+ if (lba48) {
+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
+ } else
+ tf.command = ATA_CMD_READ_NATIVE_MAX;
+
tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
+ tf.device |= ATA_LBA;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to read native "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ if (lba48)
+ *max_sectors = ata_tf_to_lba48(&tf);
+ else
+ *max_sectors = ata_tf_to_lba(&tf);
+ if (dev->horkage & ATA_HORKAGE_HPA_SIZE)
+ (*max_sectors)--;
+ return 0;
}
/**
- * ata_set_native_max_address_ext - LBA48 native max set
- * @dev: Device to query
+ * ata_set_max_sectors - Set max sectors
+ * @dev: target device
* @new_sectors: new max sectors value to set for the device
*
- * Perform an LBA48 size set max upon the device in question. Return the
- * actual LBA48 size or zero if the command fails.
+ * Set max sectors of @dev to @new_sectors.
+ *
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted or denied (due to
+ * previous non-volatile SET_MAX) by the drive. -EIO on other
+ * errors.
*/
-
-static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
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
- * @new_sectors: new max sectors value to set for the device
- *
- * Perform an LBA28 size set max upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
- */
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
-static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
-{
- unsigned int err;
- struct ata_taskfile tf;
+ if (lba48) {
+ tf.command = ATA_CMD_SET_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
- new_sectors--;
+ tf.hob_lbal = (new_sectors >> 24) & 0xff;
+ tf.hob_lbam = (new_sectors >> 32) & 0xff;
+ tf.hob_lbah = (new_sectors >> 40) & 0xff;
+ } else {
+ tf.command = ATA_CMD_SET_MAX;
- ata_tf_init(dev, &tf);
+ tf.device |= (new_sectors >> 24) & 0xf;
+ }
- tf.command = ATA_CMD_SET_MAX;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= ATA_LBA;
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;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to set "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV &&
+ (tf.feature & (ATA_ABORTED | ATA_IDNF)))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ return 0;
}
/**
@@ -975,60 +1008,93 @@ static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
* 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.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
{
- u64 sectors = dev->n_sectors;
- u64 hpa_sectors;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+ u64 sectors = ata_id_n_sectors(dev->id);
+ u64 native_sectors;
+ int rc;
- 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);
+ /* do we need to do it? */
+ if (dev->class != ATA_DEV_ATA ||
+ !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+ (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
+ return 0;
- 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;
- }
+ /* read native max address */
+ rc = ata_read_native_max_address(dev, &native_sectors);
+ if (rc) {
+ /* If HPA isn't going to be unlocked, skip HPA
+ * resizing from the next try.
+ */
+ if (!ata_ignore_hpa) {
+ ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+ "broken, will skip HPA handling\n");
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+
+ /* we can continue if device aborted the command */
+ if (rc == -EACCES)
+ rc = 0;
}
- } else if (hpa_sectors < sectors)
- ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
- "is smaller than sectors (%lld)\n", __FUNCTION__,
- (long long)hpa_sectors, (long long)sectors);
- return sectors;
-}
+ return rc;
+ }
-static u64 ata_id_n_sectors(const u16 *id)
-{
- if (ata_id_has_lba(id)) {
- if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
- else
- return ata_id_u32(id, 60);
- } else {
- if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
- else
- return id[1] * id[3] * id[6];
+ /* nothing to do? */
+ if (native_sectors <= sectors || !ata_ignore_hpa) {
+ if (!print_info || native_sectors == sectors)
+ return 0;
+
+ if (native_sectors > sectors)
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA detected: current %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ else if (native_sectors < sectors)
+ ata_dev_printk(dev, KERN_WARNING,
+ "native sectors (%llu) is smaller than "
+ "sectors (%llu)\n",
+ (unsigned long long)native_sectors,
+ (unsigned long long)sectors);
+ return 0;
+ }
+
+ /* let's unlock HPA */
+ rc = ata_set_max_sectors(dev, native_sectors);
+ if (rc == -EACCES) {
+ /* if device aborted the command, skip HPA resizing */
+ ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+ "(%llu -> %llu), skipping HPA handling\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+ return 0;
+ } else if (rc)
+ return rc;
+
+ /* re-read IDENTIFY data */
+ rc = ata_dev_reread_id(dev, 0);
+ if (rc) {
+ ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+ "data after HPA resizing\n");
+ return rc;
}
+
+ if (print_info) {
+ u64 new_sectors = ata_id_n_sectors(dev->id);
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA unlocked: %llu -> %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)new_sectors,
+ (unsigned long long)native_sectors);
+ }
+
+ return 0;
}
/**
@@ -1150,7 +1216,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
ap->ops->dev_select(ap, device);
if (wait) {
- if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+ if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
msleep(150);
ata_wait_idle(ap);
}
@@ -1328,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* @dma_dir: Data tranfer direction of the command
* @sg: sg list for the data buffer of the command
* @n_elem: Number of sg entries
+ * @timeout: Timeout in msecs (0 for default)
*
* Executes libata internal command with timeout. @tf contains
* command on entry and result on return. Timeout and error
@@ -1344,13 +1411,15 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
- unsigned int n_elem)
+ unsigned int n_elem, unsigned long timeout)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
u8 command = tf->command;
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1386,12 +1455,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->dev = dev;
ata_qc_reinit(qc);
- preempted_tag = ap->active_tag;
- preempted_sactive = ap->sactive;
+ preempted_tag = link->active_tag;
+ preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
- ap->active_tag = ATA_TAG_POISON;
- ap->sactive = 0;
+ preempted_nr_active_links = ap->nr_active_links;
+ link->active_tag = ATA_TAG_POISON;
+ link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1416,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+ if (!timeout)
+ timeout = ata_probe_timeout * 1000 / HZ;
+
+ rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
ata_port_flush_task(ap);
@@ -1467,9 +1541,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
err_mask = qc->err_mask;
ata_qc_free(qc);
- ap->active_tag = preempted_tag;
- ap->sactive = preempted_sactive;
+ link->active_tag = preempted_tag;
+ link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -1500,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
* @dma_dir: Data tranfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
+ * @timeout: Timeout in msecs (0 for default)
*
* Wrapper around ata_exec_internal_sg() which takes simple
* buffer instead of sg list.
@@ -1512,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
*/
unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen)
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout)
{
struct scatterlist *psg = NULL, sg;
unsigned int n_elem = 0;
@@ -1524,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev,
n_elem++;
}
- return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
+ return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem,
+ timeout);
}
/**
@@ -1551,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
tf.flags |= ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
- return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
}
/**
@@ -1566,7 +1644,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
/* Controller doesn't support IORDY. Probably a pointless check
as the caller should know this */
- if (adev->ap->flags & ATA_FLAG_NO_IORDY)
+ if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
/* PIO3 and higher it is mandatory */
if (adev->pio_mode > XFER_PIO_2)
@@ -1613,6 +1691,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
* devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
* for pre-ATA4 drives.
*
+ * FIXME: ATA_CMD_ID_ATA is optional for early drives and right
+ * now we abort if we hit that case.
+ *
* LOCKING:
* Kernel thread context (may sleep)
*
@@ -1622,7 +1703,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
unsigned int class = *p_class;
struct ata_taskfile tf;
unsigned int err_mask = 0;
@@ -1663,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
tf.flags |= ATA_TFLAG_POLLING;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- id, sizeof(id[0]) * ATA_ID_WORDS);
+ id, sizeof(id[0]) * ATA_ID_WORDS, 0);
if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
DPRINTK("ata%u.%d: NODEV after polling detection\n",
@@ -1722,7 +1803,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
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);
+ err_mask = ata_exec_internal(dev, &tf, NULL,
+ DMA_NONE, NULL, 0, 0);
if (err_mask && id[2] != 0x738c) {
rc = -EIO;
reason = "SPINUP failed";
@@ -1740,10 +1822,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
/*
* The exact sequence expected by certain pre-ATA4 drives is:
* SRST RESET
- * IDENTIFY
- * INITIALIZE DEVICE PARAMETERS
+ * IDENTIFY (optional in early ATA)
+ * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
* anything else..
* Some drives were very specific about that exact sequence.
+ *
+ * Note that ATA4 says lba is mandatory so the second check
+ * shoud never trigger.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -1774,13 +1859,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
static inline u8 ata_dev_knobble(struct ata_device *dev)
{
- return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+ struct ata_port *ap = dev->link->ap;
+ return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
static void ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
if (!ata_id_has_ncq(dev->id)) {
@@ -1817,8 +1903,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,
*/
int ata_dev_configure(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned int xfer_mask;
@@ -1844,6 +1930,11 @@ int ata_dev_configure(struct ata_device *dev)
if (rc)
return rc;
+ /* massage HPA, do it early as it might change IDENTIFY data */
+ rc = ata_hpa_resize(dev);
+ if (rc)
+ return rc;
+
/* print device capabilities */
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
@@ -1911,10 +2002,6 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
- if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) &&
- 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));
@@ -1963,7 +2050,9 @@ int ata_dev_configure(struct ata_device *dev)
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
- char *cdb_intr_string = "";
+ const char *cdb_intr_string = "";
+ const char *atapi_an_string = "";
+ u32 sntf;
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -1975,6 +2064,28 @@ int ata_dev_configure(struct ata_device *dev)
}
dev->cdb_len = (unsigned int) rc;
+ /* Enable ATAPI AN if both the host and device have
+ * the support. If PMP is attached, SNTF is required
+ * to enable ATAPI AN to discern between PHY status
+ * changed notifications and ATAPI ANs.
+ */
+ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+ (!ap->nr_pmp_links ||
+ sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
+ unsigned int err_mask;
+
+ /* issue SET feature command to turn this on */
+ err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
+ if (err_mask)
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to enable ATAPI AN "
+ "(err_mask=0x%x)\n", err_mask);
+ else {
+ dev->flags |= ATA_DFLAG_AN;
+ atapi_an_string = ", ATAPI AN";
+ }
+ }
+
if (ata_id_cdb_intr(dev->id)) {
dev->flags |= ATA_DFLAG_CDB_INTR;
cdb_intr_string = ", CDB intr";
@@ -1983,10 +2094,10 @@ int ata_dev_configure(struct ata_device *dev)
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s\n",
+ "ATAPI: %s, %s, max %s%s%s\n",
modelbuf, fwrevbuf,
ata_mode_string(xfer_mask),
- cdb_intr_string);
+ cdb_intr_string, atapi_an_string);
}
/* determine max_sectors */
@@ -2103,21 +2214,19 @@ int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
- int i, rc;
+ int rc;
struct ata_device *dev;
ata_port_probe(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- tries[i] = ATA_PROBE_MAX_TRIES;
+ ata_link_for_each_dev(dev, &ap->link)
+ tries[dev->devno] = ATA_PROBE_MAX_TRIES;
retry:
/* reset and determine device classes */
ap->ops->phy_reset(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, &ap->link) {
if (!(ap->flags & ATA_FLAG_DISABLED) &&
dev->class != ATA_DEV_UNKNOWN)
classes[dev->devno] = dev->class;
@@ -2132,18 +2241,16 @@ int ata_bus_probe(struct ata_port *ap)
/* after the reset the device state is PIO 0 and the controller
state is undefined. Record the mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->pio_mode = XFER_PIO_0;
/* read IDENTIFY page and configure devices. We have to do the identify
specific sequence bass-ackwards so that PDIAG- is released by
the slave device */
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- dev = &ap->device[i];
-
- if (tries[i])
- dev->class = classes[i];
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (tries[dev->devno])
+ dev->class = classes[dev->devno];
if (!ata_dev_enabled(dev))
continue;
@@ -2158,33 +2265,42 @@ int ata_bus_probe(struct ata_port *ap)
if (ap->ops->cable_detect)
ap->cbl = ap->ops->cable_detect(ap);
+ /* We may have SATA bridge glue hiding here irrespective of the
+ reported cable types and sensed types */
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (!ata_dev_enabled(dev))
+ continue;
+ /* SATA drives indicate we have a bridge. We don't know which
+ end of the link the bridge is which is a problem */
+ if (ata_id_is_sata(dev->id))
+ ap->cbl = ATA_CBL_SATA;
+ }
+
/* 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 */
- for(i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, &ap->link) {
if (!ata_dev_enabled(dev))
continue;
- ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
- ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
if (rc)
goto fail;
}
/* configure transfer mode */
- rc = ata_set_mode(ap, &dev);
+ rc = ata_set_mode(&ap->link, &dev);
if (rc)
goto fail;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, &ap->link)
+ if (ata_dev_enabled(dev))
return 0;
/* no device present, disable port */
ata_port_disable(ap);
- ap->ops->port_disable(ap);
return -ENODEV;
fail:
@@ -2204,7 +2320,7 @@ int ata_bus_probe(struct ata_port *ap)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(&ap->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2233,28 +2349,28 @@ void ata_port_probe(struct ata_port *ap)
/**
* sata_print_link_status - Print SATA link status
- * @ap: SATA port to printk link status about
+ * @link: SATA link to printk link status about
*
* This function prints link speed and status of a SATA link.
*
* LOCKING:
* None.
*/
-void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
- if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+ if (sata_scr_read(link, SCR_STATUS, &sstatus))
return;
- sata_scr_read(ap, SCR_CONTROL, &scontrol);
+ sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n",
sata_spd_string(tmp), sstatus, scontrol);
} else {
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link down (SStatus %X SControl %X)\n",
sstatus, scontrol);
}
@@ -2274,32 +2390,33 @@ void sata_print_link_status(struct ata_port *ap)
*/
void __sata_phy_reset(struct ata_port *ap)
{
- u32 sstatus;
+ struct ata_link *link = &ap->link;
unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus;
if (ap->flags & ATA_FLAG_SATA_RESET) {
/* issue phy wake/reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x301);
/* Couldn't find anything in SATA I/II specs, but
* AHCI-1.1 10.4.2 says at least 1 ms. */
mdelay(1);
}
/* phy wake/clear reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x300);
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* TODO: phy layer with polling, timeouts, etc. */
- if (!ata_port_offline(ap))
+ if (!ata_link_offline(link))
ata_port_probe(ap);
else
ata_port_disable(ap);
@@ -2344,8 +2461,8 @@ void sata_phy_reset(struct ata_port *ap)
struct ata_device *ata_dev_pair(struct ata_device *adev)
{
- struct ata_port *ap = adev->ap;
- struct ata_device *pair = &ap->device[1 - adev->devno];
+ struct ata_link *link = adev->link;
+ struct ata_device *pair = &link->device[1 - adev->devno];
if (!ata_dev_enabled(pair))
return NULL;
return pair;
@@ -2366,16 +2483,16 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
void ata_port_disable(struct ata_port *ap)
{
- ap->device[0].class = ATA_DEV_NONE;
- ap->device[1].class = ATA_DEV_NONE;
+ ap->link.device[0].class = ATA_DEV_NONE;
+ ap->link.device[1].class = ATA_DEV_NONE;
ap->flags |= ATA_FLAG_DISABLED;
}
/**
* sata_down_spd_limit - adjust SATA spd limit downward
- * @ap: Port to adjust SATA spd limit for
+ * @link: Link to adjust SATA spd limit for
*
- * Adjust SATA spd limit of @ap downward. Note that this
+ * Adjust SATA spd limit of @link downward. Note that this
* function only adjusts the limit. The change must be applied
* using sata_set_spd().
*
@@ -2385,24 +2502,24 @@ void ata_port_disable(struct ata_port *ap)
* RETURNS:
* 0 on success, negative errno on failure
*/
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
{
u32 sstatus, spd, mask;
int rc, highbit;
- if (!sata_scr_valid(ap))
+ if (!sata_scr_valid(link))
return -EOPNOTSUPP;
/* If SCR can be read, use it to determine the current SPD.
- * If not, use cached value in ap->sata_spd.
+ * If not, use cached value in link->sata_spd.
*/
- rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+ rc = sata_scr_read(link, SCR_STATUS, &sstatus);
if (rc == 0)
spd = (sstatus >> 4) & 0xf;
else
- spd = ap->sata_spd;
+ spd = link->sata_spd;
- mask = ap->sata_spd_limit;
+ mask = link->sata_spd_limit;
if (mask <= 1)
return -EINVAL;
@@ -2422,22 +2539,22 @@ int sata_down_spd_limit(struct ata_port *ap)
if (!mask)
return -EINVAL;
- ap->sata_spd_limit = mask;
+ link->sata_spd_limit = mask;
- ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+ ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
sata_spd_string(fls(mask)));
return 0;
}
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
{
u32 spd, limit;
- if (ap->sata_spd_limit == UINT_MAX)
+ if (link->sata_spd_limit == UINT_MAX)
limit = 0;
else
- limit = fls(ap->sata_spd_limit);
+ limit = fls(link->sata_spd_limit);
spd = (*scontrol >> 4) & 0xf;
*scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -2447,10 +2564,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
/**
* sata_set_spd_needed - is SATA spd configuration needed
- * @ap: Port in question
+ * @link: Link in question
*
* Test whether the spd limit in SControl matches
- * @ap->sata_spd_limit. This function is used to determine
+ * @link->sata_spd_limit. This function is used to determine
* whether hardreset is necessary to apply SATA spd
* configuration.
*
@@ -2460,21 +2577,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
* RETURNS:
* 1 if SATA spd configuration is needed, 0 otherwise.
*/
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
{
u32 scontrol;
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+ if (sata_scr_read(link, SCR_CONTROL, &scontrol))
return 0;
- return __sata_set_spd_needed(ap, &scontrol);
+ return __sata_set_spd_needed(link, &scontrol);
}
/**
* sata_set_spd - set SATA spd according to spd limit
- * @ap: Port to set SATA spd for
+ * @link: Link to set SATA spd for
*
- * Set SATA spd of @ap according to sata_spd_limit.
+ * Set SATA spd of @link according to sata_spd_limit.
*
* LOCKING:
* Inherited from caller.
@@ -2483,18 +2600,18 @@ int sata_set_spd_needed(struct ata_port *ap)
* 0 if spd doesn't need to be changed, 1 if spd has been
* changed. Negative errno if SCR registers are inaccessible.
*/
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
- if (!__sata_set_spd_needed(ap, &scontrol))
+ if (!__sata_set_spd_needed(link, &scontrol))
return 0;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
return 1;
@@ -2749,7 +2866,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
static int ata_dev_set_mode(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
unsigned int err_mask;
int rc;
@@ -2761,7 +2878,11 @@ static int ata_dev_set_mode(struct ata_device *dev)
/* Old CFA may refuse this command, which is just fine */
if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
err_mask &= ~AC_ERR_DEV;
-
+ /* Some very old devices and some bad newer ones fail any kind of
+ SET_XFERMODE request but support PIO0-2 timings and no IORDY */
+ if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
+ dev->pio_mode <= XFER_PIO_2)
+ err_mask &= ~AC_ERR_DEV;
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
"(err_mask=0x%x)\n", err_mask);
@@ -2769,7 +2890,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
ehc->i.flags |= ATA_EHI_POST_SETMODE;
- rc = ata_dev_revalidate(dev, 0);
+ rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
if (rc)
return rc;
@@ -2784,7 +2905,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
/**
* ata_do_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Standard implementation of the function used to tune and set
@@ -2799,25 +2920,36 @@ static int ata_dev_set_mode(struct ata_device *dev)
* 0 on success, negative errno otherwise
*/
-int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
struct ata_device *dev;
- int i, rc = 0, used_dma = 0, found = 0;
-
+ int rc = 0, used_dma = 0, found = 0;
/* step 1: calculate xfer_mask */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ ata_link_for_each_dev(dev, link) {
unsigned int pio_mask, dma_mask;
-
- dev = &ap->device[i];
+ unsigned int mode_mask;
if (!ata_dev_enabled(dev))
continue;
+ mode_mask = ATA_DMA_MASK_ATA;
+ if (dev->class == ATA_DEV_ATAPI)
+ mode_mask = ATA_DMA_MASK_ATAPI;
+ else if (ata_id_is_cfa(dev->id))
+ mode_mask = ATA_DMA_MASK_CFA;
+
ata_dev_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+ if (libata_dma_mask & mode_mask)
+ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+ else
+ dma_mask = 0;
+
dev->pio_mode = ata_xfer_mask2mode(pio_mask);
dev->dma_mode = ata_xfer_mask2mode(dma_mask);
@@ -2829,8 +2961,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
goto out;
/* step 2: always set host PIO timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
continue;
@@ -2847,9 +2978,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 3: set host DMA timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev) || !dev->dma_mode)
continue;
@@ -2860,9 +2989,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 4: update devices' xfer mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
/* don't update suspended devices' xfer mode */
if (!ata_dev_enabled(dev))
continue;
@@ -2886,7 +3013,7 @@ int ata_do_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
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
@@ -2899,12 +3026,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
+
/* 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);
+ return ap->ops->set_mode(link, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
/**
@@ -3007,7 +3136,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
if (!(status & ATA_BUSY))
return 0;
- if (!ata_port_online(ap) && status == 0xff)
+ if (!ata_link_online(&ap->link) && status == 0xff)
return -ENODEV;
if (time_after(now, deadline))
return -EBUSY;
@@ -3088,6 +3217,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct ata_device *dev;
+ int i = 0;
DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
@@ -3098,6 +3229,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
+ /* If we issued an SRST then an ATA drive (not ATAPI)
+ * may have changed configuration and be in PIO0 timing. If
+ * we did a hard reset (or are coming from power on) this is
+ * true for ATA or ATAPI. Until we've set a suitable controller
+ * mode we should not touch the bus as we may be talking too fast.
+ */
+
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->pio_mode = XFER_PIO_0;
+
+ /* If the controller has a pio mode setup function then use
+ it to set the chipset to rights. Don't touch the DMA setup
+ as that will be dealt with when revalidating */
+ if (ap->ops->set_piomode) {
+ ata_link_for_each_dev(dev, &ap->link)
+ if (devmask & (1 << i++))
+ ap->ops->set_piomode(ap, dev);
+ }
+
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
* ATAPI devices in Hale Landis's ATADRVR, for the period of time
@@ -3142,6 +3292,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
void ata_bus_reset(struct ata_port *ap)
{
+ struct ata_device *device = ap->link.device;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
u8 err;
@@ -3177,19 +3328,19 @@ void ata_bus_reset(struct ata_port *ap)
/*
* determine by signature whether we have ATA or ATAPI devices
*/
- ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+ device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
if ((slave_possible) && (err != 0x81))
- ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+ device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
/* is double-select really necessary? */
- if (ap->device[1].class != ATA_DEV_NONE)
+ if (device[1].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
- if (ap->device[0].class != ATA_DEV_NONE)
+ if (device[0].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 0);
/* if no devices were detected, disable this port */
- if ((ap->device[0].class == ATA_DEV_NONE) &&
- (ap->device[1].class == ATA_DEV_NONE))
+ if ((device[0].class == ATA_DEV_NONE) &&
+ (device[1].class == ATA_DEV_NONE))
goto err_out;
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -3202,18 +3353,18 @@ void ata_bus_reset(struct ata_port *ap)
err_out:
ata_port_printk(ap, KERN_ERR, "disabling port\n");
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
DPRINTK("EXIT\n");
}
/**
- * sata_phy_debounce - debounce SATA phy status
- * @ap: ATA port to debounce SATA phy status for
+ * sata_link_debounce - debounce SATA phy status
+ * @link: ATA link to debounce SATA phy status for
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Make sure SStatus of @ap reaches stable state, determined by
+* Make sure SStatus of @link reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because DET gets stuck at 1 on
@@ -3229,8 +3380,8 @@ err_out:
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
unsigned long interval_msec = params[0];
unsigned long duration = msecs_to_jiffies(params[1]);
@@ -3242,7 +3393,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
if (time_before(t, deadline))
deadline = t;
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3251,7 +3402,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
while (1) {
msleep(interval_msec);
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3277,12 +3428,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
}
/**
- * sata_phy_resume - resume SATA phy
- * @ap: ATA port to resume SATA phy for
+ * sata_link_resume - resume SATA link
+ * @link: ATA link to resume SATA
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Resume SATA phy of @ap and debounce it.
+ * Resume SATA phy @link and debounce it.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3290,18 +3441,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
scontrol = (scontrol & 0x0f0) | 0x300;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
/* Some PHYs react badly if SStatus is pounded immediately
@@ -3309,15 +3460,15 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
*/
msleep(200);
- return sata_phy_debounce(ap, params, deadline);
+ return sata_link_debounce(link, params, deadline);
}
/**
* ata_std_prereset - prepare for reset
- * @ap: ATA port to be reset
+ * @link: ATA link to be reset
* @deadline: deadline jiffies for the operation
*
- * @ap is about to be reset. Initialize it. Failure from
+ * @link is about to be reset. Initialize it. Failure from
* prereset makes libata abort whole reset sequence and give up
* that port, so prereset should be best-effort. It does its
* best to prepare for reset sequence but if things go wrong, it
@@ -3329,37 +3480,44 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
+int ata_std_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
/* handle link resume */
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
- (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* Some PMPs don't work with only SRST, force hardreset if PMP
+ * is supported.
+ */
+ if (ap->flags & ATA_FLAG_PMP)
ehc->i.action |= ATA_EH_HARDRESET;
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- /* if SATA, resume phy */
+ /* if SATA, resume link */
if (ap->flags & ATA_FLAG_SATA) {
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
/* whine about phy resume failure but proceed */
if (rc && rc != -EOPNOTSUPP)
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
}
/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+ if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) {
rc = ata_wait_ready(ap, deadline);
if (rc && rc != -ENODEV) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"(errno=%d), forcing hardreset\n", rc);
ehc->i.action |= ATA_EH_HARDRESET;
}
@@ -3370,7 +3528,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
/**
* ata_std_softreset - reset host port via ATA SRST
- * @ap: port to reset
+ * @link: ATA link to reset
* @classes: resulting classes of attached devices
* @deadline: deadline jiffies for the operation
*
@@ -3382,9 +3540,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+int ata_std_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0;
int rc;
@@ -3392,7 +3551,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -3410,15 +3569,17 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("about to softreset, devmask=%x\n", devmask);
rc = ata_bus_softreset(ap, devmask, deadline);
/* if link is occupied, -ENODEV too is an error */
- if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
return rc;
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&link->device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&link->device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -3426,12 +3587,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
}
/**
- * sata_port_hardreset - reset port via SATA phy reset
- * @ap: port to reset
+ * sata_link_hardreset - reset link via SATA phy reset
+ * @link: link to reset
* @timing: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * SATA phy-reset host port using DET bits of SControl register.
+ * SATA phy-reset @link using DET bits of SControl register.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3439,7 +3600,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
unsigned long deadline)
{
u32 scontrol;
@@ -3447,30 +3608,30 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
DPRINTK("ENTER\n");
- if (sata_set_spd_needed(ap)) {
+ if (sata_set_spd_needed(link)) {
/* SATA spec says nothing about how to reconfigure
* spd. To be on the safe side, turn off phy during
* reconfiguration. This works for at least ICH7 AHCI
* and Sil3124.
*/
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x304;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
goto out;
- sata_set_spd(ap);
+ sata_set_spd(link);
}
/* issue phy wake/reset */
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x301;
- if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
goto out;
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -3478,8 +3639,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
*/
msleep(1);
- /* bring phy back */
- rc = sata_phy_resume(ap, timing, deadline);
+ /* bring link back */
+ rc = sata_link_resume(link, timing, deadline);
out:
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
@@ -3487,7 +3648,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
/**
* sata_std_hardreset - reset host port via SATA phy reset
- * @ap: port to reset
+ * @link: link to reset
* @class: resulting class of attached device
* @deadline: deadline jiffies for the operation
*
@@ -3500,24 +3661,25 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+int sata_std_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ struct ata_port *ap = link->ap;
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
int rc;
DPRINTK("ENTER\n");
/* do hardreset */
- rc = sata_port_hardreset(ap, timing, deadline);
+ rc = sata_link_hardreset(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
/* TODO: phy layer with polling, timeouts, etc. */
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
*class = ATA_DEV_NONE;
DPRINTK("EXIT, link offline\n");
return 0;
@@ -3526,17 +3688,27 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
/* wait a while before checking status, see SRST for more info */
msleep(150);
+ /* If PMP is supported, we have to do follow-up SRST. Note
+ * that some PMPs don't send D2H Reg FIS after hardreset at
+ * all if the first port is empty. Wait for it just for a
+ * second and request follow-up SRST.
+ */
+ if (ap->flags & ATA_FLAG_PMP) {
+ ata_wait_ready(ap, jiffies + HZ);
+ return -EAGAIN;
+ }
+
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
ap->ops->dev_select(ap, 0); /* probably unnecessary */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(link->device, 1, NULL);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
@@ -3544,7 +3716,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
/**
* ata_std_postreset - standard postreset callback
- * @ap: the target ata_port
+ * @link: the target ata_link
* @classes: classes of attached devices
*
* This function is invoked after a successful reset. Note that
@@ -3554,18 +3726,19 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
* LOCKING:
* Kernel thread context (may sleep)
*/
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serror;
DPRINTK("ENTER\n");
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
- sata_scr_write(ap, SCR_ERROR, serror);
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -3652,7 +3825,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
{
unsigned int class = dev->class;
- u16 *id = (void *)dev->ap->sector_buf;
+ u16 *id = (void *)dev->link->ap->sector_buf;
int rc;
/* read ID data */
@@ -3671,6 +3844,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
/**
* ata_dev_revalidate - Revalidate ATA device
* @dev: device to revalidate
+ * @new_class: new class code
* @readid_flags: read ID flags
*
* Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3682,7 +3856,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
int rc;
@@ -3690,6 +3865,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
if (!ata_dev_enabled(dev))
return -ENODEV;
+ /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+ if (ata_class_enabled(new_class) &&
+ new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+ dev->class, new_class);
+ rc = -ENODEV;
+ goto fail;
+ }
+
/* re-read ID */
rc = ata_dev_reread_id(dev, readid_flags);
if (rc)
@@ -3763,6 +3947,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */
{ "IOMEGA ZIP 250 ATAPI Floppy",
NULL, ATA_HORKAGE_NODMA },
+ /* Odd clown on sil3726/4726 PMPs */
+ { "Config Disk", NULL, ATA_HORKAGE_NODMA |
+ ATA_HORKAGE_SKIP_PM },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -3775,16 +3962,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* http://thread.gmane.org/gmane.linux.ide/14907 */
{ "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* NCQ is broken */
- { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ },
- { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, },
- { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ },
{ "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
- { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
- ATA_HORKAGE_NONCQ },
- /* NCQ hard hangs device under heavier load, needs hard power cycle */
- { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ },
+ { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
+
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
@@ -3793,11 +3976,17 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Drives which do spurious command completion */
{ "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, },
{ "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, },
+ { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, },
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
+ { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
+ { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, },
{ "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
- { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.CCD", ATA_HORKAGE_NONCQ, },
+ { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, },
+ { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, },
{ "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, },
/* devices which puke on READ_NATIVE_MAX */
@@ -3806,10 +3995,37 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
{ "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA },
+ /* Devices which report 1 sector over size HPA */
+ { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
+ { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
+
/* End Marker */
{ }
};
+int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+{
+ const char *p;
+ int len;
+
+ /*
+ * check for trailing wildcard: *\0
+ */
+ p = strchr(patt, wildchar);
+ if (p && ((*(p + 1)) == 0))
+ len = p - patt;
+ else {
+ len = strlen(name);
+ if (!len) {
+ if (!*patt)
+ return 0;
+ return -1;
+ }
+ }
+
+ return strncmp(patt, name, len);
+}
+
static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -3820,10 +4036,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strcmp(ad->model_num, model_num)) {
+ if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strcmp(ad->model_rev, model_rev))
+ if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
return ad->horkage;
}
ad++;
@@ -3837,7 +4053,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
* DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
* if the LLDD handles only interrupts in the HSM_ST_LAST state.
*/
- if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
(dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
@@ -3857,7 +4073,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
*/
static void ata_dev_xfermask(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
struct ata_host *host = ap->host;
unsigned long xfer_mask;
@@ -3955,7 +4172,43 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
tf.protocol = ATA_PROT_NODATA;
tf.nsect = dev->xfer_mode;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES
+ * @dev: Device to which command will be sent
+ * @enable: Whether to enable or disable the feature
+ *
+ * Issue SET FEATURES - SATA FEATURES command to device @dev
+ * on port @ap with sector count set to indicate Asynchronous
+ * Notification feature
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ /* set up set-features taskfile */
+ DPRINTK("set features - SATA features\n");
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = enable;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = SATA_AN;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -3993,7 +4246,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
tf.nsect = sectors;
tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
/* A clean abort indicates an original or just out of spec drive
and we should continue as we issue the setup based on the
drive reported working geometry */
@@ -4207,6 +4460,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
}
/**
+ * ata_std_qc_defer - Check whether a qc needs to be deferred
+ * @qc: ATA command in question
+ *
+ * Non-NCQ commands cannot run with any other command, NCQ or
+ * not. As upper layer only knows the queue depth, we are
+ * responsible for maintaining exclusion. This function checks
+ * whether a new command @qc can be issued.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(link->active_tag) && !link->sactive)
+ return 0;
+ }
+
+ return ATA_DEFER_LINK;
+}
+
+/**
* ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared
*
@@ -4482,7 +4765,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
@@ -4611,6 +4894,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
ata_pio_sector(qc);
} else
ata_pio_sector(qc);
+
+ ata_altstatus(qc->ap); /* flush */
}
/**
@@ -4785,6 +5070,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
__atapi_pio_bytes(qc, bytes);
+ ata_altstatus(ap); /* flush */
return;
@@ -4956,7 +5242,6 @@ fsm_start:
*/
ap->hsm_task_state = HSM_ST;
ata_pio_sectors(qc);
- ata_altstatus(ap); /* flush */
} else
/* send CDB */
atapi_send_cdb(ap, qc);
@@ -5037,7 +5322,6 @@ fsm_start:
if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
ata_pio_sectors(qc);
- ata_altstatus(ap);
status = ata_wait_idle(ap);
}
@@ -5057,13 +5341,11 @@ fsm_start:
if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
/* all data read */
- ata_altstatus(ap);
status = ata_wait_idle(ap);
goto fsm_start;
}
}
- ata_altstatus(ap); /* flush */
poll_next = 1;
break;
@@ -5188,7 +5470,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
qc = ata_qc_new(ap);
@@ -5231,6 +5513,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -5239,10 +5522,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
- ap->sactive &= ~(1 << qc->tag);
- else
- ap->active_tag = ATA_TAG_POISON;
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ link->sactive &= ~(1 << qc->tag);
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
+ link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+ ap->excl_link == link))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -5411,19 +5703,25 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
void ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
/* Make sure only one non-NCQ command is outstanding. The
* check is skipped for old EH because it reuses active qc to
* request ATAPI sense.
*/
- WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
if (qc->tf.protocol == ATA_PROT_NCQ) {
- WARN_ON(ap->sactive & (1 << qc->tag));
- ap->sactive |= 1 << qc->tag;
+ WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
+ link->sactive |= 1 << qc->tag;
} else {
- WARN_ON(ap->sactive);
- ap->active_tag = qc->tag;
+ WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
+ link->active_tag = qc->tag;
}
qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -5606,7 +5904,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
@@ -5680,7 +5978,8 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
@@ -5721,7 +6020,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
@@ -5735,9 +6034,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
/**
* sata_scr_valid - test whether SCRs are accessible
- * @ap: ATA port to test SCR accessibility for
+ * @link: ATA link to test SCR accessibility for
*
- * Test whether SCRs are accessible for @ap.
+ * Test whether SCRs are accessible for @link.
*
* LOCKING:
* None.
@@ -5745,60 +6044,74 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
* RETURNS:
* 1 if SCRs are accessible, 0 otherwise.
*/
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
{
+ struct ata_port *ap = link->ap;
+
return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
}
/**
* sata_scr_read - read SCR register of the specified port
- * @ap: ATA port to read SCR for
+ * @link: ATA link to read SCR for
* @reg: SCR to read
* @val: Place to store read value
*
- * Read SCR register @reg of @ap into *@val. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Read SCR register @reg of @link into *@val. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{
- if (sata_scr_valid(ap))
- return ap->ops->scr_read(ap, reg, val);
- return -EOPNOTSUPP;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_read(ap, reg, val);
+ return -EOPNOTSUPP;
+ }
+
+ return sata_pmp_scr_read(link, reg, val);
}
/**
* sata_scr_write - write SCR register of the specified port
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
- * Write @val to SCR register @reg of @ap. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Write @val to SCR register @reg of @link. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
{
- if (sata_scr_valid(ap))
- return ap->ops->scr_write(ap, reg, val);
- return -EOPNOTSUPP;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_write(ap, reg, val);
+ return -EOPNOTSUPP;
+ }
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
* sata_scr_write_flush - write SCR register of the specified port and flush
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
@@ -5806,31 +6119,36 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
* function performs flush after writing to the register.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{
- int rc;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+ int rc;
- if (sata_scr_valid(ap)) {
- rc = ap->ops->scr_write(ap, reg, val);
- if (rc == 0)
- rc = ap->ops->scr_read(ap, reg, &val);
- return rc;
+ if (sata_scr_valid(link)) {
+ rc = ap->ops->scr_write(ap, reg, val);
+ if (rc == 0)
+ rc = ap->ops->scr_read(ap, reg, &val);
+ return rc;
+ }
+ return -EOPNOTSUPP;
}
- return -EOPNOTSUPP;
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
- * ata_port_online - test whether the given port is online
- * @ap: ATA port to test
+ * ata_link_online - test whether the given link is online
+ * @link: ATA link to test
*
- * Test whether @ap is online. Note that this function returns 0
- * if online status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is online. Note that this function returns
+ * 0 if online status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5838,22 +6156,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
* RETURNS:
* 1 if the port online status is available and online.
*/
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) == 0x3)
return 1;
return 0;
}
/**
- * ata_port_offline - test whether the given port is offline
- * @ap: ATA port to test
+ * ata_link_offline - test whether the given link is offline
+ * @link: ATA link to test
*
- * Test whether @ap is offline. Note that this function returns
- * 0 if offline status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is offline. Note that this function
+ * returns 0 if offline status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5861,11 +6180,12 @@ int ata_port_online(struct ata_port *ap)
* RETURNS:
* 1 if the port offline status is available and offline.
*/
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) != 0x3)
return 1;
return 0;
}
@@ -5883,6 +6203,10 @@ int ata_flush_cache(struct ata_device *dev)
else
cmd = ATA_CMD_FLUSH;
+ /* This is wrong. On a failed flush we get back the LBA of the lost
+ sector and we should (assuming it wasn't aborted as unknown) issue
+ a further flush command to continue the writeback until it
+ does not error */
err_mask = ata_do_simple_cmd(dev, cmd);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
@@ -5902,6 +6226,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
@@ -5921,8 +6246,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
}
ap->pflags |= ATA_PFLAG_PM_PENDING;
- ap->eh_info.action |= action;
- ap->eh_info.flags |= ehi_flags;
+ __ata_port_for_each_link(link, ap) {
+ link->eh_info.action |= action;
+ link->eh_info.flags |= ehi_flags;
+ }
ata_port_schedule_eh(ap);
@@ -6026,12 +6353,13 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
/* SATA spd limit is bound to the first device */
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
- ap->sata_spd = 0;
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+ link->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
@@ -6050,6 +6378,70 @@ void ata_dev_init(struct ata_device *dev)
}
/**
+ * ata_link_init - Initialize an ata_link structure
+ * @ap: ATA port link is attached to
+ * @link: Link structure to initialize
+ * @pmp: Port multiplier port number
+ *
+ * Initialize @link.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+{
+ int i;
+
+ /* clear everything except for devices */
+ memset(link, 0, offsetof(struct ata_link, device[0]));
+
+ link->ap = ap;
+ link->pmp = pmp;
+ link->active_tag = ATA_TAG_POISON;
+ link->hw_sata_spd_limit = UINT_MAX;
+
+ /* can't use iterator, ap isn't initialized yet */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &link->device[i];
+
+ dev->link = link;
+ dev->devno = dev - link->device;
+ ata_dev_init(dev);
+ }
+}
+
+/**
+ * sata_link_init_spd - Initialize link->sata_spd_limit
+ * @link: Link to configure sata_spd_limit for
+ *
+ * Initialize @link->[hw_]sata_spd_limit to the currently
+ * configured value.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_link_init_spd(struct ata_link *link)
+{
+ u32 scontrol, spd;
+ int rc;
+
+ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ if (rc)
+ return rc;
+
+ spd = (scontrol >> 4) & 0xf;
+ if (spd)
+ link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+
+ return 0;
+}
+
+/**
* ata_port_alloc - allocate and initialize basic ATA port resources
* @host: ATA host this allocated port belongs to
*
@@ -6064,7 +6456,6 @@ void ata_dev_init(struct ata_device *dev)
struct ata_port *ata_port_alloc(struct ata_host *host)
{
struct ata_port *ap;
- unsigned int i;
DPRINTK("ENTER\n");
@@ -6079,9 +6470,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->ctl = ATA_DEVCTL_OBS;
ap->host = host;
ap->dev = host->dev;
-
- ap->hw_sata_spd_limit = UINT_MAX;
- ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
#if defined(ATA_VERBOSE_DEBUG)
@@ -6104,12 +6492,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->cbl = ATA_CBL_NONE;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- dev->ap = ap;
- dev->devno = i;
- ata_dev_init(dev);
- }
+ ata_link_init(ap, &ap->link, 0);
#ifdef ATA_IRQ_TRAP
ap->stats.unhandled_irq = 1;
@@ -6145,6 +6528,7 @@ static void ata_host_release(struct device *gendev, void *res)
if (ap->scsi_host)
scsi_host_put(ap->scsi_host);
+ kfree(ap->pmp_link);
kfree(ap);
host->ports[i] = NULL;
}
@@ -6255,6 +6639,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
ap->mwdma_mask = pi->mwdma_mask;
ap->udma_mask = pi->udma_mask;
ap->flags |= pi->flags;
+ ap->link.flags |= pi->link_flags;
ap->ops = pi->port_ops;
if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
@@ -6390,8 +6775,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- int irq_line;
- u32 scontrol;
unsigned long xfer_mask;
/* set SATA cable type if still unset */
@@ -6399,32 +6782,20 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
ap->cbl = ATA_CBL_SATA;
/* init sata_spd_limit to the current value */
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
- int spd = (scontrol >> 4) & 0xf;
- if (spd)
- 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 */
- irq_line = host->irq;
- if (i == 1 && host->irq2)
- irq_line = host->irq2;
+ sata_link_init_spd(&ap->link);
+ /* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
ap->udma_mask);
- /* print per-port info to dmesg */
- 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",
+ if (!ata_port_is_dummy(ap)) {
+ ata_port_printk(ap, KERN_INFO,
+ "%cATA max %s %s\n",
(ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
ata_mode_string(xfer_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- irq_line);
- else
+ ap->link.eh_info.desc);
+ ata_ehi_clear_desc(&ap->link.eh_info);
+ } else
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
}
@@ -6436,7 +6807,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* probe */
if (ap->ops->error_handler) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -6444,7 +6815,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->probe_mask =
+ (1 << ata_link_max_devices(&ap->link)) - 1;
ehi->action |= ATA_EH_SOFTRESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
@@ -6506,7 +6878,7 @@ 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;
+ int i, rc;
rc = ata_host_start(host);
if (rc)
@@ -6517,8 +6889,8 @@ int ata_host_activate(struct ata_host *host, int irq,
if (rc)
return rc;
- /* Used to print device info at probe */
- host->irq = irq;
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_desc(host->ports[i], "irq %d", irq);
rc = ata_host_register(host, sht);
/* if failed, just free the IRQ and leave ports alone */
@@ -6542,7 +6914,8 @@ int ata_host_activate(struct ata_host *host, int irq,
void ata_port_detach(struct ata_port *ap)
{
unsigned long flags;
- int i;
+ struct ata_link *link;
+ struct ata_device *dev;
if (!ap->ops->error_handler)
goto skip_eh;
@@ -6559,8 +6932,10 @@ void ata_port_detach(struct ata_port *ap)
*/
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link)
+ ata_dev_disable(dev);
+ }
spin_unlock_irqrestore(ap->lock, flags);
@@ -6639,7 +7014,7 @@ void ata_std_ports(struct ata_ioports *ioaddr)
*/
void ata_pci_remove_one(struct pci_dev *pdev)
{
- struct device *dev = pci_dev_to_dev(pdev);
+ struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
@@ -6847,7 +7222,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
}
const struct ata_port_operations ata_dummy_port_ops = {
- .port_disable = ata_port_disable,
.check_status = ata_dummy_check_status,
.check_altstatus = ata_dummy_check_status,
.dev_select = ata_noop_dev_select,
@@ -6909,6 +7283,7 @@ 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_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
@@ -6925,14 +7300,14 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(ata_dev_disable);
EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_port_hardreset);
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_dev_classify);
@@ -6953,8 +7328,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_host_suspend);
EXPORT_SYMBOL_GPL(ata_host_resume);
@@ -6985,22 +7360,31 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
+EXPORT_SYMBOL_GPL(ata_port_desc);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
+#endif /* CONFIG_PCI */
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
EXPORT_SYMBOL_GPL(ata_port_abort);
EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_irq_on);
-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);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ac6ceed4bb6..2eaa39fc65d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
*/
#include <linux/kernel.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
@@ -74,7 +75,6 @@ static const unsigned long ata_eh_reset_timeouts[] = {
};
static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi)
ehi->desc_len = 0;
}
+/**
+ * ata_port_desc - append port description
+ * @ap: target ATA port
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to port
+ * description. If port description is not empty, " " is added
+ * in-between. This function is to be used while initializing
+ * ata_host. The description is printed on host registration.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+{
+ va_list args;
+
+ WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));
+
+ if (ap->link.eh_info.desc_len)
+ __ata_ehi_push_desc(&ap->link.eh_info, " ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
+ va_end(args);
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ * ata_port_pbar_desc - append PCI BAR description
+ * @ap: target ATA port
+ * @bar: target PCI BAR
+ * @offset: offset into PCI BAR
+ * @name: name of the area
+ *
+ * If @offset is negative, this function formats a string which
+ * contains the name, address, size and type of the BAR and
+ * appends it to the port description. If @offset is zero or
+ * positive, only name and offsetted address is appended.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+ const char *name)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ char *type = "";
+ unsigned long long start, len;
+
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+ type = "m";
+ else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+ type = "i";
+
+ start = (unsigned long long)pci_resource_start(pdev, bar);
+ len = (unsigned long long)pci_resource_len(pdev, bar);
+
+ if (offset < 0)
+ ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
+ else
+ ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+}
+
+#endif /* CONFIG_PCI */
+
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
{
@@ -195,28 +262,29 @@ static int ata_ering_map(struct ata_ering *ering,
static unsigned int ata_eh_dev_action(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
return ehc->i.action | ehc->i.dev_action[dev->devno];
}
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
struct ata_eh_info *ehi, unsigned int action)
{
- int i;
+ struct ata_device *tdev;
if (!dev) {
ehi->action &= ~action;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] &= ~action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] &= ~action;
} else {
/* doesn't make sense for port-wide EH actions */
WARN_ON(!(action & ATA_EH_PERDEV_MASK));
/* break ehi->action into ehi->dev_action */
if (ehi->action & action) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] |= ehi->action & action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] |=
+ ehi->action & action;
ehi->action &= ~action;
}
@@ -261,7 +329,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
ret = EH_HANDLED;
spin_lock_irqsave(ap->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc) {
WARN_ON(qc->scsicmd != cmd);
qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -290,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+ int i;
unsigned long flags;
DPRINTK("ENTER\n");
@@ -356,12 +424,17 @@ void ata_scsi_error(struct Scsi_Host *host)
__ata_port_freeze(ap);
spin_unlock_irqrestore(ap->lock, flags);
+
+ /* initialize eh_tries */
+ ap->eh_tries = ATA_EH_MAX_TRIES;
} else
spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ struct ata_link *link;
+
/* kill fast drain timer */
del_timer_sync(&ap->fastdrain_timer);
@@ -371,12 +444,15 @@ void ata_scsi_error(struct Scsi_Host *host)
/* fetch & clear EH info */
spin_lock_irqsave(ap->lock, flags);
- memset(&ap->eh_context, 0, sizeof(ap->eh_context));
- ap->eh_context.i = ap->eh_info;
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap) {
+ memset(&link->eh_context, 0, sizeof(link->eh_context));
+ link->eh_context.i = link->eh_info;
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
+ }
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -396,20 +472,18 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_lock_irqsave(ap->lock, flags);
if (ap->pflags & ATA_PFLAG_EH_PENDING) {
- if (--repeat_cnt) {
- ata_port_printk(ap, KERN_INFO,
- "EH pending after completion, "
- "repeating EH (cnt=%d)\n", repeat_cnt);
+ if (--ap->eh_tries) {
spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
- "tries, giving up\n", ATA_EH_MAX_REPEAT);
+ "tries, giving up\n", ATA_EH_MAX_TRIES);
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
}
/* this run is complete, make sure EH info is clear */
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap)
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
/* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
@@ -420,7 +494,7 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_unlock_irqrestore(ap->lock, flags);
} else {
- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
ap->ops->eng_timeout(ap);
}
@@ -575,7 +649,7 @@ void ata_eng_timeout(struct ata_port *ap)
{
DPRINTK("ENTER\n");
- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
DPRINTK("EXIT\n");
}
@@ -718,19 +792,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
DPRINTK("port EH scheduled\n");
}
-/**
- * ata_port_abort - abort all qc's on the port
- * @ap: ATA port to abort qc's for
- *
- * Abort all active qc's of @ap and schedule EH.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
int tag, nr_aborted = 0;
@@ -742,7 +804,7 @@ int ata_port_abort(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
- if (qc) {
+ if (qc && (!link || qc->dev->link == link)) {
qc->flags |= ATA_QCFLAG_FAILED;
ata_qc_complete(qc);
nr_aborted++;
@@ -756,6 +818,40 @@ int ata_port_abort(struct ata_port *ap)
}
/**
+ * ata_link_abort - abort all qc's on the link
+ * @link: ATA link to abort qc's for
+ *
+ * Abort all active qc's active on @link and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+ return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ * ata_port_abort - abort all qc's on the port
+ * @ap: ATA port to abort qc's for
+ *
+ * Abort all active qc's of @ap and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+ return ata_do_link_abort(ap, NULL);
+}
+
+/**
* __ata_port_freeze - freeze port
* @ap: ATA port to freeze
*
@@ -810,6 +906,79 @@ int ata_port_freeze(struct ata_port *ap)
}
/**
+ * sata_async_notification - SATA async notification handler
+ * @ap: ATA port where async notification is received
+ *
+ * Handler to be called when async notification via SDB FIS is
+ * received. This function schedules EH if necessary.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+ u32 sntf;
+ int rc;
+
+ if (!(ap->flags & ATA_FLAG_AN))
+ return 0;
+
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ if (!ap->nr_pmp_links || rc) {
+ /* PMP is not attached or SNTF is not available */
+ if (!ap->nr_pmp_links) {
+ /* PMP is not attached. Check whether ATAPI
+ * AN is configured. If so, notify media
+ * change.
+ */
+ struct ata_device *dev = ap->link.device;
+
+ if ((dev->class == ATA_DEV_ATAPI) &&
+ (dev->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(dev);
+ return 0;
+ } else {
+ /* PMP is attached but SNTF is not available.
+ * ATAPI async media change notification is
+ * not used. The PMP must be reporting PHY
+ * status change, schedule EH.
+ */
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ } else {
+ /* PMP is attached and SNTF is available */
+ struct ata_link *link;
+
+ /* check and notify ATAPI AN */
+ ata_port_for_each_link(link, ap) {
+ if (!(sntf & (1 << link->pmp)))
+ continue;
+
+ if ((link->device->class == ATA_DEV_ATAPI) &&
+ (link->device->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(link->device);
+ }
+
+ /* If PMP is reporting that PHY status of some
+ * downstream ports has changed, schedule EH.
+ */
+ if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+
+ return 0;
+ }
+}
+
+/**
* ata_eh_freeze_port - EH helper to freeze port
* @ap: ATA port to freeze
*
@@ -920,9 +1089,10 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
ata_dev_disable(dev);
@@ -937,31 +1107,32 @@ static void ata_eh_detach_dev(struct ata_device *dev)
}
/* clear per-dev EH actions */
- ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
- ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
spin_unlock_irqrestore(ap->lock, flags);
}
/**
* ata_eh_about_to_do - about to perform eh_action
- * @ap: target ATA port
+ * @link: target ATA link
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action about to be performed
*
* Called just before performing EH actions to clear related bits
- * in @ap->eh_info such that eh actions are not unnecessarily
+ * in @link->eh_info such that eh actions are not unnecessarily
* repeated.
*
* LOCKING:
* None.
*/
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_port *ap = link->ap;
+ struct ata_eh_info *ehi = &link->eh_info;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned long flags;
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags);
@@ -978,7 +1149,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, ehi, action);
+ ata_eh_clear_action(link, dev, ehi, action);
if (!(ehc->i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -988,26 +1159,28 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
/**
* ata_eh_done - EH action complete
- * @ap: target ATA port
+* @ap: target ATA port
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action just completed
*
* Called right after performing EH actions to clear related bits
- * in @ap->eh_context.
+ * in @link->eh_context.
*
* LOCKING:
* None.
*/
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_eh_context *ehc = &link->eh_context;
+
/* if reset is complete, clear all reset actions & reset modifier */
if (action & ATA_EH_RESET_MASK) {
action |= ATA_EH_RESET_MASK;
- ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, &ap->eh_context.i, action);
+ ata_eh_clear_action(link, dev, &ehc->i, action);
}
/**
@@ -1077,7 +1250,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
tf.protocol = ATA_PROT_PIO;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- buf, sectors * ATA_SECT_SIZE);
+ buf, sectors * ATA_SECT_SIZE, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -1101,7 +1274,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
static int ata_eh_read_log_10h(struct ata_device *dev,
int *tag, struct ata_taskfile *tf)
{
- u8 *buf = dev->ap->sector_buf;
+ u8 *buf = dev->link->ap->sector_buf;
unsigned int err_mask;
u8 csum;
int i;
@@ -1155,7 +1328,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
{
struct ata_device *dev = qc->dev;
unsigned char *sense_buf = qc->scsicmd->sense_buffer;
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
u8 cdb[ATAPI_CDB_LEN];
@@ -1191,12 +1364,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
}
return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
- sense_buf, SCSI_SENSE_BUFFERSIZE);
+ sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
}
/**
* ata_eh_analyze_serror - analyze SError for a failed port
- * @ap: ATA port to analyze SError for
+ * @link: ATA link to analyze SError for
*
* Analyze SError if available and further determine cause of
* failure.
@@ -1204,11 +1377,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
u32 serror = ehc->i.serror;
unsigned int err_mask = 0, action = 0;
+ u32 hotplug_mask;
if (serror & SERR_PERSISTENT) {
err_mask |= AC_ERR_ATA_BUS;
@@ -1227,7 +1401,20 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_HARDRESET;
}
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+ /* Determine whether a hotplug event has occurred. Both
+ * SError.N/X are considered hotplug events for enabled or
+ * host links. For disabled PMP links, only N bit is
+ * considered as X bit is left at 1 for link plugging.
+ */
+ hotplug_mask = 0;
+
+ if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+ else
+ hotplug_mask = SERR_PHYRDY_CHG;
+
+ if (serror & hotplug_mask)
ata_ehi_hotplugged(&ehc->i);
ehc->i.err_mask |= err_mask;
@@ -1236,7 +1423,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
/**
* ata_eh_analyze_ncq_error - analyze NCQ error
- * @ap: ATA port to analyze NCQ error for
+ * @link: ATA link to analyze NCQ error for
*
* Read log page 10h, determine the offending qc and acquire
* error status TF. For NCQ device errors, all LLDDs have to do
@@ -1246,10 +1433,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev = ap->device;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
struct ata_queued_cmd *qc;
struct ata_taskfile tf;
int tag, rc;
@@ -1259,7 +1447,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
return;
/* is it NCQ device error? */
- if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
return;
/* has LLDD analyzed already? */
@@ -1276,13 +1464,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* okay, this error is ours */
rc = ata_eh_read_log_10h(dev, &tag, &tf);
if (rc) {
- ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
"(errno=%d)\n", rc);
return;
}
- if (!(ap->sactive & (1 << tag))) {
- ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ if (!(link->sactive & (1 << tag))) {
+ ata_link_printk(link, KERN_ERR, "log page 10h reported "
"inactive tag %d\n", tag);
return;
}
@@ -1497,7 +1685,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
/* speed down? */
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
/* speed down SATA link speed if possible */
- if (sata_down_spd_limit(dev->ap) == 0) {
+ if (sata_down_spd_limit(dev->link) == 0) {
action |= ATA_EH_HARDRESET;
goto done;
}
@@ -1528,7 +1716,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
* SATA. Consider it only for PATA.
*/
if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
- (dev->ap->cbl != ATA_CBL_SATA) &&
+ (dev->link->ap->cbl != ATA_CBL_SATA) &&
(dev->xfer_shift != ATA_SHIFT_PIO)) {
if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
dev->spdn_cnt = 0;
@@ -1545,19 +1733,20 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
}
/**
- * ata_eh_autopsy - analyze error and determine recovery action
- * @ap: ATA port to perform autopsy on
+ * ata_eh_link_autopsy - analyze error and determine recovery action
+ * @link: host link to perform autopsy on
*
- * Analyze why @ap failed and determine which recovery action is
- * needed. This function also sets more detailed AC_ERR_* values
- * and fills sense data for ATAPI CHECK SENSE.
+ * Analyze why @link failed and determine which recovery actions
+ * are needed. This function also sets more detailed AC_ERR_*
+ * values and fills sense data for ATAPI CHECK SENSE.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_link_autopsy(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned int all_err_mask = 0;
int tag, is_io = 0;
u32 serror;
@@ -1569,10 +1758,10 @@ static void ata_eh_autopsy(struct ata_port *ap)
return;
/* obtain and analyze SError */
- rc = sata_scr_read(ap, SCR_ERROR, &serror);
+ rc = sata_scr_read(link, SCR_ERROR, &serror);
if (rc == 0) {
ehc->i.serror |= serror;
- ata_eh_analyze_serror(ap);
+ ata_eh_analyze_serror(link);
} else if (rc != -EOPNOTSUPP) {
/* SError read failed, force hardreset and probing */
ata_ehi_schedule_probe(&ehc->i);
@@ -1581,7 +1770,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/* analyze NCQ failure */
- ata_eh_analyze_ncq_error(ap);
+ ata_eh_analyze_ncq_error(link);
/* any real error trumps AC_ERR_OTHER */
if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1592,7 +1781,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
continue;
/* inherit upper level err_mask */
@@ -1646,20 +1835,43 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/**
- * ata_eh_report - report error handling to user
- * @ap: ATA port EH is going on
+ * ata_eh_autopsy - analyze error and determine recovery action
+ * @ap: host port to perform autopsy on
+ *
+ * Analyze all links of @ap and determine why they failed and
+ * which recovery actions are needed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_eh_autopsy(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_autopsy(link);
+}
+
+/**
+ * ata_eh_link_report - report error handling to user
+ * @link: ATA link EH is going on
*
* Report EH to user.
*
* LOCKING:
* None.
*/
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_link_report(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
+ char tries_buf[6];
int tag, nr_failed = 0;
+ if (ehc->i.flags & ATA_EHI_QUIET)
+ return;
+
desc = NULL;
if (ehc->i.desc[0] != '\0')
desc = ehc->i.desc;
@@ -1667,7 +1879,7 @@ static void ata_eh_report(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
continue;
if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
continue;
@@ -1682,22 +1894,48 @@ static void ata_eh_report(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
+ memset(tries_buf, 0, sizeof(tries_buf));
+ if (ap->eh_tries < ATA_EH_MAX_TRIES)
+ snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ ap->eh_tries);
+
if (ehc->i.dev) {
ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else {
- ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_port_printk(ap, KERN_ERR, "%s\n", desc);
+ ata_link_printk(link, KERN_ERR, "%s\n", desc);
}
+ if (ehc->i.serror)
+ ata_port_printk(ap, KERN_ERR,
+ "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+ ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
+ ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
+ ehc->i.serror & SERR_DATA ? "UnrecovData " : "",
+ ehc->i.serror & SERR_PERSISTENT ? "Persist " : "",
+ ehc->i.serror & SERR_PROTOCOL ? "Proto " : "",
+ ehc->i.serror & SERR_INTERNAL ? "HostInt " : "",
+ ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "",
+ ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "",
+ ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "",
+ ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "",
+ ehc->i.serror & SERR_DISPARITY ? "Dispar " : "",
+ ehc->i.serror & SERR_CRC ? "BadCRC " : "",
+ ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "",
+ ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "",
+ ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
+ ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
+ ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" );
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
static const char *dma_str[] = {
[DMA_BIDIRECTIONAL] = "bidi",
@@ -1708,7 +1946,8 @@ static void ata_eh_report(struct ata_port *ap)
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ qc->dev->link != link || !qc->err_mask)
continue;
ata_dev_printk(qc->dev, KERN_ERR,
@@ -1728,18 +1967,60 @@ static void ata_eh_report(struct ata_port *ap)
res->hob_lbal, res->hob_lbam, res->hob_lbah,
res->device, qc->err_mask, ata_err_string(qc->err_mask),
qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+
+ if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
+ ATA_ERR) ) {
+ if (res->command & ATA_BUSY)
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { Busy }\n" );
+ else
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { %s%s%s%s}\n",
+ res->command & ATA_DRDY ? "DRDY " : "",
+ res->command & ATA_DF ? "DF " : "",
+ res->command & ATA_DRQ ? "DRQ " : "",
+ res->command & ATA_ERR ? "ERR " : "" );
+ }
+
+ if (cmd->command != ATA_CMD_PACKET &&
+ (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
+ ATA_ABORTED)))
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "error: { %s%s%s%s}\n",
+ res->feature & ATA_ICRC ? "ICRC " : "",
+ res->feature & ATA_UNC ? "UNC " : "",
+ res->feature & ATA_IDNF ? "IDNF " : "",
+ res->feature & ATA_ABORTED ? "ABRT " : "" );
}
}
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+/**
+ * ata_eh_report - report error handling to user
+ * @ap: ATA port to report EH about
+ *
+ * Report EH to user.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_report(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_report(link);
+}
+
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
- int i, rc;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(ap, classes, deadline);
+ rc = reset(link, classes, deadline);
if (rc)
return rc;
@@ -1747,71 +2028,87 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
* is complete and convert all ATA_DEV_UNKNOWN to
* ATA_DEV_NONE.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (classes[dev->devno] != ATA_DEV_UNKNOWN)
break;
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
+ if (dev) {
+ ata_link_for_each_dev(dev, link) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+ }
return 0;
}
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+ int rc, int classify,
const unsigned int *classes)
{
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ return 0;
if (rc == -EAGAIN)
return 1;
if (rc != 0)
return 0;
- if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+ return 1;
+ if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+ classes[0] == ATA_DEV_UNKNOWN)
return 1;
return 0;
}
-static int ata_eh_reset(struct ata_port *ap, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned int *classes = ehc->classes;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
int try = 0;
+ struct ata_device *dev;
unsigned long deadline;
unsigned int action;
ata_reset_fn_t reset;
- int i, rc;
+ unsigned long flags;
+ int rc;
/* about to reset */
- ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
action = ehc->i.action;
ehc->i.action &= ~ATA_EH_RESET_MASK;
- if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+ if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) &&
+ !sata_set_spd_needed(link) &&
!(action & ATA_EH_HARDRESET))))
ehc->i.action |= ATA_EH_SOFTRESET;
else
ehc->i.action |= ATA_EH_HARDRESET;
if (prereset) {
- rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
+ rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
if (rc) {
if (rc == -ENOENT) {
- ata_port_printk(ap, KERN_DEBUG,
+ ata_link_printk(link, KERN_DEBUG,
"port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
} else
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
goto out;
}
@@ -1824,8 +2121,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
reset = softreset;
else {
/* prereset told us not to reset, bang classes and return */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
goto out;
}
@@ -1843,7 +2140,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* shut up during boot probing */
if (verbose)
- ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+ ata_link_printk(link, KERN_INFO, "%s resetting link\n",
reset == softreset ? "soft" : "hard");
/* mark that this EH session started with reset */
@@ -1852,49 +2149,54 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
else
ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(ap, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline);
if (reset == hardreset &&
- ata_eh_followup_srst_needed(rc, classify, classes)) {
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
/* okay, let's do follow-up softreset */
reset = softreset;
if (!reset) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
rc = -EINVAL;
goto out;
}
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- rc = ata_do_reset(ap, reset, classes, deadline);
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
+ rc = ata_do_reset(link, reset, classes, deadline);
- if (rc == 0 && classify &&
- classes[0] == ATA_DEV_UNKNOWN) {
- ata_port_printk(ap, KERN_ERR,
+ if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN &&
+ !(link->flags & ATA_LFLAG_ASSUME_CLASS)) {
+ ata_link_printk(link, KERN_ERR,
"classification failed\n");
rc = -EINVAL;
goto out;
}
}
- if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+ /* if we skipped follow-up srst, clear rc */
+ if (rc == -EAGAIN)
+ rc = 0;
+
+ if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
unsigned long now = jiffies;
if (time_before(now, deadline)) {
unsigned long delta = deadline - jiffies;
- ata_port_printk(ap, KERN_WARNING, "reset failed "
+ ata_link_printk(link, KERN_WARNING, "reset failed "
"(errno=%d), retrying in %u secs\n",
rc, (jiffies_to_msecs(delta) + 999) / 1000);
- schedule_timeout_uninterruptible(delta);
+ while (delta)
+ delta = schedule_timeout_uninterruptible(delta);
}
if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(link);
if (hardreset)
reset = hardreset;
goto retry;
@@ -1903,37 +2205,56 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
if (rc == 0) {
u32 sstatus;
- /* After the reset, the device state is PIO 0 and the
- * controller state is undefined. Record the mode.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
+ ata_link_for_each_dev(dev, link) {
+ /* After the reset, the device state is PIO 0
+ * and the controller state is undefined.
+ * Record the mode.
+ */
+ dev->pio_mode = XFER_PIO_0;
+
+ if (ata_link_offline(link))
+ continue;
+
+ /* apply class override and convert UNKNOWN to NONE */
+ if (link->flags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (link->flags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
/* record current link speed */
- if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
- ap->sata_spd = (sstatus >> 4) & 0xf;
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
+ link->sata_spd = (sstatus >> 4) & 0xf;
if (postreset)
- postreset(ap, classes);
+ postreset(link, classes);
/* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
out:
/* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
return rc;
}
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
unsigned int new_mask = 0;
unsigned long flags;
- int i, rc = 0;
+ int rc = 0;
DPRINTK("ENTER\n");
@@ -1941,27 +2262,28 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
* be done backwards such that PDIAG- is released by the slave
* device before the master device is identified.
*/
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- unsigned int action, readid_flags = 0;
-
- dev = &ap->device[i];
- action = ata_eh_dev_action(dev);
+ ata_link_for_each_dev_reverse(dev, link) {
+ unsigned int action = ata_eh_dev_action(dev);
+ unsigned int readid_flags = 0;
if (ehc->i.flags & ATA_EHI_DID_RESET)
readid_flags |= ATA_READID_POSTRESET;
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
- if (ata_port_offline(ap)) {
+ WARN_ON(dev->class == ATA_DEV_PMP);
+
+ if (ata_link_offline(link)) {
rc = -EIO;
goto err;
}
- ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev, readid_flags);
+ ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
+ rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+ readid_flags);
if (rc)
goto err;
- ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+ ata_eh_done(link, dev, ATA_EH_REVALIDATE);
/* Configuration may have changed, reconfigure
* transfer mode.
@@ -1975,11 +2297,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
ata_class_enabled(ehc->classes[dev->devno])) {
dev->class = ehc->classes[dev->devno];
- rc = ata_dev_read_id(dev, &dev->class, readid_flags,
- dev->id);
+ if (dev->class == ATA_DEV_PMP)
+ rc = sata_pmp_attach(dev);
+ else
+ rc = ata_dev_read_id(dev, &dev->class,
+ readid_flags, dev->id);
switch (rc) {
case 0:
- new_mask |= 1 << i;
+ new_mask |= 1 << dev->devno;
break;
case -ENOENT:
/* IDENTIFY was issued to non-existent
@@ -1997,16 +2322,16 @@ 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)
+ if (ata_is_host_link(link) && ap->ops->cable_detect &&
+ (ehc->i.flags & ATA_EHI_DID_RESET))
ap->cbl = ap->ops->cable_detect(ap);
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!(new_mask & (1 << i)))
+ ata_link_for_each_dev(dev, link) {
+ if (!(new_mask & (1 << dev->devno)) ||
+ dev->class == ATA_DEV_PMP)
continue;
ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -2031,40 +2356,44 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, link)
+ if (ata_dev_enabled(dev))
cnt++;
return cnt;
}
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ap->device[i].class == ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (dev->class == ATA_DEV_UNKNOWN)
cnt++;
return cnt;
}
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- int i;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev;
+
+ /* skip disabled links */
+ if (link->flags & ATA_LFLAG_DISABLED)
+ return 1;
/* thaw frozen port, resume link and recover failed devices */
- if ((ap->pflags & ATA_PFLAG_FROZEN) ||
- (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+ if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (dev->class == ATA_DEV_UNKNOWN &&
ehc->classes[dev->devno] != ATA_DEV_NONE)
return 0;
@@ -2073,10 +2402,9 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
return 1;
}
-static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
ehc->tries[dev->devno]--;
@@ -2092,7 +2420,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(dev->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2102,7 +2430,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev);
/* detach if offline */
- if (ata_port_offline(ap))
+ if (ata_link_offline(dev->link))
ata_eh_detach_dev(dev);
/* probe if requested */
@@ -2115,12 +2443,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ehc->did_probe_mask |= (1 << dev->devno);
ehc->i.action |= ATA_EH_SOFTRESET;
}
+
+ return 1;
} else {
/* soft didn't work? be haaaaard */
if (ehc->i.flags & ATA_EHI_DID_RESET)
ehc->i.action |= ATA_EH_HARDRESET;
else
ehc->i.action |= ATA_EH_SOFTRESET;
+
+ return 0;
}
}
@@ -2131,12 +2463,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
+ * @r_failed_link: out parameter for failed link
*
* This is the alpha and omega, eum and yang, heart and soul of
* libata exception handling. On entry, actions required to
- * recover the port and hotplug requests are recorded in
- * eh_context. This function executes all the operations with
- * appropriate retrials and fallbacks to resurrect failed
+ * recover each link and hotplug requests are recorded in the
+ * link's eh_context. This function executes all the operations
+ * with appropriate retrials and fallbacks to resurrect failed
* devices, detach goners and greet newcomers.
*
* LOCKING:
@@ -2145,104 +2478,171 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_link *link;
struct ata_device *dev;
- int i, rc;
+ int nr_failed_devs, nr_disabled_devs;
+ int reset, rc;
+ unsigned long flags;
DPRINTK("ENTER\n");
/* prep for recovery */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-
- /* collect port action mask recorded in dev actions */
- ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
- ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
-
- /* process hotplug request */
- if (dev->flags & ATA_DFLAG_DETACH)
- ata_eh_detach_dev(dev);
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ /* re-enable link? */
+ if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+ ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags &= ~ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+ }
- if (!ata_dev_enabled(dev) &&
- ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno)))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
+ ata_link_for_each_dev(dev, link) {
+ if (link->flags & ATA_LFLAG_NO_RETRY)
+ ehc->tries[dev->devno] = 1;
+ else
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+ /* collect port action mask recorded in dev actions */
+ ehc->i.action |= ehc->i.dev_action[dev->devno] &
+ ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK;
+
+ /* process hotplug request */
+ if (dev->flags & ATA_DFLAG_DETACH)
+ ata_eh_detach_dev(dev);
+
+ if (!ata_dev_enabled(dev) &&
+ ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno)))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
}
}
retry:
rc = 0;
+ nr_failed_devs = 0;
+ nr_disabled_devs = 0;
+ reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
- /* skip EH if possible. */
- if (ata_eh_skip_recovery(ap))
- ehc->i.action = 0;
+ /* prep for EH */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehc->classes[i] = ATA_DEV_UNKNOWN;
+ /* skip EH if possible. */
+ if (ata_eh_skip_recovery(link))
+ ehc->i.action = 0;
- /* reset */
- if (ehc->i.action & ATA_EH_RESET_MASK) {
- ata_eh_freeze_port(ap);
+ /* do we need to reset? */
+ if (ehc->i.action & ATA_EH_RESET_MASK)
+ reset = 1;
- rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
- softreset, hardreset, postreset);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
+ ata_link_for_each_dev(dev, link)
+ ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+ }
+
+ /* reset */
+ if (reset) {
+ /* if PMP is attached, this function only deals with
+ * downstream links, port should stay thawed.
+ */
+ if (!ap->nr_pmp_links)
+ ata_eh_freeze_port(ap);
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ if (!(ehc->i.action & ATA_EH_RESET_MASK))
+ continue;
+
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
+ }
}
- ata_eh_thaw_port(ap);
+ if (!ap->nr_pmp_links)
+ ata_eh_thaw_port(ap);
}
- /* revalidate existing devices and attach new ones */
- rc = ata_eh_revalidate_and_attach(ap, &dev);
- if (rc)
- goto dev_fail;
+ /* the rest */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- /* configure transfer mode if necessary */
- if (ehc->i.flags & ATA_EHI_SETMODE) {
- rc = ata_set_mode(ap, &dev);
+ /* revalidate existing devices and attach new ones */
+ rc = ata_eh_revalidate_and_attach(link, &dev);
if (rc)
goto dev_fail;
- ehc->i.flags &= ~ATA_EHI_SETMODE;
- }
- goto out;
+ /* if PMP got attached, return, pmp EH will take care of it */
+ if (link->device->class == ATA_DEV_PMP) {
+ ehc->i.action = 0;
+ return 0;
+ }
- dev_fail:
- ata_eh_handle_dev_fail(dev, rc);
+ /* configure transfer mode if necessary */
+ if (ehc->i.flags & ATA_EHI_SETMODE) {
+ rc = ata_set_mode(link, &dev);
+ if (rc)
+ goto dev_fail;
+ ehc->i.flags &= ~ATA_EHI_SETMODE;
+ }
- if (ata_port_nr_enabled(ap)) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover some "
- "devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left, repeat fast */
- msleep(500);
+ /* this link is okay now */
+ ehc->i.flags = 0;
+ continue;
+
+ dev_fail:
+ nr_failed_devs++;
+ if (ata_eh_handle_dev_fail(dev, rc))
+ nr_disabled_devs++;
+
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
+ /* PMP reset requires working host port.
+ * Can't retry if it's frozen.
+ */
+ if (ap->nr_pmp_links)
+ goto out;
+ break;
+ }
}
- goto retry;
+ if (nr_failed_devs) {
+ if (nr_failed_devs != nr_disabled_devs) {
+ ata_port_printk(ap, KERN_WARNING, "failed to recover "
+ "some devices, retrying in 5 secs\n");
+ ssleep(5);
+ } else {
+ /* no device left to recover, repeat fast */
+ msleep(500);
+ }
- out:
- if (rc) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ goto retry;
}
+ out:
+ if (rc && r_failed_link)
+ *r_failed_link = link;
+
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -2257,7 +2657,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
* LOCKING:
* None.
*/
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
{
int tag;
@@ -2287,6 +2687,10 @@ static void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
@@ -2306,9 +2710,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
+ struct ata_device *dev;
+ int rc;
+
ata_eh_autopsy(ap);
ata_eh_report(ap);
- ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ }
+
ata_eh_finish(ap);
}
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644
index 00000000000..c0c4dbcde09
--- /dev/null
+++ b/drivers/ata/libata-pmp.c
@@ -0,0 +1,1191 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ * sata_pmp_read - read PMP register
+ * @link: link to read PMP register for
+ * @reg: register to read
+ * @r_val: resulting value
+ *
+ * Read PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_READ;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+
+ err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+ if (err_mask)
+ return err_mask;
+
+ *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
+ return 0;
+}
+
+/**
+ * sata_pmp_write - write PMP register
+ * @link: link to write PMP register for
+ * @reg: register to write
+ * @r_val: value to write
+ *
+ * Write PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_WRITE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+ tf.nsect = val & 0xff;
+ tf.lbal = (val >> 8) & 0xff;
+ tf.lbam = (val >> 16) & 0xff;
+ tf.lbah = (val >> 24) & 0xff;
+
+ return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+}
+
+/**
+ * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ * @qc: ATA command in question
+ *
+ * A host which has command switching PMP support cannot issue
+ * commands to multiple links simultaneously.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+
+ if (ap->excl_link == NULL || ap->excl_link == link) {
+ if (ap->nr_active_links == 0 || ata_link_active(link)) {
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return ata_std_qc_defer(qc);
+ }
+
+ ap->excl_link = link;
+ }
+
+ return ATA_DEFER_PORT;
+}
+
+/**
+ * sata_pmp_scr_read - read PSCR
+ * @link: ATA link to read PSCR for
+ * @reg: PSCR to read
+ * @r_val: resulting value
+ *
+ * Read PSCR @reg into @r_val for @link, to be called from
+ * ata_scr_read().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_read(link, reg, r_val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_scr_write - write PSCR
+ * @link: ATA link to write PSCR for
+ * @reg: PSCR to write
+ * @val: value to be written
+ *
+ * Write @val to PSCR @reg for @link, to be called from
+ * ata_scr_write() and ata_scr_write_flush().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_write(link, reg, val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_std_prereset - prepare PMP link for reset
+ * @link: link to be reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * @link is about to be reset. Initialize it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ /* force HRST? */
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* handle link resume */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* resume link */
+ rc = sata_link_resume(link, timing, deadline);
+ if (rc) {
+ /* phy resume failed */
+ ata_link_printk(link, KERN_WARNING, "failed to resume link "
+ "for reset (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to clear SError (errno=%d)\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_std_hardreset - standard hardreset method for PMP link
+ * @link: link to be reset
+ * @class: resulting class of attached device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Hardreset PMP port @link. Note that this function doesn't
+ * wait for BSY clearance. There simply isn't a generic way to
+ * wait the event. Instead, this function return -EAGAIN thus
+ * telling libata-EH to followup with softreset.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ u32 tmp;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* do hardreset */
+ rc = sata_link_hardreset(link, timing, deadline);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "COMRESET failed (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear SError "
+ "during hardreset (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* if device is present, follow up with srst to wait for !BSY */
+ if (ata_link_online(link))
+ rc = -EAGAIN;
+ out:
+ /* if SCR isn't accessible, we need to reset the PMP */
+ if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+ rc = -ERESTART;
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * ata_std_postreset - standard postreset method for PMP link
+ * @link: the target ata_link
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. Note that
+ * the device might have been reset more than once using
+ * different reset methods before postreset is invoked.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+ u32 serror;
+
+ DPRINTK("ENTER\n");
+
+ /* clear SError */
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
+
+ /* print link status */
+ sata_print_link_status(link);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * sata_pmp_read_gscr - read GSCR block of SATA PMP
+ * @dev: PMP device
+ * @gscr: buffer to read GSCR block into
+ *
+ * Read selected PMP GSCRs from the PMP at @dev. This will serve
+ * as configuration and identification info for the PMP.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+ static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+ int reg = gscr_to_read[i];
+ unsigned int err_mask;
+
+ err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
+ "GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+ u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+ if (rev & (1 << 2))
+ return "1.1";
+ if (rev & (1 << 1))
+ return "1.0";
+ return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+ struct ata_port *ap = dev->link->ap;
+ u32 *gscr = dev->gscr;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int nr_ports, rc;
+
+ nr_ports = sata_pmp_gscr_ports(gscr);
+
+ if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+ rc = -EINVAL;
+ reason = "invalid nr_ports";
+ goto fail;
+ }
+
+ if ((ap->flags & ATA_FLAG_AN) &&
+ (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
+ dev->flags |= ATA_DFLAG_AN;
+
+ /* monitor SERR_PHYRDY_CHG on fan-out ports */
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
+ SERR_PHYRDY_CHG);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_ERROR_EN";
+ goto fail;
+ }
+
+ /* turn off notification till fan-out ports are reset and configured */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_FEAT_EN";
+ goto fail;
+ }
+ }
+
+ if (print_info) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+ "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+ sata_pmp_spec_rev_str(gscr),
+ sata_pmp_gscr_vendor(gscr),
+ sata_pmp_gscr_devid(gscr),
+ sata_pmp_gscr_rev(gscr),
+ nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+ gscr[SATA_PMP_GSCR_FEAT]);
+
+ if (!(dev->flags & ATA_DFLAG_AN))
+ ata_dev_printk(dev, KERN_INFO,
+ "Asynchronous notification not supported, "
+ "hotplug won't\n work on fan-out "
+ "ports. Use warm-plug instead.\n");
+ }
+
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+ reason, err_mask);
+ return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+ struct ata_link *pmp_link = ap->pmp_link;
+ int i;
+
+ if (!pmp_link) {
+ pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+ GFP_NOIO);
+ if (!pmp_link)
+ return -ENOMEM;
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_link_init(ap, &pmp_link[i], i);
+
+ ap->pmp_link = pmp_link;
+ }
+
+ for (i = 0; i < nr_ports; i++) {
+ struct ata_link *link = &pmp_link[i];
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ link->flags = 0;
+ ehc->i.probe_mask |= 1;
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ ehc->i.flags |= ATA_EHI_RESUME_LINK;
+ }
+
+ return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+ u32 *gscr = ap->link.device->gscr;
+ u16 vendor = sata_pmp_gscr_vendor(gscr);
+ u16 devid = sata_pmp_gscr_devid(gscr);
+ struct ata_link *link;
+
+ if (vendor == 0x1095 && devid == 0x3726) {
+ /* sil3726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* port 5 is for SEMB device and it doesn't like SRST */
+ if (link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4723) {
+ /* sil4723 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 2)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* the config device at port 2 locks up on SRST */
+ if (link->pmp == 2)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4726) {
+ /* sil4726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* The config device, which can be either at
+ * port 0 or 5, locks up on SRST.
+ */
+ if (link->pmp == 0 || link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+
+ /* Port 6 is for SEMB device which doesn't
+ * like SRST either.
+ */
+ if (link->pmp == 6)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+ devid == 0x5734 || devid == 0x5744)) {
+ /* sil5723/5744 quirks */
+
+ /* sil5723/5744 has either two or three downstream
+ * ports depending on operation mode. The last port
+ * is empty if any actual IO device is available or
+ * occupied by a pseudo configuration device
+ * otherwise. Don't try hard to recover it.
+ */
+ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+ } else if (vendor == 0x11ab && devid == 0x4140) {
+ /* Marvell 88SM4140 quirks. Fan-out ports require PHY
+ * reset to work; other than that, it behaves very
+ * nicely.
+ */
+ ata_port_for_each_link(link, ap)
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+ }
+}
+
+/**
+ * sata_pmp_attach - attach a SATA PMP device
+ * @dev: SATA PMP device to attach
+ *
+ * Configure and attach SATA PMP device @dev. This function is
+ * also responsible for allocating and initializing PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+ struct ata_link *tlink;
+ int rc;
+
+ /* is it hanging off the right place? */
+ if (!(ap->flags & ATA_FLAG_PMP)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "host does not support Port Multiplier\n");
+ return -EINVAL;
+ }
+
+ if (!ata_is_host_link(link)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multipliers cannot be nested\n");
+ return -EINVAL;
+ }
+
+ if (dev->devno) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multiplier must be the first device\n");
+ return -EINVAL;
+ }
+
+ WARN_ON(link->pmp != 0);
+ link->pmp = SATA_PMP_CTRL_PORT;
+
+ /* read GSCR block */
+ rc = sata_pmp_read_gscr(dev, dev->gscr);
+ if (rc)
+ goto fail;
+
+ /* config PMP */
+ rc = sata_pmp_configure(dev, 1);
+ if (rc)
+ goto fail;
+
+ rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+ if (rc) {
+ ata_dev_printk(dev, KERN_INFO,
+ "failed to initialize PMP links\n");
+ goto fail;
+ }
+
+ /* attach it */
+ spin_lock_irqsave(ap->lock, flags);
+ WARN_ON(ap->nr_pmp_links);
+ ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ sata_pmp_quirks(ap);
+
+ if (ap->ops->pmp_attach)
+ ap->ops->pmp_attach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ sata_link_init_spd(tlink);
+
+ ata_acpi_associate_sata_port(ap);
+
+ return 0;
+
+ fail:
+ link->pmp = 0;
+ return rc;
+}
+
+/**
+ * sata_pmp_detach - detach a SATA PMP device
+ * @dev: SATA PMP device to detach
+ *
+ * Detach SATA PMP device @dev. This function is also
+ * responsible for deconfiguring PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ata_link *tlink;
+ unsigned long flags;
+
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+ WARN_ON(!ata_is_host_link(link) || dev->devno ||
+ link->pmp != SATA_PMP_CTRL_PORT);
+
+ if (ap->ops->pmp_detach)
+ ap->ops->pmp_detach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ ata_eh_detach_dev(tlink->device);
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->nr_pmp_links = 0;
+ link->pmp = 0;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_acpi_associate_sata_port(ap);
+}
+
+/**
+ * sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ * @dev: PMP device to compare against
+ * @new_gscr: GSCR block of the new device
+ *
+ * Compare @new_gscr against @dev and determine whether @dev is
+ * the PMP described by @new_gscr.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+ const u32 *old_gscr = dev->gscr;
+ u16 old_vendor, new_vendor, old_devid, new_devid;
+ int old_nr_ports, new_nr_ports;
+
+ old_vendor = sata_pmp_gscr_vendor(old_gscr);
+ new_vendor = sata_pmp_gscr_vendor(new_gscr);
+ old_devid = sata_pmp_gscr_devid(old_gscr);
+ new_devid = sata_pmp_gscr_devid(new_gscr);
+ old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+ new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+ if (old_vendor != new_vendor) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "vendor mismatch '0x%x' != '0x%x'\n",
+ old_vendor, new_vendor);
+ return 0;
+ }
+
+ if (old_devid != new_devid) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "device ID mismatch '0x%x' != '0x%x'\n",
+ old_devid, new_devid);
+ return 0;
+ }
+
+ if (old_nr_ports != new_nr_ports) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "nr_ports mismatch '0x%x' != '0x%x'\n",
+ old_nr_ports, new_nr_ports);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * sata_pmp_revalidate - revalidate SATA PMP
+ * @dev: PMP device to revalidate
+ * @new_class: new class code
+ *
+ * Re-read GSCR block and make sure @dev is still attached to the
+ * port and properly configured.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ u32 *gscr = (void *)ap->sector_buf;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+ if (!ata_dev_enabled(dev)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* wrong class? */
+ if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* read GSCR */
+ rc = sata_pmp_read_gscr(dev, gscr);
+ if (rc)
+ goto fail;
+
+ /* is the pmp still there? */
+ if (!sata_pmp_same_pmp(dev, gscr)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+ rc = sata_pmp_configure(dev, 0);
+ if (rc)
+ goto fail;
+
+ ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "PMP revalidation failed (errno=%d)\n", rc);
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ * @dev: PMP device to revalidate
+ *
+ * Make sure the attached PMP is accessible.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u32 prod_id;
+
+ err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
+ "(Emask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+
+ if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+ ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+ /* something weird is going on, request full PMP recovery */
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover_pmp - recover PMP
+ * @ap: ATA port PMP is attached to
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ *
+ * Recover PMP attached to @ap. Recovery procedure is somewhat
+ * similar to that of ata_eh_recover() except that reset should
+ * always be performed in hard->soft sequence and recovery
+ * failure results in PMP detachment.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_link *link = &ap->link;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
+ int tries = ATA_EH_PMP_TRIES;
+ int detach = 0, rc = 0;
+ int reval_failed = 0;
+
+ DPRINTK("ENTER\n");
+
+ if (dev->flags & ATA_DFLAG_DETACH) {
+ detach = 1;
+ goto fail;
+ }
+
+ retry:
+ ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+ if (ehc->i.action & ATA_EH_RESET_MASK) {
+ struct ata_link *tlink;
+
+ ata_eh_freeze_port(ap);
+
+ /* reset */
+ ehc->i.action = ATA_EH_HARDRESET;
+ rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to reset PMP, giving up\n");
+ goto fail;
+ }
+
+ ata_eh_thaw_port(ap);
+
+ /* PMP is reset, SErrors cannot be trusted, scan all */
+ ata_port_for_each_link(tlink, ap)
+ ata_ehi_schedule_probe(&tlink->eh_context.i);
+ }
+
+ /* If revalidation is requested, revalidate and reconfigure;
+ * otherwise, do quick revalidation.
+ */
+ if (ehc->i.action & ATA_EH_REVALIDATE)
+ rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+ else
+ rc = sata_pmp_revalidate_quick(dev);
+
+ if (rc) {
+ tries--;
+
+ if (rc == -ENODEV) {
+ ehc->i.probe_mask |= 1;
+ detach = 1;
+ /* give it just two more chances */
+ tries = min(tries, 2);
+ }
+
+ if (tries) {
+ int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+ /* consecutive revalidation failures? speed down */
+ if (reval_failed)
+ sata_down_spd_limit(link);
+ else
+ reval_failed = 1;
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "retrying hardreset%s\n",
+ sleep ? " in 5 secs" : "");
+ if (sleep)
+ ssleep(5);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ } else {
+ ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+ "after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ goto fail;
+ }
+ }
+
+ /* okay, PMP resurrected */
+ ehc->i.flags = 0;
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ sata_pmp_detach(dev);
+ if (detach)
+ ata_eh_detach_dev(dev);
+ else
+ ata_dev_disable(dev);
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+ struct ata_link *link;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ata_port_for_each_link(link, ap) {
+ if (!(link->flags & ATA_LFLAG_DISABLED))
+ continue;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Some PMPs require hardreset sequence to get
+ * SError.N working.
+ */
+ if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+ (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+ sata_link_hardreset(link, sata_deb_timing_normal,
+ jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+ /* unconditionally clear SError.N */
+ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear "
+ "SError.N (errno=%d)\n", rc);
+ return rc;
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+
+ if (link_tries[link->pmp] && --link_tries[link->pmp])
+ return 1;
+
+ /* disable this link */
+ if (!(link->flags & ATA_LFLAG_DISABLED)) {
+ ata_link_printk(link, KERN_WARNING,
+ "failed to recover link after %d tries, disabling\n",
+ ATA_EH_PMP_LINK_TRIES);
+
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags |= ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ ata_dev_disable(link->device);
+ link->eh_context.i.action = 0;
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover - recover PMP-enabled port
+ * @ap: ATA port to recover
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Drive EH recovery operation for PMP enabled port @ap. This
+ * function recovers host and PMP ports with proper retrials and
+ * fallbacks. Actual recovery operations are performed using
+ * ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+ struct ata_link *pmp_link = &ap->link;
+ struct ata_device *pmp_dev = pmp_link->device;
+ struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned int err_mask;
+ u32 gscr_error, sntf;
+ int cnt, rc;
+
+ pmp_tries = ATA_EH_PMP_TRIES;
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+ /* PMP attached? */
+ if (!ap->nr_pmp_links) {
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+ postreset, NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ return rc;
+ }
+
+ if (pmp_dev->class != ATA_DEV_PMP)
+ return 0;
+
+ /* new PMP online */
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ /* fall through */
+ }
+
+ /* recover pmp */
+ rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+ postreset);
+ if (rc)
+ goto pmp_fail;
+
+ /* handle disabled links */
+ rc = sata_pmp_eh_handle_disabled_links(ap);
+ if (rc)
+ goto pmp_fail;
+
+ /* recover links */
+ rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset, &link);
+ if (rc)
+ goto link_fail;
+
+ /* Connection status might have changed while resetting other
+ * links, check SATA_PMP_GSCR_ERROR before returning.
+ */
+
+ /* clear SNotification */
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ /* enable notification */
+ if (pmp_dev->flags & ATA_DFLAG_AN) {
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
+ "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+ }
+
+ /* check GSCR_ERROR */
+ err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
+ "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+
+ cnt = 0;
+ ata_port_for_each_link(link, ap) {
+ if (!(gscr_error & (1 << link->pmp)))
+ continue;
+
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ ata_ehi_hotplugged(&link->eh_context.i);
+ cnt++;
+ } else {
+ ata_link_printk(link, KERN_WARNING,
+ "PHY status changed but maxed out on retries, "
+ "giving up\n");
+ ata_link_printk(link, KERN_WARNING,
+ "Manully issue scan to resume this link\n");
+ }
+ }
+
+ if (cnt) {
+ ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+ "ports, repeating recovery\n");
+ goto retry;
+ }
+
+ return 0;
+
+ link_fail:
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ }
+
+ /* fall through */
+ pmp_fail:
+ /* Control always ends up here after detaching PMP. Shut up
+ * and return if we're unloading.
+ */
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
+ return rc;
+
+ if (!ap->nr_pmp_links)
+ goto retry;
+
+ if (--pmp_tries) {
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to recover PMP, retrying in 5 secs\n");
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ ssleep(5);
+ goto retry;
+ }
+
+ ata_port_printk(ap, KERN_ERR,
+ "failed to recover PMP after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ sata_pmp_detach(pmp_dev);
+ ata_dev_disable(pmp_dev);
+
+ return rc;
+}
+
+/**
+ * sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ * @ap: host port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Perform standard error handling sequence for PMP-enabled host
+ * @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
+ sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset);
+ ata_eh_finish(ap);
+}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e83647651b3..d63c81ed084 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
#define ALL_SUB_MPAGES 0xff
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
RW_RECOVERY_MPAGE,
RW_RECOVERY_MPAGE_LEN - 2,
- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
- (1 << 6), /* ARRE (auto read reallocation) */
+ (1 << 7), /* AWRE */
0, /* read retry count */
0, 0, 0, 0,
0, /* write retry count */
@@ -450,13 +449,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
qc->scsicmd = cmd;
qc->scsidone = done;
- if (cmd->use_sg) {
- qc->__sg = (struct scatterlist *) cmd->request_buffer;
- qc->n_elem = cmd->use_sg;
- } else if (cmd->request_bufflen) {
- qc->__sg = &qc->sgent;
- qc->n_elem = 1;
- }
+ qc->__sg = scsi_sglist(cmd);
+ qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
done(cmd);
@@ -755,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ /* Schedule policy is determined by ->qc_defer() callback and
+ * it needs to see every deferred qc. Set dev_blocked to 1 to
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+ sdev->max_device_blocked = 1;
}
static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -943,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
goto invalid_fld; /* LOEJ bit set not supported */
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
+
+ if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+ /* the device lacks PM support, finish without doing anything */
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+ }
+
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -1355,6 +1363,7 @@ nothing_to_do:
static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &qc->dev->link->eh_info;
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
int need_sense = (qc->err_mask != 0);
@@ -1368,14 +1377,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
case ATA_CMD_SET_FEATURES:
if ((qc->tf.feature == SETFEATURES_WC_ON) ||
(qc->tf.feature == SETFEATURES_WC_OFF)) {
- ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ehi->action |= ATA_EH_REVALIDATE;
ata_port_schedule_eh(ap);
}
break;
case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
case ATA_CMD_SET_MULTI: /* multi_count changed */
- ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ehi->action |= ATA_EH_REVALIDATE;
ata_port_schedule_eh(ap);
break;
}
@@ -1422,37 +1431,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_port *ap = dev->ap;
- int is_ncq = is_io && ata_ncq_enabled(dev);
-
- if (is_ncq) {
- if (!ata_tag_valid(ap->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1483,14 +1461,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1498,17 +1474,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
/* data is present; dma-map it */
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
- if (unlikely(cmd->request_bufflen < 1)) {
+ if (unlikely(scsi_bufflen(cmd) < 1)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: zero len r/w req\n");
goto err_did;
}
- if (cmd->use_sg)
- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
- else
- ata_sg_init_one(qc, cmd->request_buffer,
- cmd->request_bufflen);
+ ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
qc->dma_dir = cmd->sc_data_direction;
}
@@ -1518,6 +1490,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
if (xlat_func(qc))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
@@ -1539,8 +1516,12 @@ err_mem:
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
@@ -1562,15 +1543,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
u8 *buf;
unsigned int buflen;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ struct scatterlist *sg = scsi_sglist(cmd);
- sg = (struct scatterlist *) cmd->request_buffer;
+ if (sg) {
buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
buflen = sg->length;
} else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
+ buf = NULL;
+ buflen = 0;
}
*buf_out = buf;
@@ -1590,12 +1570,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
+ if (sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
}
/**
@@ -1817,6 +1794,62 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
}
/**
+ * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Yields SAT-specified ATA VPD page.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ u8 pbuf[60];
+ struct ata_taskfile tf;
+ unsigned int i;
+
+ if (!buflen)
+ return 0;
+
+ memset(&pbuf, 0, sizeof(pbuf));
+ memset(&tf, 0, sizeof(tf));
+
+ pbuf[1] = 0x89; /* our page code */
+ pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ pbuf[3] = (0x238 & 0xff);
+
+ memcpy(&pbuf[8], "linux ", 8);
+ memcpy(&pbuf[16], "libata ", 16);
+ memcpy(&pbuf[32], DRV_VERSION, 4);
+ ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+ /* we don't store the ATA device signature, so we fake it */
+
+ tf.command = ATA_DRDY; /* really, this is Status reg */
+ tf.lbal = 0x1;
+ tf.nsect = 0x1;
+
+ ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
+ pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+
+ pbuf[56] = ATA_CMD_ID_ATA;
+
+ i = min(buflen, 60U);
+ memcpy(rbuf, &pbuf[0], i);
+ buflen -= i;
+
+ if (!buflen)
+ return 0;
+
+ memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+ return 0;
+}
+
+/**
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
@@ -2273,8 +2306,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_PKT_DMA;
} else {
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+ qc->tf.lbah = 0;
}
qc->nbytes = SCSI_SENSE_BUFFERSIZE;
@@ -2383,6 +2416,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
@@ -2396,20 +2430,26 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
}
qc->tf.command = ATA_CMD_PACKET;
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
/* check whether ATAPI DMA is safe */
if (!using_pio && ata_check_atapi_dma(qc))
using_pio = 1;
+ /* Some controller variants snoop this value for Packet transfers
+ to do state machine and FIFO management. Thus we want to set it
+ properly, and for DMA where it is effectively meaningless */
+ nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+
+ qc->tf.lbam = (nbytes & 0xFF);
+ qc->tf.lbah = (nbytes >> 8);
+
if (using_pio || nodata) {
/* no data, or PIO data xfer */
if (nodata)
qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
else
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
} else {
/* DMA data xfer */
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
@@ -2420,24 +2460,42 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_DMADIR;
}
+
+ /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+ as ATAPI tape drives don't get this right otherwise */
return 0;
}
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+static struct ata_device * ata_find_dev(struct ata_port *ap, int devno)
{
- if (likely(id < ATA_MAX_DEVICES))
- return &ap->device[id];
+ if (ap->nr_pmp_links == 0) {
+ if (likely(devno < ata_link_max_devices(&ap->link)))
+ return &ap->link.device[devno];
+ } else {
+ if (likely(devno < ap->nr_pmp_links))
+ return &ap->pmp_link[devno].device[0];
+ }
+
return NULL;
}
static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev)
{
+ int devno;
+
/* skip commands not addressed to targets we simulate */
- if (unlikely(scsidev->channel || scsidev->lun))
- return NULL;
+ if (ap->nr_pmp_links == 0) {
+ if (unlikely(scsidev->channel || scsidev->lun))
+ return NULL;
+ devno = scsidev->id;
+ } else {
+ if (unlikely(scsidev->id || scsidev->lun))
+ return NULL;
+ devno = scsidev->channel;
+ }
- return ata_find_dev(ap, scsidev->id);
+ return ata_find_dev(ap, devno);
}
/**
@@ -2458,7 +2516,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev)
if (unlikely(!ata_dev_enabled(dev)))
return 0;
- if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+ if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
if (unlikely(dev->class == ATA_DEV_ATAPI)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: ATAPI is %s, device ignored.\n",
@@ -2631,7 +2689,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
case ATA_CMD_WRITE_LONG_ONCE:
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld;
- qc->sect_size = scmd->request_bufflen;
+ qc->sect_size = scsi_bufflen(scmd);
}
/*
@@ -2661,7 +2719,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
/* request result TF */
qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -2746,28 +2804,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
void (*done)(struct scsi_cmnd *),
struct ata_device *dev)
{
+ u8 scsi_op = scmd->cmnd[0];
+ ata_xlat_func_t xlat_func;
int rc = 0;
- 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;
- }
-
if (dev->class == ATA_DEV_ATA) {
- ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
- scmd->cmnd[0]);
+ if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
- if (xlat_func)
- rc = ata_scsi_translate(dev, scmd, done, xlat_func);
- else
- ata_scsi_simulate(dev, scmd, done);
- } else
- rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ } else {
+ if (unlikely(!scmd->cmd_len))
+ goto bad_cdb_len;
+
+ xlat_func = NULL;
+ if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+ /* relay SCSI command to ATAPI device */
+ if (unlikely(scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
+
+ xlat_func = atapi_xlat;
+ } else {
+ /* ATA_16 passthru, treat as an ATA command */
+ if (unlikely(scmd->cmd_len > 16))
+ goto bad_cdb_len;
+
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ }
+ }
+
+ if (xlat_func)
+ rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+ else
+ ata_scsi_simulate(dev, scmd, done);
return rc;
+
+ bad_cdb_len:
+ DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+ scmd->cmd_len, scsi_op, dev->cdb_len);
+ scmd->result = DID_ERROR << 16;
+ done(scmd);
+ return 0;
}
/**
@@ -2835,6 +2913,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
+ u8 tmp8;
args.dev = dev;
args.id = dev->id;
@@ -2842,15 +2921,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
args.done = done;
switch(scsicmd[0]) {
- /* no-op's, complete with success */
- case SYNCHRONIZE_CACHE:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case FORMAT_UNIT: /* FIXME: correct? */
- case SEND_DIAGNOSTIC: /* FIXME: correct? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ /* TODO: worth improving? */
+ case FORMAT_UNIT:
+ ata_scsi_invalid_field(cmd, done);
break;
case INQUIRY:
@@ -2858,14 +2931,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_invalid_field(cmd, done);
else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
- else if (scsicmd[2] == 0x00)
+ else switch (scsicmd[2]) {
+ case 0x00:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
- else if (scsicmd[2] == 0x80)
+ break;
+ case 0x80:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
- else if (scsicmd[2] == 0x83)
+ break;
+ case 0x83:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
- else
+ break;
+ case 0x89:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+ break;
+ default:
ata_scsi_invalid_field(cmd, done);
+ break;
+ }
break;
case MODE_SENSE:
@@ -2893,8 +2975,33 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
break;
- /* mandatory commands we haven't implemented yet */
case REQUEST_SENSE:
+ ata_scsi_set_sense(cmd, 0, 0, 0);
+ cmd->result = (DRIVER_SENSE << 24);
+ done(cmd);
+ break;
+
+ /* if we reach this, then writeback caching is disabled,
+ * turning this into a no-op.
+ */
+ case SYNCHRONIZE_CACHE:
+ /* fall through */
+
+ /* no-op's, complete with success */
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ case TEST_UNIT_READY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ break;
+
+ case SEND_DIAGNOSTIC:
+ tmp8 = scsicmd[1] & ~(1 << 3);
+ if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
/* all other commands */
default:
@@ -2928,6 +3035,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /* Schedule policy is determined by ->qc_defer()
+ * callback and it needs to see every deferred qc.
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+ shost->max_host_blocked = 1;
+
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
if (rc)
goto err_add;
@@ -2951,25 +3065,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
int tries = 5;
struct ata_device *last_failed_dev = NULL;
+ struct ata_link *link;
struct ata_device *dev;
- unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED)
return;
repeat:
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct scsi_device *sdev;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev;
+ int channel = 0, id = 0;
- dev = &ap->device[i];
+ if (!ata_dev_enabled(dev) || dev->sdev)
+ continue;
- if (!ata_dev_enabled(dev) || dev->sdev)
- continue;
+ if (ata_is_host_link(link))
+ id = dev->devno;
+ else
+ channel = link->pmp;
- sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
- if (!IS_ERR(sdev)) {
- dev->sdev = sdev;
- scsi_device_put(sdev);
+ sdev = __scsi_add_device(ap->scsi_host, channel, id, 0,
+ NULL);
+ if (!IS_ERR(sdev)) {
+ dev->sdev = sdev;
+ scsi_device_put(sdev);
+ }
}
}
@@ -2977,12 +3098,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
* failure occurred, scan would have failed silently. Check
* whether all devices are attached.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev)
- break;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ goto exit_loop;
+ }
}
- if (i == ATA_MAX_DEVICES)
+ exit_loop:
+ if (!link)
return;
/* we're missing some SCSI devices */
@@ -3049,7 +3172,7 @@ int ata_scsi_offline_dev(struct ata_device *dev)
*/
static void ata_scsi_remove_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct scsi_device *sdev;
unsigned long flags;
@@ -3096,6 +3219,43 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
}
}
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+
+ ata_link_for_each_dev(dev, link) {
+ unsigned long flags;
+
+ if (!(dev->flags & ATA_DFLAG_DETACHED))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_DETACHED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_scsi_remove_dev(dev);
+ }
+}
+
+/**
+ * ata_scsi_media_change_notify - send media change event
+ * @atadev: Pointer to the disk device with media change event
+ *
+ * Tell the block layer to send a media change notification
+ * event.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_scsi_media_change_notify(struct ata_device *dev)
+{
+#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
+ if (dev->sdev)
+ scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
+#endif
+}
+
/**
* ata_scsi_hotplug - SCSI part of hotplug
* @work: Pointer to ATA port to perform SCSI hotplug on
@@ -3121,20 +3281,14 @@ void ata_scsi_hotplug(struct work_struct *work)
DPRINTK("ENTER\n");
- /* unplug detached devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- unsigned long flags;
-
- if (!(dev->flags & ATA_DFLAG_DETACHED))
- continue;
-
- spin_lock_irqsave(ap->lock, flags);
- dev->flags &= ~ATA_DFLAG_DETACHED;
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_scsi_remove_dev(dev);
- }
+ /* Unplug detached devices. We cannot use link iterator here
+ * because PMP links have to be scanned even if PMP is
+ * currently not attached. Iterate manually.
+ */
+ ata_scsi_handle_link_detach(&ap->link);
+ if (ap->pmp_link)
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_scsi_handle_link_detach(&ap->pmp_link[i]);
/* scan for new ones */
ata_scsi_scan_host(ap, 0);
@@ -3163,27 +3317,42 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
{
struct ata_port *ap = ata_shost_to_port(shost);
unsigned long flags;
- int rc = 0;
+ int devno, rc = 0;
if (!ap->ops->error_handler)
return -EOPNOTSUPP;
- if ((channel != SCAN_WILD_CARD && channel != 0) ||
- (lun != SCAN_WILD_CARD && lun != 0))
+ if (lun != SCAN_WILD_CARD && lun)
return -EINVAL;
+ if (ap->nr_pmp_links == 0) {
+ if (channel != SCAN_WILD_CARD && channel)
+ return -EINVAL;
+ devno = id;
+ } else {
+ if (id != SCAN_WILD_CARD && id)
+ return -EINVAL;
+ devno = channel;
+ }
+
spin_lock_irqsave(ap->lock, flags);
- if (id == SCAN_WILD_CARD) {
- ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ if (devno == SCAN_WILD_CARD) {
+ struct ata_link *link;
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_info *ehi = &link->eh_info;
+ ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ }
} else {
- struct ata_device *dev = ata_find_dev(ap, id);
+ struct ata_device *dev = ata_find_dev(ap, devno);
if (dev) {
- ap->eh_info.probe_mask |= 1 << dev->devno;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
- ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
+ ehi->probe_mask |= 1 << dev->devno;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
@@ -3214,24 +3383,26 @@ void ata_scsi_dev_rescan(struct work_struct *work)
{
struct ata_port *ap =
container_of(work, struct ata_port, scsi_rescan_task);
+ struct ata_link *link;
+ struct ata_device *dev;
unsigned long flags;
- unsigned int i;
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- struct scsi_device *sdev = dev->sdev;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev = dev->sdev;
- if (!ata_dev_enabled(dev) || !sdev)
- continue;
- if (scsi_device_get(sdev))
- continue;
+ if (!ata_dev_enabled(dev) || !sdev)
+ continue;
+ if (scsi_device_get(sdev))
+ continue;
- spin_unlock_irqrestore(ap->lock, flags);
- scsi_rescan_device(&(sdev->sdev_gendev));
- scsi_device_put(sdev);
- spin_lock_irqsave(ap->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
+ scsi_rescan_device(&(sdev->sdev_gendev));
+ scsi_device_put(sdev);
+ spin_lock_irqsave(ap->lock, flags);
+ }
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -3359,7 +3530,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
{
ata_scsi_sdev_config(sdev);
- ata_scsi_dev_config(sdev, ap->device);
+ ata_scsi_dev_config(sdev, ap->link.device);
return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
@@ -3382,8 +3553,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
ata_scsi_dump_cdb(ap, cmd);
- if (likely(ata_scsi_dev_enabled(ap->device)))
- rc = __ata_scsi_queuecmd(cmd, done, ap->device);
+ if (likely(ata_scsi_dev_enabled(ap->link.device)))
+ rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
else {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 8023167bbbe..026439e05af 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap)
return tmp;
}
-u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
-
-/**
- * ata_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Wait up to 10 ms for legacy IDE device to become idle (BUSY
- * or BUSY+DRQ clear). Obtain dma status and port status from
- * device. Clear the interrupt. Return port status.
- *
- * LOCKING:
- */
-
-u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat = 0, post_stat = 0, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ap->ioaddr.bmdma_addr) {
- /* get controller status; clear intr, err bits */
- host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
- ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- }
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
- return status;
-}
-
-u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
-
/**
* ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -445,7 +405,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
unsigned long flags;
int thaw = 0;
- qc = __ata_qc_from_tag(ap, ap->active_tag);
+ qc = __ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
qc = NULL;
@@ -500,7 +460,7 @@ void ata_bmdma_error_handler(struct ata_port *ap)
ata_reset_fn_t hardreset;
hardreset = NULL;
- if (sata_scr_valid(ap))
+ if (sata_scr_valid(&ap->link))
hardreset = sata_std_hardreset;
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
@@ -607,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host)
if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
(ioread8(bmdma + 2) & 0x80))
host->flags |= ATA_HOST_SIMPLEX;
+
+ ata_port_desc(ap, "bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
}
return 0;
@@ -674,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host)
((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, base),
+ (unsigned long long)pci_resource_start(pdev, base + 1));
+
mask |= 1 << i;
}
@@ -844,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
- host->irq = pdev->irq;
+
+ ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+ ata_port_desc(host->ports[1], "irq %d", pdev->irq);
} else {
if (!ata_port_is_dummy(host->ports[0])) {
- host->irq = ATA_PRIMARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq,
+ rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[0], "irq %d",
+ ATA_PRIMARY_IRQ(pdev));
}
if (!ata_port_is_dummy(host->ports[1])) {
- host->irq2 = ATA_SECONDARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq2,
+ rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[1], "irq %d",
+ ATA_SECONDARY_IRQ(pdev));
}
}
@@ -909,7 +882,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer
/* Filter out DMA modes if the device has been configured by
the BIOS as PIO only */
- if (adev->ap->ioaddr.bmdma_addr == 0)
+ if (adev->link->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 564cd234c80..90df58a3edc 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,6 +29,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
+#define DRV_VERSION "3.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -56,6 +57,7 @@ extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
+extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
@@ -67,21 +69,23 @@ extern void ata_dev_disable(struct ata_device *dev);
extern void ata_port_flush_task(struct ata_port *ap);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen);
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout);
extern unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
- unsigned int n_elem);
+ unsigned int n_elem, unsigned long timeout);
extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id);
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -92,17 +96,21 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd(struct ata_link *link);
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 struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
extern void ata_acpi_associate(struct ata_host *host);
extern int ata_acpi_on_suspend(struct ata_port *ap);
extern void ata_acpi_on_resume(struct ata_port *ap);
extern int ata_acpi_on_devcfg(struct ata_device *adev);
#else
+static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
static inline void ata_acpi_associate(struct ata_host *host) { }
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -114,6 +122,7 @@ 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, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen);
@@ -147,12 +156,32 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
/* libata-eh.c */
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
new file mode 100644
index 00000000000..5d3920f6fd6
--- /dev/null
+++ b/drivers/ata/pata_acpi.c
@@ -0,0 +1,395 @@
+/*
+ * ACPI PATA driver
+ *
+ * (c) 2007 Red Hat <alan@redhat.com>
+ */
+
+#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 <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_acpi"
+#define DRV_VERSION "0.2.3"
+
+struct pata_acpi {
+ struct ata_acpi_gtm gtm;
+ void *last;
+ unsigned long mask[2];
+};
+
+/**
+ * pacpi_pre_reset - check for 40/80 pin
+ * @ap: Port
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the PATA port setup we need.
+ */
+
+static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pata_acpi *acpi = ap->private_data;
+ if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+ return -ENODEV;
+
+ return ata_std_prereset(link, deadline);
+}
+
+/**
+ * pacpi_cable_detect - cable type detection
+ * @ap: port to detect
+ *
+ * Perform device specific cable detection
+ */
+
+static int pacpi_cable_detect(struct ata_port *ap)
+{
+ struct pata_acpi *acpi = ap->private_data;
+
+ if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * pacpi_error_handler - Setup and error handler
+ * @ap: Port to handle
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pacpi_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+/* Welcome to ACPI, bring a bucket */
+static const unsigned int pio_cycle[7] = {
+ 600, 383, 240, 180, 120, 100, 80
+};
+static const unsigned int mwdma_cycle[5] = {
+ 480, 150, 120, 100, 80
+};
+static const unsigned int udma_cycle[7] = {
+ 120, 80, 60, 45, 30, 20, 15
+};
+
+/**
+ * pacpi_discover_modes - filter non ACPI modes
+ * @adev: ATA device
+ * @mask: proposed modes
+ *
+ * Try the modes available and see which ones the ACPI method will
+ * set up sensibly. From this we get a mask of ACPI modes we can use
+ */
+
+static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+ int i;
+ u32 t;
+ unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
+
+ struct ata_acpi_gtm probe;
+
+ probe = acpi->gtm;
+
+ /* We always use the 0 slot for crap hardware */
+ if (!(probe.flags & 0x10))
+ unit = 0;
+
+ ata_acpi_gtm(ap, &probe);
+
+ /* Start by scanning for PIO modes */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].pio;
+ if (t <= pio_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
+ break;
+ }
+ }
+
+ /* See if we have MWDMA or UDMA data. We don't bother with MWDMA
+ if UDMA is availabe as this means the BIOS set UDMA and our
+ error changedown if it works is UDMA to PIO anyway */
+ if (probe.flags & (1 << (2 * unit))) {
+ /* MWDMA */
+ for (i = 0; i < 5; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= mwdma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
+ break;
+ }
+ }
+ } else {
+ /* UDMA */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= udma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
+ break;
+ }
+ }
+ }
+ if (mask & (0xF8 << ATA_SHIFT_UDMA))
+ ap->cbl = ATA_CBL_PATA80;
+ return mask;
+}
+
+/**
+ * pacpi_mode_filter - mode filter for ACPI
+ * @adev: device
+ * @mask: mask of valid modes
+ *
+ * Filter the valid mode list according to our own specific rules, in
+ * this case the list of discovered valid modes obtained by ACPI probing
+ */
+
+static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ struct pata_acpi *acpi = adev->link->ap->private_data;
+ return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]);
+}
+
+/**
+ * pacpi_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if(!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if(!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+ acpi->gtm.flags |= (1 << (2 * unit));
+ } else {
+ acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+ acpi->gtm.flags &= ~(1 << (2 * unit));
+ }
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary.
+ */
+
+static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if (acpi->gtm.flags & 0x10)
+ return ata_qc_issue_prot(qc);
+
+ if (adev != acpi->last) {
+ pacpi_set_piomode(ap, adev);
+ if (adev->dma_mode)
+ pacpi_set_dmamode(ap, adev);
+ acpi->last = adev;
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * pacpi_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * Use the port_start hook to maintain private control structures
+ */
+
+static int pacpi_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pata_acpi *acpi;
+
+ int ret;
+
+ if (ap->acpi_handle == NULL)
+ return -ENODEV;
+
+ acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
+ if (ap->private_data == NULL)
+ return -ENOMEM;
+ acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
+ acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
+ ret = ata_sff_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct scsi_host_template pacpi_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,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pacpi_ops = {
+ .set_piomode = pacpi_set_piomode,
+ .set_dmamode = pacpi_set_dmamode,
+ .mode_filter = pacpi_mode_filter,
+
+ /* Task file is PCI ATA format, use helpers */
+ .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 = pacpi_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pacpi_cable_detect,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .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 = pacpi_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ /* Timeout handling */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = pacpi_port_start,
+};
+
+
+/**
+ * pacpi_init_one - Register ACPI ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in pacpi_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .sht = &pacpi_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+
+ .port_ops = &pacpi_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id pacpi_pci_tbl[] = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { } /* terminate list */
+};
+
+static struct pci_driver pacpi_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pacpi_pci_tbl,
+ .probe = pacpi_init_one,
+ .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+};
+
+static int __init pacpi_init(void)
+{
+ return pci_register_driver(&pacpi_pci_driver);
+}
+
+static void __exit pacpi_exit(void)
+{
+ pci_unregister_driver(&pacpi_pci_driver);
+}
+
+module_init(pacpi_init);
+module_exit(pacpi_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 32a10c99c06..364534e7aff 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = {
*/
static struct ata_port_operations ali_early_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -327,9 +326,8 @@ static struct ata_port_operations ali_early_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
@@ -337,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = {
* detect
*/
static struct ata_port_operations ali_20_port_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ali_20_filter,
@@ -369,16 +365,14 @@ static struct ata_port_operations ali_20_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect
*/
static struct ata_port_operations ali_c2_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -408,16 +402,14 @@ static struct ata_port_operations ali_c2_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect and LBA48
*/
static struct ata_port_operations ali_c5_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -446,9 +438,8 @@ static struct ata_port_operations ali_c5_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 04048fcf630..c5779ad4abc 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
}
/**
- * amd_probe_init - perform reset handling
- * @ap: ATA port
+ * amd_pre_reset - perform reset handling
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Reset sequence checking enable bits to see which ports are
* active.
*/
-static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits amd_enable_bits[] = {
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void amd_error_handler(struct ata_port *ap)
@@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* nv_probe_init - cable detection
- * @ap: ATA port
+ * @lin: ATA link
*
* Perform cable detection. The BIOS stores this in PCI config
* space for us.
*/
-static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int nv_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits nv_enable_bits[] = {
{ 0x50, 1, 0x02, 0x02 },
{ 0x50, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -268,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap)
pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
cbl = ATA_CBL_PATA80;
+ /* And a triple check across suspend/resume with ACPI around */
+ if (ata_acpi_cbl_80wire(ap))
+ cbl = ATA_CBL_PATA80;
return cbl;
}
@@ -327,7 +332,6 @@ static struct scsi_host_template amd_sht = {
};
static struct ata_port_operations amd33_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd33_set_piomode,
.set_dmamode = amd33_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -356,13 +360,11 @@ static struct ata_port_operations amd33_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd66_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd66_set_piomode,
.set_dmamode = amd66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -391,13 +393,11 @@ static struct ata_port_operations amd66_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd100_set_piomode,
.set_dmamode = amd100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -426,13 +426,11 @@ static struct ata_port_operations amd100_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd133_set_piomode,
.set_dmamode = amd133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -461,13 +459,11 @@ static struct ata_port_operations amd133_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv100_set_piomode,
.set_dmamode = nv100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -496,13 +492,11 @@ static struct ata_port_operations nv100_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv133_set_piomode,
.set_dmamode = nv133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -531,9 +525,8 @@ static struct ata_port_operations nv133_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index b5352ebecef..d4218310327 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -40,8 +40,9 @@
static int clock = 0;
-static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap)
/**
* artop6260_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* The ARTOP hardware reports the cable detect bits in register 0x49.
* Nothing complicated needed here.
*/
-static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Odd numbered device ids are the units with enable bits (the -R cards) */
if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -330,7 +332,6 @@ static struct scsi_host_template artop_sht = {
};
static const struct ata_port_operations artop6210_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6210_set_piomode,
.set_dmamode = artop6210_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -359,13 +360,11 @@ static const struct ata_port_operations artop6210_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations artop6260_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6260_set_piomode,
.set_dmamode = artop6260_set_dmamode,
@@ -392,9 +391,8 @@ static const struct ata_port_operations artop6260_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
new file mode 100644
index 00000000000..bb250a48e27
--- /dev/null
+++ b/drivers/ata/pata_at32.c
@@ -0,0 +1,441 @@
+/*
+ * AVR32 SMC/CFC PATA Driver
+ *
+ * Copyright (C) 2007 Atmel Norway
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/smc.h>
+
+#define DRV_NAME "pata_at32"
+#define DRV_VERSION "0.0.2"
+
+/*
+ * CompactFlash controller memory layout relative to the base address:
+ *
+ * Attribute memory: 0000 0000 -> 003f ffff
+ * Common memory: 0040 0000 -> 007f ffff
+ * I/O memory: 0080 0000 -> 00bf ffff
+ * True IDE Mode: 00c0 0000 -> 00df ffff
+ * Alt IDE Mode: 00e0 0000 -> 00ff ffff
+ *
+ * Only True IDE and Alt True IDE mode are needed for this driver.
+ *
+ * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc)
+ * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat)
+ */
+#define CF_IDE_OFFSET 0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_RES_SIZE 2048
+
+/*
+ * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA
+ * adaptor with a logic analyzer or similar.
+ */
+#undef DEBUG_BUS
+
+/*
+ * ATA PIO modes
+ *
+ * Name | Mb/s | Min cycle time | Mask
+ * --------+-------+----------------+--------
+ * Mode 0 | 3.3 | 600 ns | 0x01
+ * Mode 1 | 5.2 | 383 ns | 0x03
+ * Mode 2 | 8.3 | 240 ns | 0x07
+ * Mode 3 | 11.1 | 180 ns | 0x0f
+ * Mode 4 | 16.7 | 120 ns | 0x1f
+ */
+#define PIO_MASK (0x1f)
+
+/*
+ * Struct containing private information about device.
+ */
+struct at32_ide_info {
+ unsigned int irq;
+ struct resource res_ide;
+ struct resource res_alt;
+ void __iomem *ide_addr;
+ void __iomem *alt_addr;
+ unsigned int cs;
+ struct smc_config smc;
+};
+
+/*
+ * Setup SMC for the given ATA timing.
+ */
+static int pata_at32_setup_timing(struct device *dev,
+ struct at32_ide_info *info,
+ const struct ata_timing *timing)
+{
+ /* These two values are found through testing */
+ const int min_recover = 25;
+ const int ncs_hold = 15;
+
+ struct smc_config *smc = &info->smc;
+
+ int active;
+ int recover;
+
+ /* Total cycle time */
+ smc->read_cycle = timing->cyc8b;
+
+ /* DIOR <= CFIOR timings */
+ smc->nrd_setup = timing->setup;
+ smc->nrd_pulse = timing->act8b;
+
+ /* Compute recover, extend total cycle if needed */
+ active = smc->nrd_setup + smc->nrd_pulse;
+ recover = smc->read_cycle - active;
+
+ if (recover < min_recover) {
+ smc->read_cycle = active + min_recover;
+ recover = min_recover;
+ }
+
+ /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+ smc->ncs_read_setup = 0;
+ smc->ncs_read_pulse = active + ncs_hold;
+
+ /* Write timings same as read timings */
+ smc->write_cycle = smc->read_cycle;
+ smc->nwe_setup = smc->nrd_setup;
+ smc->nwe_pulse = smc->nrd_pulse;
+ smc->ncs_write_setup = smc->ncs_read_setup;
+ smc->ncs_write_pulse = smc->ncs_read_pulse;
+
+ /* Do some debugging output */
+ dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n",
+ smc->read_cycle, smc->nrd_setup, smc->nrd_pulse,
+ recover, smc->ncs_read_setup, smc->ncs_read_pulse,
+ smc->read_cycle - smc->ncs_read_pulse);
+
+ /* Finally, configure the SMC */
+ return smc_set_configuration(info->cs, smc);
+}
+
+/*
+ * Procedures for libATA.
+ */
+static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing timing;
+ struct at32_ide_info *info = ap->host->private_data;
+
+ int ret;
+
+ /* Compute ATA timing */
+ ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret);
+ return;
+ }
+
+ /* Setup SMC to ATA timing */
+ ret = pata_at32_setup_timing(ap->dev, info, &timing);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret);
+ return;
+ }
+}
+
+static void pata_at32_irq_clear(struct ata_port *ap)
+{
+ /* No DMA controller yet */
+}
+
+static struct scsi_host_template at32_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,
+};
+
+static struct ata_port_operations at32_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pata_at32_set_piomode,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+
+ .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,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_data_xfer,
+
+ .irq_clear = pata_at32_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = ata_sff_port_start,
+};
+
+static int __init pata_at32_init_one(struct device *dev,
+ struct at32_ide_info *info)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+
+ host = ata_host_alloc(dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+
+ /* Setup ATA bindings */
+ ap->ops = &at32_port_ops;
+ ap->pio_mask = PIO_MASK;
+ ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_PIO_POLLING;
+
+ /*
+ * Since all 8-bit taskfile transfers has to go on the lower
+ * byte of the data bus and there is a bug in the SMC that
+ * makes it impossible to alter the bus width during runtime,
+ * we need to hardwire the address signals as follows:
+ *
+ * A_IDE(2:0) <= A_EBI(3:1)
+ *
+ * This makes all addresses on the EBI even, thus all data
+ * will be on the lower byte of the data bus. All addresses
+ * used by libATA need to be altered according to this.
+ */
+ ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1);
+ ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1);
+
+ ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1);
+ ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1);
+ ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1);
+ ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1);
+ ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1);
+ ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1);
+ ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1);
+ ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1);
+ ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1);
+ ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1);
+
+ /* Set info as private data of ATA host */
+ host->private_data = info;
+
+ /* Register ATA device and return */
+ return ata_host_activate(host, info->irq, ata_interrupt,
+ IRQF_SHARED | IRQF_TRIGGER_RISING,
+ &at32_sht);
+}
+
+/*
+ * This function may come in handy for people analyzing their own
+ * EBI -> PATA adaptors.
+ */
+#ifdef DEBUG_BUS
+
+static void __init pata_at32_debug_bus(struct device *dev,
+ struct at32_ide_info *info)
+{
+ const int d1 = 0xff;
+ const int d2 = 0x00;
+
+ int i;
+
+ /* Write 8-bit values (registers) */
+ iowrite8(d1, info->alt_addr + (0x06 << 1));
+ iowrite8(d2, info->alt_addr + (0x06 << 1));
+
+ for (i = 0; i < 8; i++) {
+ iowrite8(d1, info->ide_addr + (i << 1));
+ iowrite8(d2, info->ide_addr + (i << 1));
+ }
+
+ /* Write 16 bit values (data) */
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+}
+
+#endif
+
+static int __init pata_at32_probe(struct platform_device *pdev)
+{
+ const struct ata_timing initial_timing =
+ {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+ struct device *dev = &pdev->dev;
+ struct at32_ide_info *info;
+ struct ide_platform_data *board = pdev->dev.platform_data;
+ struct resource *res;
+
+ int irq;
+ int ret;
+
+ if (!board)
+ return -ENXIO;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ /* Retrive IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Setup struct containing private infomation */
+ info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct at32_ide_info));
+
+ info->irq = irq;
+ info->cs = board->cs;
+
+ /* Request memory resources */
+ info->res_ide.start = res->start + CF_IDE_OFFSET;
+ info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1;
+ info->res_ide.name = "ide";
+ info->res_ide.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_ide);
+ if (ret)
+ goto err_req_res_ide;
+
+ info->res_alt.start = res->start + CF_ALT_IDE_OFFSET;
+ info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1;
+ info->res_alt.name = "alt";
+ info->res_alt.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_alt);
+ if (ret)
+ goto err_req_res_alt;
+
+ /* Setup non-timing elements of SMC */
+ info->smc.bus_width = 2; /* 16 bit data bus */
+ info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */
+ info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */
+ info->smc.nwait_mode = 3; /* NWAIT is in READY mode */
+ info->smc.byte_write = 0; /* Byte select access type */
+ info->smc.tdf_mode = 0; /* TDF optimization disabled */
+ info->smc.tdf_cycles = 0; /* No TDF wait cycles */
+
+ /* Setup ATA timing */
+ ret = pata_at32_setup_timing(dev, info, &initial_timing);
+ if (ret)
+ goto err_setup_timing;
+
+ /* Setup ATA addresses */
+ ret = -ENOMEM;
+ info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16);
+ info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16);
+ if (!info->ide_addr || !info->alt_addr)
+ goto err_ioremap;
+
+#ifdef DEBUG_BUS
+ pata_at32_debug_bus(dev, info);
+#endif
+
+ /* Register ATA device */
+ ret = pata_at32_init_one(dev, info);
+ if (ret)
+ goto err_ata_device;
+
+ return 0;
+
+ err_ata_device:
+ err_ioremap:
+ err_setup_timing:
+ release_resource(&info->res_alt);
+ err_req_res_alt:
+ release_resource(&info->res_ide);
+ err_req_res_ide:
+ kfree(info);
+
+ return ret;
+}
+
+static int __exit pata_at32_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct at32_ide_info *info;
+
+ if (!host)
+ return 0;
+
+ info = host->private_data;
+ ata_host_detach(host);
+
+ if (!info)
+ return 0;
+
+ release_resource(&info->res_ide);
+ release_resource(&info->res_alt);
+
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver pata_at32_driver = {
+ .remove = __exit_p(pata_at32_remove),
+ .driver = {
+ .name = "at32_ide",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pata_at32_init(void)
+{
+ return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
+}
+
+static void __exit pata_at32_exit(void)
+{
+ platform_driver_unregister(&pata_at32_driver);
+}
+
+module_init(pata_at32_init);
+module_exit(pata_at32_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
+MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 86f85a2cab7..9623f529553 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -33,8 +33,9 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
static const struct pci_bits atiixp_enable_bits[] = {
{ 0x48, 1, 0x01, 0x00 },
{ 0x48, 1, 0x08, 0x00 }
@@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void atiixp_error_handler(struct ata_port *ap)
@@ -172,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* When DMA begins we need to ensure that the UDMA control
* register for the channel is correctly set.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
@@ -198,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
*
* DMA has completed. Clear the UDMA flag as the next operations will
* be PIO ones not UDMA data transfer.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
@@ -232,7 +239,6 @@ static struct scsi_host_template atiixp_sht = {
};
static struct ata_port_operations atiixp_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = atiixp_set_piomode,
.set_dmamode = atiixp_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -261,9 +267,8 @@ static struct ata_port_operations atiixp_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
new file mode 100644
index 00000000000..747549e4563
--- /dev/null
+++ b/drivers/ata/pata_bf54x.c
@@ -0,0 +1,1627 @@
+/*
+ * File: drivers/ata/pata_bf54x.c
+ * Author: Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:
+ * Description: PATA Driver for blackfin 54x
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#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 <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME "pata-bf54x"
+#define DRV_VERSION "0.9"
+
+#define ATA_REG_CTRL 0x0E
+#define ATA_REG_ALTSTATUS ATA_REG_CTRL
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL 0x00
+#define ATAPI_OFFSET_STATUS 0x04
+#define ATAPI_OFFSET_DEV_ADDR 0x08
+#define ATAPI_OFFSET_DEV_TXBUF 0x0c
+#define ATAPI_OFFSET_DEV_RXBUF 0x10
+#define ATAPI_OFFSET_INT_MASK 0x14
+#define ATAPI_OFFSET_INT_STATUS 0x18
+#define ATAPI_OFFSET_XFER_LEN 0x1c
+#define ATAPI_OFFSET_LINE_STATUS 0x20
+#define ATAPI_OFFSET_SM_STATE 0x24
+#define ATAPI_OFFSET_TERMINATE 0x28
+#define ATAPI_OFFSET_PIO_TFRCNT 0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT 0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38
+#define ATAPI_OFFSET_REG_TIM_0 0x40
+#define ATAPI_OFFSET_PIO_TIM_0 0x44
+#define ATAPI_OFFSET_PIO_TIM_1 0x48
+#define ATAPI_OFFSET_MULTI_TIM_0 0x50
+#define ATAPI_OFFSET_MULTI_TIM_1 0x54
+#define ATAPI_OFFSET_MULTI_TIM_2 0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0 0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1 0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2 0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+ bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+ bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 3 4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s - SCLK = 133 MHz
+ * UDMA4 - 66 MB/s - SCLK >= 80 MHz
+ * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz
+ * UDMA2 - 33 MB/s - SCLK >= 40 MHz
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle */
+static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 };
+
+/**
+ * PIO timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW */
+static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 };
+/* DIOR/DIOW to end cycle */
+static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 };
+/* DIOW data hold */
+static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/* mode: 0 1 2 */
+/* Cycle Time */
+static const u32 mdma_t0min[] = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[] = { 215, 80, 70 };
+/* DMACK to read data released */
+static const u32 mdma_thmin[] = { 20, 15, 10 };
+/* DIOR/DIOW to DMACK hold */
+static const u32 mdma_tjmin[] = { 20, 5, 5 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkrmin[] = { 50, 50, 25 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkwmin[] = { 215, 50, 25 };
+/* CS[1:0] valid to DIOR/DIOW */
+static const u32 mdma_tmmin[] = { 50, 30, 25 };
+/* DMACK to read data released */
+static const u32 mdma_tzmax[] = { 20, 25, 25 };
+
+/**
+ * Ultra DMA timing table
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 };
+static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 };
+static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 };
+static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+/**
+ *
+ * Function: num_clocks_min
+ *
+ * Description:
+ * calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+ unsigned long fsclk)
+{
+ unsigned long tmp ;
+ unsigned short result;
+
+ tmp = tmin * (fsclk/1000/1000) / 1000;
+ result = (unsigned short)tmp;
+ if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {
+ result++;
+ }
+
+ return result;
+}
+
+/**
+ * bfin_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode = adev->pio_mode - XFER_PIO_0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int fsclk = get_sclk();
+ unsigned short teoc_reg, t2_reg, teoc_pio;
+ unsigned short t4_reg, t2_pio, t1_reg;
+ unsigned short n0, n6, t6min = 5;
+
+ /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+ * If one SCLK pulse is longer than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ n6 = num_clocks_min(t6min, fsclk);
+ if (mode >= 0 && mode <= 4 && n6 >= 1) {
+ pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ /* calculate the timing values for register transfers. */
+ while (mode > 0 && pio_fsclk[mode] > fsclk)
+ mode--;
+
+ /* DIOR/DIOW to end cycle time */
+ t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(reg_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_reg + teoc_reg < n0)
+ t2_reg = n0 - teoc_reg;
+
+ /* calculate the timing values for pio transfers. */
+
+ /* DIOR/DIOW to end cycle time */
+ t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(pio_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_pio + teoc_pio < n0)
+ t2_pio = n0 - teoc_pio;
+
+ /* Address valid to DIOR/DIORW */
+ t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+ /* DIOW data hold */
+ t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+ ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+ ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+ ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+ if (mode > 2) {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) | IORDY_EN);
+ } else {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+ }
+
+ /* Disable host ATAPI PIO interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+ SSYNC();
+ }
+}
+
+/**
+ * bfin_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned long fsclk = get_sclk();
+ unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;
+ unsigned short tm, td, tkr, tkw, teoc, th;
+ unsigned short n0, nf, tfmin = 5;
+ unsigned short nmin, tcyc;
+
+ mode = adev->dma_mode - XFER_UDMA_0;
+ if (mode >= 0 && mode <= 5) {
+ pr_debug("set udmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is t6 and tc,
+ * the DIOW - data hold. If one SCLK pulse is longer
+ * than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ while (mode > 0 && udma_fsclk[mode] > fsclk)
+ mode--;
+
+ nmin = num_clocks_min(udma_tmin[mode], fsclk);
+ if (nmin >= 1) {
+ /* calculate the timing values for Ultra DMA. */
+ tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);
+ tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);
+ tcyc_tdvs = 2;
+
+ /* increase tcyc - tdvs (tcyc_tdvs) until we meed
+ * the minimum cycle length
+ */
+ if (tdvs + tcyc_tdvs < tcyc)
+ tcyc_tdvs = tcyc - tdvs;
+
+ /* Mow assign the values required for the timing
+ * registers
+ */
+ if (tcyc_tdvs < 2)
+ tcyc_tdvs = 2;
+
+ if (tdvs < 2)
+ tdvs = 2;
+
+ tack = num_clocks_min(udma_tackmin, fsclk);
+ tss = num_clocks_min(udma_tssmin, fsclk);
+ tmli = num_clocks_min(udma_tmlimin, fsclk);
+ tzah = num_clocks_min(udma_tzahmin, fsclk);
+ trp = num_clocks_min(udma_trpmin[mode], fsclk);
+ tenv = num_clocks_min(udma_tenvmin, fsclk);
+ if (tenv <= udma_tenvmax[mode]) {
+ ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));
+ ATAPI_SET_ULTRA_TIM_1(base,
+ (tcyc_tdvs<<8 | tdvs));
+ ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
+ ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
+
+ /* Enable host ATAPI Untra DMA interrupts */
+ ATAPI_SET_INT_MASK(base,
+ ATAPI_GET_INT_MASK(base)
+ | UDMAIN_DONE_MASK
+ | UDMAOUT_DONE_MASK
+ | UDMAIN_TERM_MASK
+ | UDMAOUT_TERM_MASK);
+ }
+ }
+ }
+
+ mode = adev->dma_mode - XFER_MW_DMA_0;
+ if (mode >= 0 && mode <= 2) {
+ pr_debug("set mdmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is tf, the DMACK to
+ * read data released. If one SCLK pulse is longer than
+ * this maximum value then the MDMA mode
+ * cannot be supported at this frequency.
+ */
+ while (mode > 0 && mdma_fsclk[mode] > fsclk)
+ mode--;
+
+ nf = num_clocks_min(tfmin, fsclk);
+ if (nf >= 1) {
+ /* calculate the timing values for Multi-word DMA. */
+
+ /* DIOR/DIOW asserted pulse width */
+ td = num_clocks_min(mdma_tdmin[mode], fsclk);
+
+ /* DIOR negated pulse width */
+ tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);
+
+ /* Cycle Time */
+ n0 = num_clocks_min(mdma_t0min[mode], fsclk);
+
+ /* increase tk until we meed the minimum cycle length */
+ if (tkw + td < n0)
+ tkw = n0 - td;
+
+ /* DIOR negated pulse width - read */
+ tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);
+ /* CS{1:0] valid to DIOR/DIOW */
+ tm = num_clocks_min(mdma_tmmin[mode], fsclk);
+ /* DIOR/DIOW to DMACK hold */
+ teoc = num_clocks_min(mdma_tjmin[mode], fsclk);
+ /* DIOW Data hold */
+ th = num_clocks_min(mdma_thmin[mode], fsclk);
+
+ ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
+ ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
+ ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
+
+ /* Enable host ATAPI Multi DMA interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ | MULTI_DONE_MASK | MULTI_TERM_MASK);
+ SSYNC();
+ }
+ }
+ return;
+}
+
+/**
+ *
+ * Function: wait_complete
+ *
+ * Description: Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+ unsigned short status;
+ unsigned int i = 0;
+
+#define PATA_BF54X_WAIT_TIMEOUT 10000
+
+ for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {
+ status = ATAPI_GET_INT_STATUS(base) & mask;
+ if (status)
+ break;
+ }
+
+ ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ * Function: write_atapi_register
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+ unsigned long ata_reg, unsigned short value)
+{
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, value);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ * Function: read_atapi_register
+ *
+ *Description: Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+ unsigned long ata_reg)
+{
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ * Function: write_atapi_register_data
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT
+ * interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+ }
+}
+
+/**
+ *
+ * Function: read_atapi_register_data
+ *
+ * Description: Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ buf[i] = ATAPI_GET_DEV_RXBUF(base);
+ }
+}
+
+/**
+ * bfin_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_tf_load().
+ */
+
+static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_FEATURE,
+ tf->hob_feature);
+ write_atapi_register(base, ATA_REG_NSECT,
+ tf->hob_nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+ pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+ "0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ write_atapi_register(base, ATA_REG_FEATURE, tf->feature);
+ write_atapi_register(base, ATA_REG_NSECT, tf->nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+ pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+ pr_debug("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * bfin_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ * bfin_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Note: Original code is ata_tf_read().
+ */
+
+static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ tf->command = bfin_check_status(ap);
+ tf->feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->lbah = read_atapi_register(base, ATA_REG_LBAH);
+ tf->device = read_atapi_register(base, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);
+ tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);
+ }
+}
+
+/**
+ * bfin_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_exec_command().
+ */
+
+static void bfin_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ write_atapi_register(base, ATA_REG_CMD, tf->command);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_check_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ * bfin_std_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Note: Original code is ata_std_dev_select().
+ */
+
+static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ write_atapi_register(base, ATA_REG_DEVICE, tmp);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_bmdma_setup - Set up IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_setup().
+ */
+
+static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ unsigned short config = WDSIZE_16;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma setup\n");
+ /* Program the ATA_CTRL register with dir */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_TX, config);
+ set_dma_x_modify(CH_ATAPI_TX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
+ }
+ } else {
+ config |= WNR;
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_RX, config);
+ set_dma_x_modify(CH_ATAPI_RX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
+ }
+ }
+}
+
+/**
+ * bfin_bmdma_start - Start an IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* start ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be flushed if WB
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ flush_dcache_range(sg_dma_address(sg),
+ sg_dma_address(sg) + sg_dma_len(sg));
+ }
+ enable_dma(CH_ATAPI_TX);
+ pr_debug("enable udma write\n");
+
+ /* Send ATA DMA write command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA write direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ | XFER_DIR));
+ } else {
+ enable_dma(CH_ATAPI_RX);
+ pr_debug("enable udma read\n");
+
+ /* Send ATA DMA read command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA read direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ & ~XFER_DIR));
+ }
+
+ /* Reset all transfer count */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
+
+ /* Set transfer length to buffer len */
+ ata_for_each_sg(sg, qc) {
+ ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
+ }
+
+ /* Enable ATA DMA operation*/
+ if (ap->udma_mask)
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | ULTRA_START);
+ else
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | MULTI_START);
+}
+
+/**
+ * bfin_bmdma_stop - Stop IDE DMA transfer
+ * @qc: Command we are ending DMA for
+ */
+
+static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma stop\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* stop ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ disable_dma(CH_ATAPI_TX);
+ else {
+ disable_dma(CH_ATAPI_RX);
+ if (ap->hsm_task_state & HSM_ST_LAST) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be invalidated if
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ invalidate_dcache_range(
+ sg_dma_address(sg),
+ sg_dma_address(sg)
+ + sg_dma_len(sg));
+ }
+ }
+ }
+}
+
+/**
+ * bfin_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, device);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+ write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * bfin_bus_post_reset - PATA device post reset
+ *
+ * Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ unsigned long timeout;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ timeout = jiffies + ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, 1);
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ }
+ if (dev1)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ bfin_std_dev_select(ap, 0);
+ if (dev1)
+ bfin_std_dev_select(ap, 1);
+ if (dev0)
+ bfin_std_dev_select(ap, 0);
+}
+
+/**
+ * bfin_bus_softreset - PATA device software reset
+ *
+ * Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+ unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* software reset. causes dev0 to be selected */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (bfin_check_status(ap) == 0xFF)
+ return 0;
+
+ bfin_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * bfin_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Note: Original code is ata_std_softreset().
+ */
+
+static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline)
+{
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ if (ata_port_offline(ap)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (bfin_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && bfin_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ bfin_std_dev_select(ap, 0);
+
+ /* issue bus reset */
+ err_mask = bfin_bus_softreset(ap, devmask);
+ if (err_mask) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(ap, 0, &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+ return 0;
+}
+
+/**
+ * bfin_bmdma_status - Read IDE DMA status
+ * @ap: Port associated with this ATA transaction.
+ */
+
+static unsigned char bfin_bmdma_status(struct ata_port *ap)
+{
+ unsigned char host_stat = 0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+
+ if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+ host_stat = ATA_DMA_ACTIVE;
+ }
+ if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+ host_stat = ATA_DMA_INTR;
+ }
+ if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+ host_stat = ATA_DMA_ERR;
+ }
+
+ return host_stat;
+}
+
+/**
+ * bfin_data_xfer - Transfer data by PIO
+ * @adev: device for this I/O
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Note: Original code is ata_data_xfer().
+ */
+
+static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ unsigned int words = buflen >> 1;
+ unsigned short *buf16 = (u16 *) buf;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data) {
+ write_atapi_data(base, words, buf16);
+ } else {
+ read_atapi_data(base, words, buf16);
+ }
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned short align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ write_atapi_data(base, 1, align_buf);
+ } else {
+ read_atapi_data(base, 1, align_buf);
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * bfin_irq_clear - Clear ATAPI interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi irq clear\n");
+ ATAPI_SET_INT_STATUS(base, 0x1FF);
+}
+
+/**
+ * bfin_irq_on - Enable interrupts on a port.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_on().
+ */
+
+static unsigned char bfin_irq_on(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ pr_debug("in atapi irq on\n");
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ tmp = ata_wait_idle(ap);
+
+ bfin_irq_clear(ap);
+
+ return tmp;
+}
+
+/**
+ * bfin_irq_ack - Acknowledge a device interrupt.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_ack().
+ */
+
+static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ unsigned char status;
+
+ pr_debug("in atapi irq ack\n");
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ dev_err(ap->dev, "abnormal status 0x%X\n", status);
+
+ /* get controller status; clear intr, err bits */
+ ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+ | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+
+ return bfin_bmdma_status(ap);
+}
+
+/**
+ * bfin_bmdma_freeze - Freeze DMA controller port
+ * @ap: port to freeze
+ *
+ * Note: Original code is ata_bmdma_freeze().
+ */
+
+static void bfin_bmdma_freeze(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi dma freeze\n");
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* Under certain circumstances, some controllers raise IRQ on
+ * ATA_NIEN manipulation. Also, many controllers fail to mask
+ * previously pending IRQ on ATA_NIEN assertion. Clear it.
+ */
+ ata_chk_status(ap);
+
+ bfin_irq_clear(ap);
+}
+
+/**
+ * bfin_bmdma_thaw - Thaw DMA controller port
+ * @ap: port to thaw
+ *
+ * Note: Original code is ata_bmdma_thaw().
+ */
+
+void bfin_bmdma_thaw(struct ata_port *ap)
+{
+ bfin_check_status(ap);
+ bfin_irq_clear(ap);
+ bfin_irq_on(ap);
+}
+
+/**
+ * bfin_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * Note: Original code is ata_std_postreset().
+ */
+
+static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* re-enable interrupts */
+ bfin_irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ return;
+ }
+
+ /* set up device control */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+}
+
+/**
+ * bfin_error_handler - Stock error handler for DMA controller
+ * @ap: port to handle error for
+ */
+
+static void bfin_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,
+ bfin_std_postreset);
+}
+
+static void bfin_port_stop(struct ata_port *ap)
+{
+ pr_debug("in atapi port stop\n");
+ if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+ free_dma(CH_ATAPI_RX);
+ free_dma(CH_ATAPI_TX);
+ }
+}
+
+static int bfin_port_start(struct ata_port *ap)
+{
+ pr_debug("in atapi port start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return 0;
+
+ if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
+ if (request_dma(CH_ATAPI_TX,
+ "BFIN ATAPI TX DMA") >= 0)
+ return 0;
+
+ free_dma(CH_ATAPI_RX);
+ }
+
+ ap->udma_mask = 0;
+ ap->mwdma_mask = 0;
+ dev_err(ap->dev, "Unable to request ATAPI DMA!"
+ " Continue in PIO mode.\n");
+
+ return 0;
+}
+
+static struct scsi_host_template bfin_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 = SG_NONE,
+ .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 const struct ata_port_operations bfin_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = bfin_set_piomode,
+ .set_dmamode = bfin_set_dmamode,
+
+ .tf_load = bfin_tf_load,
+ .tf_read = bfin_tf_read,
+ .exec_command = bfin_exec_command,
+ .check_status = bfin_check_status,
+ .check_altstatus = bfin_check_altstatus,
+ .dev_select = bfin_std_dev_select,
+
+ .bmdma_setup = bfin_bmdma_setup,
+ .bmdma_start = bfin_bmdma_start,
+ .bmdma_stop = bfin_bmdma_stop,
+ .bmdma_status = bfin_bmdma_status,
+ .data_xfer = bfin_data_xfer,
+
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .freeze = bfin_bmdma_freeze,
+ .thaw = bfin_bmdma_thaw,
+ .error_handler = bfin_error_handler,
+ .post_internal_cmd = bfin_bmdma_stop,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = bfin_irq_clear,
+ .irq_on = bfin_irq_on,
+ .irq_ack = bfin_irq_ack,
+
+ .port_start = bfin_port_start,
+ .port_stop = bfin_port_stop,
+};
+
+static struct ata_port_info bfin_port_info[] = {
+ {
+ .sht = &bfin_sht,
+ .flags = ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_MMIO
+ | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0,
+#ifdef CONFIG_PATA_BF54X_DMA
+ .udma_mask = ATA_UDMA5,
+#else
+ .udma_mask = 0,
+#endif
+ .port_ops = &bfin_pata_ops,
+ },
+};
+
+/**
+ * bfin_reset_controller - initialize BF54x ATAPI controller.
+ */
+
+static int bfin_reset_controller(struct ata_host *host)
+{
+ void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;
+ int count;
+ unsigned short status;
+
+ /* Disable all ATAPI interrupts */
+ ATAPI_SET_INT_MASK(base, 0);
+ SSYNC();
+
+ /* Assert the RESET signal 25us*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+ udelay(30);
+
+ /* Negate the RESET signal for 2ms*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+ msleep(2);
+
+ /* Wait on Busy flag to clear */
+ count = 10000000;
+ do {
+ status = read_atapi_register(base, ATA_REG_STATUS);
+ } while (count-- && (status & ATA_BUSY));
+
+ /* Enable only ATAPI Device interrupt */
+ ATAPI_SET_INT_MASK(base, 1);
+ SSYNC();
+
+ return (!count);
+}
+
+/**
+ * atapi_io_port - define atapi peripheral port pins.
+ */
+static unsigned short atapi_io_port[] = {
+ P_ATAPI_RESET,
+ P_ATAPI_DIOR,
+ P_ATAPI_DIOW,
+ P_ATAPI_CS0,
+ P_ATAPI_CS1,
+ P_ATAPI_DMACK,
+ P_ATAPI_DMARQ,
+ P_ATAPI_INTRQ,
+ P_ATAPI_IORDY,
+ 0
+};
+
+/**
+ * bfin_atapi_probe - attach a bfin atapi interface
+ * @pdev: platform device
+ *
+ * Register a bfin atapi interface.
+ *
+ *
+ * Platform devices are expected to contain 2 resources per port:
+ *
+ * - I/O Base (IORESOURCE_IO)
+ * - IRQ (IORESOURCE_IRQ)
+ *
+ */
+static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+{
+ int board_idx = 0;
+ struct resource *res;
+ struct ata_host *host;
+ const struct ata_port_info *ppi[] =
+ { &bfin_port_info[board_idx], NULL };
+
+ /*
+ * Simple resource validation ..
+ */
+ if (unlikely(pdev->num_resources != 2)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Get the register base first
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ /*
+ * Now that that's out of the way, wire up the port..
+ */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
+ if (!host)
+ return -ENOMEM;
+
+ host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
+
+ if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
+ dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+ return -EFAULT;
+ }
+
+ if (bfin_reset_controller(host)) {
+ peripheral_free_list(atapi_io_port);
+ dev_err(&pdev->dev, "Fail to reset ATAPI device\n");
+ return -EFAULT;
+ }
+
+ if (ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ peripheral_free_list(atapi_io_port);
+ dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * bfin_atapi_remove - unplug a bfin atapi interface
+ * @pdev: platform device
+ *
+ * A bfin atapi device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_detach(host);
+
+ peripheral_free_list(atapi_io_port);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+int bfin_atapi_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+static struct platform_driver bfin_atapi_driver = {
+ .probe = bfin_atapi_probe,
+ .remove = __devexit_p(bfin_atapi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
+#endif
+ },
+};
+
+static int __init bfin_atapi_init(void)
+{
+ pr_info("register bfin atapi driver\n");
+ return platform_driver_register(&bfin_atapi_driver);
+}
+
+static void __exit bfin_atapi_exit(void)
+{
+ platform_driver_unregister(&bfin_atapi_driver);
+}
+
+module_init(bfin_atapi_init);
+module_exit(bfin_atapi_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 0feb5ae8c48..43d198f9096 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -153,7 +153,7 @@ 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);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = {
};
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,
@@ -213,7 +212,6 @@ static struct ata_port_operations cmd640_port_ops = {
.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,
};
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e34b632487d..9e412c26b2a 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.2.5"
/*
* CMD64x specific registers definition.
@@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap)
}
/**
- * cmd64x_set_piomode - set initial PIO mode data
+ * cmd64x_set_piomode - set PIO and MWDMA timing
* @ap: ATA interface
* @adev: ATA device
+ * @mode: mode
*
- * Called to do the PIO mode setup.
+ * Called to do the PIO and MWDMA mode setup.
*/
-static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_timing t;
@@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
int arttim = arttim_port[ap->port_no][adev->devno];
int drwtim = drwtim_port[ap->port_no][adev->devno];
-
- if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ /* ata_timing_compute is smart and will produce timings for MWDMA
+ that don't violate the drives PIO capabilities. */
+ if (ata_timing_compute(adev, mode, &t, T, 0) < 0) {
printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
return;
}
@@ -168,6 +170,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
/**
+ * cmd64x_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Used when configuring the devices ot set the PIO timings. All the
+ * actual work is done by the PIO/MWDMA setting helper
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ cmd64x_set_timing(ap, adev, adev->pio_mode);
+}
+
+/**
* cmd64x_set_dmamode - set initial DMA mode data
* @ap: ATA interface
* @adev: ATA device
@@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
static const u8 udma_data[] = {
0x30, 0x20, 0x10, 0x20, 0x10, 0x00
};
- static const u8 mwdma_data[] = {
- 0x30, 0x20, 0x10
- };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 regU, regD;
@@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
regU |= 1 << adev->devno; /* UDMA on */
if (adev->dma_mode > 2) /* 15nS timing */
regU |= 4 << adev->devno;
- } else
- regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+ } else {
+ regU &= ~ (1 << adev->devno); /* UDMA off */
+ cmd64x_set_timing(ap, adev, adev->dma_mode);
+ }
regD |= 0x20 << adev->devno;
@@ -269,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = {
};
static struct ata_port_operations cmd64x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -298,13 +312,11 @@ static struct ata_port_operations cmd64x_port_ops = {
.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_port_operations cmd646r1_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -333,13 +345,11 @@ static struct ata_port_operations cmd646r1_port_ops = {
.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_port_operations cmd648_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -368,7 +378,6 @@ static struct ata_port_operations cmd648_port_ops = {
.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,
};
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index e2459088cdc..33f7f0843f4 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = {
};
static struct ata_port_operations cs5520_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5520_set_piomode,
.set_dmamode = cs5520_set_dmamode,
@@ -184,13 +183,14 @@ static struct ata_port_operations cs5520_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
+ static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
struct ata_port_info pi = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
@@ -244,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
}
/* 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[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
+ iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
iomap[4] = pcim_iomap(pdev, 2, 0);
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
@@ -260,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4];
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[0],
+ "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
+ ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
+
ioaddr = &host->ports[1]->ioaddr;
ioaddr->cmd_addr = iomap[2];
ioaddr->ctl_addr = iomap[3];
@@ -267,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4] + 8;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[1],
+ "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
+ ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
+
/* activate the host */
pci_set_master(pdev);
rc = ata_host_start(host);
@@ -285,33 +293,12 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
if (rc)
return rc;
- if (i == 0)
- host->irq = irq[0];
- else
- host->irq2 = irq[1];
+ ata_port_desc(ap, "irq %d", irq[i]);
}
return ata_host_register(host, &cs5520_sht);
}
-/**
- * cs5520_remove_one - device unload
- * @pdev: PCI device being removed
- *
- * Handle an unplug/unload event for a PCI device. Unload the
- * PCI driver but do not use the default handler as we manage
- * resources ourself and *MUST NOT* disable the device as it has
- * other functions.
- */
-
-static void __devexit cs5520_remove_one(struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_detach(host);
-}
-
#ifdef CONFIG_PM
/**
* cs5520_reinit_one - device resume
@@ -368,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = {
.name = DRV_NAME,
.id_table = pata_cs5520,
.probe = cs5520_init_one,
- .remove = cs5520_remove_one,
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = cs5520_pci_device_suspend,
.resume = cs5520_reinit_one,
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index eaaea848b64..57e827e4109 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = {
};
static struct ata_port_operations cs5530_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5530_set_piomode,
.set_dmamode = cs5530_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -209,9 +208,8 @@ static struct ata_port_operations cs5530_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct dmi_system_id palmax_dmi_table[] = {
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 360b6f32e17..3578593a882 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = {
};
static struct ata_port_operations cs5535_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5535_set_piomode,
.set_dmamode = cs5535_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -206,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
new file mode 100644
index 00000000000..53070f6b1fc
--- /dev/null
+++ b/drivers/ata/pata_cs5536.c
@@ -0,0 +1,344 @@
+/*
+ * pata_cs5536.c - CS5536 PATA for new ATA layer
+ * (C) 2007 Martin K. Petersen <mkp@mkp.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ * Documentation:
+ * Available from AMD web site.
+ *
+ * The IDE timing registers for the CS5536 live in the Geode Machine
+ * Specific Register file and not PCI config space. Most BIOSes
+ * virtualize the PCI registers so the chip looks like a standard IDE
+ * controller. Unfortunately not all implementations get this right.
+ * In particular some have problems with unaligned accesses to the
+ * virtualized PCI registers. This driver always does full dword
+ * writes to work around the issue. Also, in case of a bad BIOS this
+ * driver can be loaded with the "msr=1" parameter which forces using
+ * the Machine Specific Registers to configure the device.
+ */
+
+#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 <linux/libata.h>
+#include <scsi/scsi_host.h>
+#include <asm/msr.h>
+
+#define DRV_NAME "pata_cs5536"
+#define DRV_VERSION "0.0.5"
+
+enum {
+ CFG = 0,
+ DTC = 1,
+ CAST = 2,
+ ETC = 3,
+
+ MSR_IDE_BASE = 0x51300000,
+ MSR_IDE_CFG = (MSR_IDE_BASE + 0x10),
+ MSR_IDE_DTC = (MSR_IDE_BASE + 0x12),
+ MSR_IDE_CAST = (MSR_IDE_BASE + 0x13),
+ MSR_IDE_ETC = (MSR_IDE_BASE + 0x14),
+
+ PCI_IDE_CFG = 0x40,
+ PCI_IDE_DTC = 0x48,
+ PCI_IDE_CAST = 0x4c,
+ PCI_IDE_ETC = 0x50,
+
+ IDE_CFG_CHANEN = 0x2,
+ IDE_CFG_CABLE = 0x10000,
+
+ IDE_D0_SHIFT = 24,
+ IDE_D1_SHIFT = 16,
+ IDE_DRV_MASK = 0xff,
+
+ IDE_CAST_D0_SHIFT = 6,
+ IDE_CAST_D1_SHIFT = 4,
+ IDE_CAST_DRV_MASK = 0x3,
+ IDE_CAST_CMD_MASK = 0xff,
+ IDE_CAST_CMD_SHIFT = 24,
+
+ IDE_ETC_NODMA = 0x03,
+};
+
+static int use_msr;
+
+static const u32 msr_reg[4] = {
+ MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
+};
+
+static const u8 pci_reg[4] = {
+ PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
+};
+
+static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val)
+{
+ if (unlikely(use_msr)) {
+ u32 dummy;
+
+ rdmsr(msr_reg[reg], *val, dummy);
+ return 0;
+ }
+
+ return pci_read_config_dword(pdev, pci_reg[reg], val);
+}
+
+static inline int cs5536_write(struct pci_dev *pdev, int reg, int val)
+{
+ if (unlikely(use_msr)) {
+ wrmsr(msr_reg[reg], val, 0);
+ return 0;
+ }
+
+ return pci_write_config_dword(pdev, pci_reg[reg], val);
+}
+
+/**
+ * cs5536_cable_detect - detect cable type
+ * @ap: Port to detect on
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform cable detection for ATA66 capable cable. Return a libata
+ * cable type.
+ */
+
+static int cs5536_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 cfg;
+
+ cs5536_read(pdev, CFG, &cfg);
+
+ if (cfg & (IDE_CFG_CABLE << ap->port_no))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * cs5536_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ */
+
+static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 drv_timings[5] = {
+ 0x98, 0x55, 0x32, 0x21, 0x20,
+ };
+
+ static const u8 addr_timings[5] = {
+ 0x2, 0x1, 0x0, 0x0, 0x0,
+ };
+
+ static const u8 cmd_timings[5] = {
+ 0x99, 0x92, 0x90, 0x22, 0x20,
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *pair = ata_dev_pair(adev);
+ int mode = adev->pio_mode - XFER_PIO_0;
+ int cmdmode = mode;
+ int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+ int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
+ u32 dtc, cast, etc;
+
+ if (pair)
+ cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
+
+ cs5536_read(pdev, DTC, &dtc);
+ cs5536_read(pdev, CAST, &cast);
+ cs5536_read(pdev, ETC, &etc);
+
+ dtc &= ~(IDE_DRV_MASK << dshift);
+ dtc |= drv_timings[mode] << dshift;
+
+ cast &= ~(IDE_CAST_DRV_MASK << cshift);
+ cast |= addr_timings[mode] << cshift;
+
+ cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
+ cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
+
+ etc &= ~(IDE_DRV_MASK << dshift);
+ etc |= IDE_ETC_NODMA << dshift;
+
+ cs5536_write(pdev, DTC, dtc);
+ cs5536_write(pdev, CAST, cast);
+ cs5536_write(pdev, ETC, etc);
+}
+
+/**
+ * cs5536_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ */
+
+static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 udma_timings[6] = {
+ 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
+ };
+
+ static const u8 mwdma_timings[3] = {
+ 0x67, 0x21, 0x20,
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 dtc, etc;
+ int mode = adev->dma_mode;
+ int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+
+ if (mode >= XFER_UDMA_0) {
+ cs5536_read(pdev, ETC, &etc);
+
+ etc &= ~(IDE_DRV_MASK << dshift);
+ etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
+
+ cs5536_write(pdev, ETC, etc);
+ } else { /* MWDMA */
+ cs5536_read(pdev, DTC, &dtc);
+
+ dtc &= ~(IDE_DRV_MASK << dshift);
+ dtc |= mwdma_timings[mode] << dshift;
+
+ cs5536_write(pdev, DTC, dtc);
+ }
+}
+
+static struct scsi_host_template cs5536_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,
+};
+
+static struct ata_port_operations cs5536_port_ops = {
+ .set_piomode = cs5536_set_piomode,
+ .set_dmamode = cs5536_set_dmamode,
+ .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 = cs5536_cable_detect,
+
+ .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 = ata_qc_issue_prot,
+
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_port_start,
+};
+
+/**
+ * cs5536_init_one
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ */
+
+static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .sht = &cs5536_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &cs5536_port_ops,
+ };
+
+ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ u32 cfg;
+
+ if (use_msr)
+ printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n");
+
+ cs5536_read(dev, CFG, &cfg);
+
+ if ((cfg & IDE_CFG_CHANEN) == 0) {
+ printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
+ return -ENODEV;
+ }
+
+ return ata_pci_init_one(dev, ppi);
+}
+
+static const struct pci_device_id cs5536[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
+ { },
+};
+
+static struct pci_driver cs5536_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5536,
+ .probe = cs5536_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init cs5536_init(void)
+{
+ return pci_register_driver(&cs5536_pci_driver);
+}
+
+static void __exit cs5536_exit(void)
+{
+ pci_unregister_driver(&cs5536_pci_driver);
+}
+
+MODULE_AUTHOR("Martin K. Petersen");
+MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5536);
+MODULE_VERSION(DRV_VERSION);
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+
+module_init(cs5536_init);
+module_exit(cs5536_exit);
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 6cbc8778bf4..fc5f9c4e5d8 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = {
};
static struct ata_port_operations cy82c693_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cy82c693_set_piomode,
.set_dmamode = cy82c693_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -158,9 +157,8 @@ static struct ata_port_operations cy82c693_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c8ba59c5611..043dcd35106 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -26,25 +26,26 @@
/**
* efar_pre_reset - Enable bits
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform cable detection for the EFAR ATA interface. This is
* different to the PIIX arrangement
*/
-static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int efar_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits efar_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
{ 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -250,7 +251,6 @@ static struct scsi_host_template efar_sht = {
};
static const struct ata_port_operations efar_ops = {
- .port_disable = ata_port_disable,
.set_piomode = efar_set_piomode,
.set_dmamode = efar_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -278,9 +278,8 @@ static const struct ata_port_operations efar_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 6f7d34ad19e..0713872cf65 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = {
*/
static struct ata_port_operations hpt366_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt366_set_piomode,
.set_dmamode = hpt366_set_dmamode,
.mode_filter = hpt366_filter,
@@ -342,9 +341,8 @@ static struct ata_port_operations hpt366_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index c5ddd937dbf..e61cb1fd57b 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
/**
* hpt37x_pre_reset - reset the hpt37x bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 370/372 and 374 func 0
*/
-static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
{
u8 scr2, ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -352,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap)
ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
-static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -360,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
};
u16 mcr3, mcr6;
u8 ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
@@ -387,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -642,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = {
*/
static struct ata_port_operations hpt370_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370_filter,
@@ -671,9 +672,8 @@ static struct ata_port_operations hpt370_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
@@ -681,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = {
*/
static struct ata_port_operations hpt370a_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370a_filter,
@@ -710,9 +709,8 @@ static struct ata_port_operations hpt370a_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
@@ -721,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = {
*/
static struct ata_port_operations hpt372_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -750,9 +747,8 @@ static struct ata_port_operations hpt372_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/*
@@ -761,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = {
*/
static struct ata_port_operations hpt374_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -790,9 +785,8 @@ static struct ata_port_operations hpt374_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index f8f234bfc8c..9f1c084f846 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
/**
* hpt3x2n_pre_reset - reset the hpt3x2n bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 3x2n series controllers.
* Reset the hardware and state machine,
*/
-static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Reset the state machine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -360,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = {
*/
static struct ata_port_operations hpt3x2n_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x2n_set_piomode,
.set_dmamode = hpt3x2n_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -390,9 +390,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index be0f05efac6..cb8bdb6887d 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = {
};
static struct ata_port_operations hpt3x3_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x3_set_piomode,
#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
@@ -153,9 +152,8 @@ static struct ata_port_operations hpt3x3_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
@@ -239,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
base = host->iomap[4]; /* Bus mastering base */
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = base + offset_cmd[i];
ioaddr->altstatus_addr =
@@ -247,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ioaddr->scr_addr = NULL;
ata_std_ports(ioaddr);
ioaddr->bmdma_addr = base + 8 * i;
+
+ ata_port_pbar_desc(ap, 4, -1, "ioport");
+ ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
}
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 64a711776c4..be30923566c 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -70,6 +70,8 @@ struct pata_icside_info {
unsigned int mwdma_mask;
unsigned int nr_ports;
const struct portinfo *port[2];
+ unsigned long raw_base;
+ unsigned long raw_ioc_base;
};
#define ICS_TYPE_A3IN 0
@@ -357,26 +359,7 @@ static void pata_icside_error_handler(struct ata_port *ap)
pata_icside_postreset);
}
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
- __FUNCTION__, status);
-
- return status;
-}
-
static struct ata_port_operations pata_icside_port_ops = {
- .port_disable = ata_port_disable,
-
.set_dmamode = pata_icside_set_dmamode,
.tf_load = ata_tf_load,
@@ -403,7 +386,6 @@ static struct ata_port_operations pata_icside_port_ops = {
.irq_clear = ata_dummy_noret,
.irq_on = ata_irq_on,
- .irq_ack = pata_icside_irq_ack,
.port_start = pata_icside_port_start,
@@ -412,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = {
};
static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
const struct portinfo *info)
{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
void __iomem *cmd = base + info->dataoffset;
ioaddr->cmd_addr = cmd;
@@ -431,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
ioaddr->ctl_addr = base + info->ctrloffset;
ioaddr->altstatus_addr = ioaddr->ctl_addr;
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ info->raw_base + info->dataoffset,
+ info->raw_base + info->ctrloffset);
+
+ if (info->raw_ioc_base)
+ ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
}
static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -451,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
info->nr_ports = 1;
info->port[0] = &pata_icside_portinfo_v5;
+ info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC);
+
return 0;
}
@@ -491,6 +483,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
info->port[0] = &pata_icside_portinfo_v6_1;
info->port[1] = &pata_icside_portinfo_v6_2;
+ info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+ info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
return icside_dma_init(info);
}
@@ -527,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ops = &pata_icside_port_ops;
- pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+ pata_icside_setup_ioaddr(ap, info->base, info->port[i]);
}
return ata_host_activate(host, ec->irq, ata_interrupt, 0,
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 9e553c54203..88ab0e1d353 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = {
};
static struct ata_port_operations isapnp_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -58,9 +57,8 @@ static struct ata_port_operations isapnp_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -112,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pnp_port_start(idev, 0),
+ (unsigned long long)pnp_port_start(idev, 1));
+
/* 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 b8af55e8915..1eda821e5e3 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -23,23 +23,24 @@
/**
* it8213_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Filter out ports by the enable bits before doing the normal reset
* and probe.
*/
-static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int it8213_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits it8213_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -260,7 +261,6 @@ static struct scsi_host_template it8213_sht = {
};
static const struct ata_port_operations it8213_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it8213_set_piomode,
.set_dmamode = it8213_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -288,9 +288,8 @@ static const struct ata_port_operations it8213_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 5d8b91e70ec..988ef736b93 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
{
struct it821x_dev *itdev = ap->private_data;
if (itdev && device != itdev->last_device) {
- struct ata_device *adev = &ap->device[device];
+ struct ata_device *adev = &ap->link.device[device];
it821x_program(ap, adev, itdev->pio[adev->devno]);
itdev->last_device = device;
}
@@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
/**
* it821x_smart_set_mode - mode setting
- * @ap: interface to set up
+ * @link: interface to set up
* @unused: device that failed (error only)
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -459,12 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
* and respect them.
*/
-static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -564,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap)
struct it821x_dev *itdev;
u8 conf;
- int ret = ata_port_start(ap);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -621,7 +620,6 @@ static struct scsi_host_template it821x_sht = {
static struct ata_port_operations it821x_smart_port_ops = {
.set_mode = it821x_smart_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.mode_filter = ata_pci_default_filter,
@@ -651,13 +649,11 @@ static struct ata_port_operations it821x_smart_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
static struct ata_port_operations it821x_passthru_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it821x_passthru_set_piomode,
.set_dmamode = it821x_passthru_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -688,7 +684,6 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_handler = ata_interrupt,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 5dea3584c6c..fcd532afbf2 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -26,12 +26,11 @@
#define DRV_NAME "pata_ixp4xx_cf"
#define DRV_VERSION "0.2"
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
+static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
dev->pio_mode = XFER_PIO_0;
@@ -49,7 +48,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
@@ -108,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = {
.set_mode = ixp4xx_set_mode,
.mode_filter = ata_pci_default_filter,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -128,14 +126,17 @@ static struct ata_port_operations ixp4xx_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.port_start = ata_port_start,
};
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
- struct ixp4xx_pata_data *data)
+ struct ixp4xx_pata_data *data,
+ unsigned long raw_cs0, unsigned long raw_cs1)
{
+ unsigned long raw_cmd = raw_cs0;
+ unsigned long raw_ctl = raw_cs1 + 0x06;
+
ioaddr->cmd_addr = data->cs0;
ioaddr->altstatus_addr = data->cs1 + 0x06;
ioaddr->ctl_addr = data->cs1 + 0x06;
@@ -161,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
+
+ raw_cmd ^= 0x03;
+ raw_ctl ^= 0x03;
#endif
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
}
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
@@ -206,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
ap->pio_mask = 0x1f; /* PIO4 */
ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
- ixp4xx_setup_port(&ap->ioaddr, data);
+ ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 4d67f238eee..225a7223a72 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -29,7 +29,7 @@ typedef enum {
/**
* jmicron_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
@@ -39,9 +39,9 @@ typedef enum {
* and setup here. We assume that has been done by init_one and the
* BIOS.
*/
-
-static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 control;
u32 control5;
@@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
ap->cbl = ATA_CBL_SATA;
break;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = {
};
static const struct ata_port_operations jmicron_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -168,7 +166,6 @@ static const struct ata_port_operations jmicron_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
@@ -207,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
-
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index edffc25d2d3..7bed8d80638 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
/**
* legacy_set_mode - mode setting
- * @ap: IDE interface
+ * @link: IDE link
* @unused: Device that failed when error is returned
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -107,12 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
* expand on this as per hdparm in the base kernel.
*/
-static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->pio_mode = XFER_PIO_0;
@@ -151,7 +150,6 @@ static struct scsi_host_template legacy_sht = {
*/
static struct ata_port_operations simple_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -172,7 +170,6 @@ static struct ata_port_operations simple_port_ops = {
.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,
};
@@ -180,7 +177,6 @@ static struct ata_port_operations simple_port_ops = {
static struct ata_port_operations legacy_port_ops = {
.set_mode = legacy_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -201,7 +197,6 @@ static struct ata_port_operations legacy_port_ops = {
.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,
};
@@ -256,7 +251,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
unsigned long flags;
@@ -296,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
static struct ata_port_operations pdc20230_port_ops = {
.set_piomode = pdc20230_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -317,7 +311,6 @@ static struct ata_port_operations pdc20230_port_ops = {
.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,
};
@@ -352,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560a_port_ops = {
.set_piomode = ht6560a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -373,7 +365,6 @@ static struct ata_port_operations ht6560a_port_ops = {
.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,
};
@@ -419,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560b_port_ops = {
.set_piomode = ht6560b_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -440,7 +430,6 @@ static struct ata_port_operations ht6560b_port_ops = {
.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,
};
@@ -541,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
static struct ata_port_operations opti82c611a_port_ops = {
.set_piomode = opti82c611a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -562,7 +550,6 @@ static struct ata_port_operations opti82c611a_port_ops = {
.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,
};
@@ -675,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
static struct ata_port_operations opti82c46x_port_ops = {
.set_piomode = opti82c46x_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -696,7 +682,6 @@ static struct ata_port_operations opti82c46x_port_ops = {
.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,
};
@@ -814,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
ata_std_ports(&ap->ioaddr);
ap->private_data = ld;
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+
ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
if (ret)
goto fail;
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index b45506f1ef7..9afc8a32b22 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -24,14 +24,15 @@
/**
* marvell_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
*/
-static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 devices;
void __iomem *barp;
@@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static int marvell_cable_detect(struct ata_port *ap)
@@ -110,8 +111,6 @@ static struct scsi_host_template marvell_sht = {
};
static const struct ata_port_operations marvell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -138,10 +137,9 @@ static const struct ata_port_operations marvell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 099f4cdc4cd..50c56e2814c 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = {
};
static struct ata_port_operations mpc52xx_ata_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpc52xx_ata_set_piomode,
.dev_select = mpc52xx_ata_dev_select,
.tf_load = ata_tf_load,
@@ -299,17 +298,16 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
+ unsigned long raw_ata_regs)
{
struct ata_host *host;
struct ata_port *ap;
struct ata_ioports *aio;
- int rc;
host = ata_host_alloc(dev, 1);
if (!host)
@@ -338,6 +336,8 @@ 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;
+ ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
+
/* activate host */
return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
&mpc52xx_ata_sht);
@@ -434,7 +434,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
}
/* Register ourselves to libata */
- rv = mpc52xx_ata_init_one(&op->dev, priv);
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
if (rv) {
printk(KERN_ERR DRV_NAME ": "
"Error while registering to ATA layer\n");
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ea42838297..d5483087a3f 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -46,15 +46,16 @@ enum {
SECONDARY = (1 << 14)
};
-static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -168,7 +169,6 @@ static struct scsi_host_template mpiix_sht = {
};
static struct ata_port_operations mpiix_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpiix_set_piomode,
.tf_load = ata_tf_load,
@@ -189,9 +189,8 @@ static struct ata_port_operations mpiix_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -202,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
- int irq;
+ int cmd, ctl, irq;
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -210,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
host = ata_host_alloc(&dev->dev, 1);
if (!host)
return -ENOMEM;
+ ap = host->ports[0];
/* MPIIX has many functions which can be turned on or off according
to other devices present. Make sure IDE is enabled before we try
@@ -221,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* See if it's primary or secondary channel... */
if (!(idetim & SECONDARY)) {
+ cmd = 0x1F0;
+ ctl = 0x3F6;
irq = 14;
- cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
} else {
+ cmd = 0x170;
+ ctl = 0x376;
irq = 15;
- cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
}
+ cmd_addr = devm_ioport_map(&dev->dev, cmd, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, ctl, 1);
if (!cmd_addr || !ctl_addr)
return -ENOMEM;
+ ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl);
+
/* We do our own plumbing to avoid leaking special cases for whacko
ancient hardware into the core code. There are two issues to
worry about. #1 The chip is a bridge so if in legacy mode and
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- ap = host->ports[0];
ap->ops = &mpiix_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 40eb574828b..25c922abd55 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = {
};
static const struct ata_port_operations netcell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -68,10 +66,9 @@ static const struct ata_port_operations netcell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2f5d714ebfc..6e8e55745b7 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -32,14 +32,15 @@
/**
* ns87410_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Check enabled ports
*/
-static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits ns87410_enable_bits[] = {
{ 0x43, 1, 0x08, 0x08 },
@@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -161,7 +162,6 @@ static struct scsi_host_template ns87410_sht = {
};
static struct ata_port_operations ns87410_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ns87410_set_piomode,
.tf_load = ata_tf_load,
@@ -184,9 +184,8 @@ static struct ata_port_operations ns87410_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
new file mode 100644
index 00000000000..bb97ef583f9
--- /dev/null
+++ b/drivers/ata/pata_ns87415.c
@@ -0,0 +1,467 @@
+/*
+ * pata_ns87415.c - NS87415 (non PARISC) PATA
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * This is a fairly generic MWDMA controller. It has some limitations
+ * as it requires timing reloads on PIO/DMA transitions but it is otherwise
+ * fairly well designed.
+ *
+ * This driver assumes the firmware has left the chip in a valid ST506
+ * compliant state, either legacy IRQ 14/15 or native INTA shared. You
+ * may need to add platform code if your system fails to do this.
+ *
+ * The same cell appears in the 87560 controller used by some PARISC
+ * systems. This has its own special mountain of errata.
+ *
+ * TODO:
+ * Test PARISC SuperIO
+ * Get someone to test on SPARC
+ * Implement lazy pio/dma switching for better performance
+ * 8bit shared timing.
+ * See if we need to kill the FIFO for ATAPI
+ */
+
+#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 <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_ns87415"
+#define DRV_VERSION "0.0.1"
+
+/**
+ * ns87415_set_mode - Initialize host controller mode timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device whose timings we are configuring
+ * @mode: Mode to set
+ *
+ * Program the mode registers for this controller, channel and
+ * device. Because the chip is quite an old design we have to do this
+ * for PIO/DMA switches.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ int unit = 2 * ap->port_no + adev->devno;
+ int timing = 0x44 + 2 * unit;
+ unsigned long T = 1000000000 / 33333; /* PCI clocks */
+ struct ata_timing t;
+ u16 clocking;
+ u8 iordy;
+ u8 status;
+
+ /* Timing register format is 17 - low nybble read timing with
+ the high nybble being 16 - x for recovery time in PCI clocks */
+
+ ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
+
+ clocking = 17 - FIT(t.active, 2, 17);
+ clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ /* Use the same timing for read and write bytes */
+ clocking |= (clocking << 8);
+ pci_write_config_word(dev, timing, clocking);
+
+ /* Set the IORDY enable versus DMA enable on or off properly */
+ pci_read_config_byte(dev, 0x42, &iordy);
+ iordy &= ~(1 << (4 + unit));
+ if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev))
+ iordy |= (1 << (4 + unit));
+
+ /* Paranoia: We shouldn't ever get here with busy write buffers
+ but if so wait */
+
+ pci_read_config_byte(dev, 0x43, &status);
+ while (status & 0x03) {
+ udelay(1);
+ pci_read_config_byte(dev, 0x43, &status);
+ }
+ /* Flip the IORDY/DMA bits now we are sure the write buffers are
+ clear */
+ pci_write_config_byte(dev, 0x42, iordy);
+
+ /* TODO: Set byte 54 command timing to the best 8bit
+ mode shared by all four devices */
+}
+
+/**
+ * ns87415_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ ns87415_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_setup - Set up DMA
+ * @qc: Command block
+ *
+ * Set up for bus masterng DMA. We have to do this ourselves
+ * rather than use the helper due to a chip erratum
+ */
+
+static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ /* Due to an erratum we need to write these bits to the wrong
+ place - which does save us an I/O bizarrely */
+ dmactl |= ATA_DMA_INTR | ATA_DMA_ERR;
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * ns87415_bmdma_start - Begin DMA transfer
+ * @qc: Command block
+ *
+ * Switch the timings for the chip and set up for a DMA transfer
+ * before the DMA burst begins.
+ *
+ * FIXME: We should do lazy switching on bmdma_start versus
+ * ata_pio_data_xfer for better performance.
+ */
+
+static void ns87415_bmdma_start(struct ata_queued_cmd *qc)
+{
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * ns87415_bmdma_stop - End DMA transfer
+ * @qc: Command block
+ *
+ * End DMA mode and switch the controller back into PIO mode
+ */
+
+static void ns87415_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_irq_clear - Clear interrupt
+ * @ap: Channel to clear
+ *
+ * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the
+ * error bits) are reset by writing to register 00 or 08.
+ */
+
+static void ns87415_bmdma_irq_clear(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
+ return;
+ iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR),
+ mmio + ATA_DMA_CMD);
+}
+
+/**
+ * ns87415_check_atapi_dma - ATAPI DMA filter
+ * @qc: Command block
+ *
+ * Disable ATAPI DMA (for now). We may be able to do DMA if we
+ * kill the prefetching. This isn't clear.
+ */
+
+static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return -EOPNOTSUPP;
+}
+
+#if defined(CONFIG_SUPERIO)
+
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ *
+ * Workarounds taken from drivers/ide/pci/ns87415.c
+ */
+
+#include <asm/superio.h>
+
+/**
+ * ns87560_read_buggy - workaround buggy Super I/O chip
+ * @port: Port to read
+ *
+ * Work around chipset problems in the 87560 SuperIO chip
+ */
+
+static u8 ns87560_read_buggy(void __iomem *port)
+{
+ u8 tmp;
+ int retries = SUPERIO_IDE_MAX_RETRIES;
+ do {
+ tmp = ioread8(port);
+ if (tmp != 0)
+ return tmp;
+ udelay(50);
+ } while(retries-- > 0);
+ return tmp;
+}
+
+/**
+ * ns87560_check_status
+ * @ap: channel to check
+ *
+ * Return the status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_check_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.status_addr);
+}
+
+/**
+ * ns87560_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf. Work around the 87560 bugs.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ns87560_check_status(ap);
+ tf->feature = ioread8(ioaddr->error_addr);
+ tf->nsect = ioread8(ioaddr->nsect_addr);
+ tf->lbal = ioread8(ioaddr->lbal_addr);
+ tf->lbam = ioread8(ioaddr->lbam_addr);
+ tf->lbah = ioread8(ioaddr->lbah_addr);
+ tf->device = ns87560_read_buggy(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread8(ioaddr->error_addr);
+ tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/**
+ * ns87560_bmdma_status
+ * @ap: channel to check
+ *
+ * Return the DMA status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_bmdma_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static const struct ata_port_operations ns87560_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ns87560_tf_read,
+ .check_status = ns87560_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .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 = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ns87560_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+#endif /* 87560 SuperIO Support */
+
+
+static const struct ata_port_operations ns87415_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .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 = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct scsi_host_template ns87415_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,
+};
+
+
+/**
+ * ns87415_init_one - Register 87415 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in ns87415_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static const struct ata_port_info info = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87415_pata_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+#if defined(CONFIG_SUPERIO)
+ static const struct ata_port_info info87560 = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87560_pata_ops,
+ };
+
+ if (PCI_SLOT(pdev->devfn) == 0x0E)
+ ppi[0] = &info87560;
+#endif
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+ /* Select 512 byte sectors */
+ pci_write_config_byte(pdev, 0x55, 0xEE);
+ /* Select PIO0 8bit clocking */
+ pci_write_config_byte(pdev, 0x54, 0xB7);
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver ns87415_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ns87415_pci_tbl,
+ .probe = ns87415_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init ns87415_init(void)
+{
+ return pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_exit(void)
+{
+ pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_init);
+module_exit(ns87415_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 091a70a0ef1..3cd5eb2b6c9 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -29,14 +29,15 @@
/**
* oldpiix_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits oldpiix_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
@@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -237,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = {
};
static const struct ata_port_operations oldpiix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = oldpiix_set_piomode,
.set_dmamode = oldpiix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -265,9 +265,8 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 458bf67f766..8f79447b615 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -46,14 +46,15 @@ enum {
/**
* opti_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits opti_enable_bits[] = {
{ 0x45, 1, 0x80, 0x00 },
@@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -182,7 +183,6 @@ static struct scsi_host_template opti_sht = {
};
static struct ata_port_operations opti_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = opti_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -209,9 +209,8 @@ static struct ata_port_operations opti_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index f89bdfde16d..6b07b5b4853 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */
/**
* optidma_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int optidma_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits optidma_enable_bits = {
0x40, 1, 0x08, 0x00
@@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -323,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev)
/**
* optidma_set_mode - mode setup
- * @ap: port to set up
+ * @link: link to set up
*
* 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 int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
+ struct ata_port *ap = link->ap;
u8 r;
int nybble = 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int rc = ata_do_set_mode(ap, r_failed);
+ int rc = ata_do_set_mode(link, 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;
+ r |= (optidma_make_bits43(&link->device[0]) +
+ (optidma_make_bits43(&link->device[0]) << 2)) << nybble;
pci_write_config_byte(pdev, 0x43, r);
}
return rc;
@@ -366,7 +368,6 @@ static struct scsi_host_template optidma_sht = {
};
static struct ata_port_operations optidma_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optidma_set_pio_mode,
.set_dmamode = optidma_set_dma_mode,
@@ -396,13 +397,11 @@ static struct ata_port_operations optidma_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations optiplus_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optiplus_set_pio_mode,
.set_dmamode = optiplus_set_dma_mode,
@@ -432,9 +431,8 @@ static struct ata_port_operations optiplus_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 0f2b027624d..5db2013230b 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -56,7 +56,7 @@ struct ata_pcmcia_info {
/**
* pcmcia_set_mode - PCMCIA specific mode setup
- * @ap: Port
+ * @link: link
* @r_failed_dev: Return pointer for failed device
*
* Perform the tuning and setup of the devices and timings, which
@@ -65,13 +65,13 @@ struct ata_pcmcia_info {
* 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)
+static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
- struct ata_device *master = &ap->device[0];
- struct ata_device *slave = &ap->device[1];
+ struct ata_device *master = &link->device[0];
+ struct ata_device *slave = &link->device[1];
if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, 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)
@@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev
ata_dev_disable(slave);
}
}
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
static struct scsi_host_template pcmcia_sht = {
@@ -107,7 +107,6 @@ 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,
.check_status = ata_check_status,
@@ -127,7 +126,6 @@ static struct ata_port_operations pcmcia_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_sff_port_start,
};
@@ -304,6 +302,8 @@ next_entry:
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+
/* activate */
ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
IRQF_SHARED, &pcmcia_sht);
@@ -353,6 +353,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
@@ -378,6 +379,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index bb64a986e8f..3d3f1558cde 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
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);
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed);
/*
* ATA Timing Tables based on 133MHz controller clock.
@@ -147,7 +147,6 @@ 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,
@@ -173,13 +172,11 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2027x_pata133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc2027x_set_piomode,
.set_dmamode = pdc2027x_set_dmamode,
.set_mode = pdc2027x_set_mode,
@@ -208,9 +205,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_info pdc2027x_port_info[] = {
@@ -277,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap)
u32 cgcr;
/* check cable detect results */
- cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+ cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL));
if (cgcr & (1 << 26))
goto cbl40;
@@ -295,12 +291,12 @@ cbl40:
*/
static inline int pdc2027x_port_enabled(struct ata_port *ap)
{
- return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+ return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
}
/**
* pdc2027x_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* Probeinit including cable detection.
@@ -309,12 +305,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
* None (inherited from caller).
*/
-static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
+static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline)
{
/* Check whether port enabled */
- if (!pdc2027x_port_enabled(ap))
+ if (!pdc2027x_port_enabled(link->ap))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -387,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Set the PIO timing registers using value table for 133MHz */
PDPRINTK("Set pio regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0xffff0000;
ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
(pdc2027x_pio_timing_tbl[pio].value1 << 8);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0x00ffffff;
ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set pio regs done\n");
@@ -430,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* If tHOLD is '1', the hardware will add half clock for data hold time.
* This code segment seems to be no effect. tHOLD will be overwritten below.
*/
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
- writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
}
PDPRINTK("Set udma regs... \n");
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0xff000000;
ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
(pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
(pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set udma regs done\n");
@@ -453,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
unsigned int mdma_mode = dma_mode & 0x07;
PDPRINTK("Set mdma regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0x0000ffff;
ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
(pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
PDPRINTK("Set mdma regs done\n");
PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
@@ -470,24 +466,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* pdc2027x_set_mode - Set the timing registers back to correct values.
- * @ap: Port to configure
+ * @link: link 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 int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- int i;
-
- i = ata_do_set_mode(ap, r_failed);
- if (i < 0)
- return i;
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ rc = ata_do_set_mode(link, r_failed);
+ if (rc < 0)
+ return rc;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
pdc2027x_set_piomode(ap, dev);
@@ -496,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
* Enable prefetch if the device support PIO only.
*/
if (dev->xfer_shift == ATA_SHIFT_PIO) {
- u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+ u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
ctcr1 |= (1 << 25);
- writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
PDPRINTK("Turn on prefetch\n");
} else {
@@ -563,14 +559,12 @@ static long pdc_read_counter(struct ata_host *host)
u32 bccrl, bccrh, bccrlv, bccrhv;
retry:
- bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
- bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
- rmb();
+ bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
/* Read the counter values again for verification */
- bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
- bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
- rmb();
+ bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
counter = (bccrh << 15) | bccrl;
@@ -619,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
/* Show the current clock value of PLL control register
* (maybe already configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -659,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
- writew(pll_ctl, mmio_base + PDC_PLL_CTL);
- readw(mmio_base + PDC_PLL_CTL); /* flush */
+ iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);
+ ioread16(mmio_base + PDC_PLL_CTL); /* flush */
/* Wait the PLL circuit to be stable */
mdelay(30);
@@ -670,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
* Show the current clock value of PLL control register
* (maybe configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -693,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
long pll_clock, usec_elapsed;
/* Start the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
+ iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* Read current counter value */
start_count = pdc_read_counter(host);
@@ -710,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
do_gettimeofday(&end_time);
/* Stop the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
+ iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
@@ -745,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
*/
pll_clock = pdc_detect_pll_input_clock(host);
- if (pll_clock < 0) /* counter overflow? Try again. */
- pll_clock = pdc_detect_pll_input_clock(host);
-
dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
/* Adjust PLL control register */
@@ -791,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
+ static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
+ static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] =
{ &pdc2027x_port_info[board_idx], NULL };
struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -826,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
mmio_base = host->iomap[PDC_MMIO_BAR];
- 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;
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);
+ ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");
+ }
//pci_enable_intx(pdev);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 92447bed5e7..65d951618c6 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -9,7 +9,7 @@
* First cut with LBA48/ATAPI
*
* TODO:
- * Channel interlock/reset on both required
+ * Channel interlock/reset on both required ?
*/
#include <linux/kernel.h>
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
static int pdc2026x_cable_detect(struct ata_port *ap)
{
@@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{ 0x20, 0x01 }
};
static u8 mdma_timing[3][2] = {
- { 0x60, 0x03 },
- { 0x60, 0x04 },
{ 0xe0, 0x0f },
+ { 0x60, 0x04 },
+ { 0x60, 0x03 },
};
u8 r_bp, r_cp;
@@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* In UDMA3 or higher we have to clock switch for the duration of the
* DMA transfer sequence.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
@@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
*
* After a DMA completes we need to put the clock back to 33MHz for
* PIO timings.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
@@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
iowrite32(0, atapi_reg);
iowrite8(ioread8(clock) & ~sel66, clock);
}
- /* Check we keep host level locking here */
/* Flip back to 33Mhz for PIO */
if (adev->dma_mode >= XFER_UDMA_2)
iowrite8(ioread8(clock) & ~sel66, clock);
@@ -247,7 +252,6 @@ static struct scsi_host_template pdc202xx_sht = {
};
static struct ata_port_operations pdc2024x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -275,13 +279,11 @@ static struct ata_port_operations pdc2024x_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2026x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -310,9 +312,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 5086d03f2d7..fc72a965643 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -30,13 +30,11 @@ static int pio_mask = 1;
* Provide our own set_mode() as we don't want to change anything that has
* already been configured..
*/
-static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
@@ -71,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = {
static struct ata_port_operations pata_platform_port_ops = {
.set_mode = pata_platform_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -91,7 +88,6 @@ static struct ata_port_operations pata_platform_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_dummy_ret0,
};
@@ -209,9 +205,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pp_info = (struct pata_platform_info *)(pdev->dev.platform_data);
+ pp_info = pdev->dev.platform_data;
pata_platform_setup_port(&ap->ioaddr, pp_info);
+ ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
+ (unsigned long long)io_res->start,
+ (unsigned long long)ctl_res->start);
+
/* activate */
return ata_host_activate(host, platform_get_irq(pdev, 0),
ata_interrupt, pp_info ? pp_info->irq_flags
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 1998c19e874..7d4c696c4cb 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = {
};
static struct ata_port_operations qdi6500_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6500_set_piomode,
.tf_load = ata_tf_load,
@@ -192,13 +191,11 @@ static struct ata_port_operations qdi6500_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations qdi6580_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6580_set_piomode,
.tf_load = ata_tf_load,
@@ -220,9 +217,8 @@ static struct ata_port_operations qdi6580_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -238,6 +234,7 @@ 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)
{
+ unsigned long ctl = io + 0x206;
struct platform_device *pdev;
struct ata_host *host;
struct ata_port *ap;
@@ -254,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ret = -ENOMEM;
io_addr = devm_ioport_map(&pdev->dev, io, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
if (!io_addr || !ctl_addr)
goto fail;
@@ -279,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
+
/*
* Hook in a private data structure per channel
*/
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 7d1aabed422..d5b76497f4a 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = {
};
static const struct ata_port_operations radisys_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = radisys_set_piomode,
.set_dmamode = radisys_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -231,9 +230,8 @@ static const struct ata_port_operations radisys_pata_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 7632fcb070c..ba8a31c55ed 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -26,7 +26,7 @@
/**
* rz1000_set_mode - mode setting function
- * @ap: ATA interface
+ * @link: ATA link
* @unused: returned device on set_mode failure
*
* Use a non standard set_mode function. We don't want to be tuned. We
@@ -34,12 +34,11 @@
* whacked out.
*/
-static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -74,7 +73,6 @@ static struct scsi_host_template rz1000_sht = {
static struct ata_port_operations rz1000_port_ops = {
.set_mode = rz1000_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -100,9 +98,8 @@ static struct ata_port_operations rz1000_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 5edf67b1f3b..21ebc485ca4 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = {
};
static struct ata_port_operations sc1200_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sc1200_set_piomode,
.set_dmamode = sc1200_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -227,9 +226,8 @@ static struct ata_port_operations sc1200_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 2d048ef25a5..55576138fae 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -603,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
* Note: Original code is ata_std_softreset().
*/
-static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
- unsigned long deadline)
+static int scc_std_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0, err_mask;
u8 err;
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -636,9 +637,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&ap->link.device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -701,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
/* TBD: SW reset */
- scc_std_softreset(ap, &classes, deadline);
+ scc_std_softreset(&ap->link, &classes, deadline);
continue;
}
@@ -740,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
void __iomem *mmio = ap->ioaddr.bmdma_addr;
u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
static int retry = 0;
/* return if IOS_SS is cleared */
@@ -785,7 +788,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
unsigned int i;
u16 *buf16 = (u16 *) buf;
@@ -839,38 +842,6 @@ static u8 scc_irq_on (struct ata_port *ap)
}
/**
- * scc_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Note: Original code is ata_irq_ack().
- */
-
-static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat, post_stat, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- /* get controller status; clear intr, err bits */
- host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
- out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
- host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
-
- post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
-
- return status;
-}
-
-/**
* scc_bmdma_freeze - Freeze BMDMA controller port
* @ap: port to freeze
*
@@ -901,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap)
* @deadline: deadline jiffies for the operation
*/
-static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap, deadline);
+ link->ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(link, deadline);
}
/**
@@ -915,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
* Note: Original code is ata_std_postreset().
*/
-static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+static void scc_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
+
DPRINTK("ENTER\n");
/* is double-select really necessary? */
@@ -1020,7 +993,6 @@ static struct scsi_host_template scc_sht = {
};
static const struct ata_port_operations scc_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
.mode_filter = scc_mode_filter,
@@ -1047,7 +1019,6 @@ static const struct ata_port_operations scc_pata_ops = {
.irq_clear = scc_bmdma_irq_clear,
.irq_on = scc_irq_on,
- .irq_ack = scc_irq_ack,
.port_start = scc_port_start,
.port_stop = scc_port_stop,
@@ -1193,6 +1164,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
host->iomap = pcim_iomap_table(pdev);
+ ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
+ ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
+
rc = scc_host_init(host);
if (rc)
return rc;
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 0faf99c8f13..df68806df4b 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = {
};
static struct ata_port_operations serverworks_osb4_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_osb4_filter,
@@ -348,13 +347,11 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations serverworks_csb_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_csb_filter,
@@ -384,9 +381,8 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int serverworks_fixup_osb4(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 40395804a66..4dc2e73298f 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) {
/**
* sil680_bus_reset - reset the SIL680 bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the SIL680 housekeeping when doing an ATA bus reset
*/
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+static int sil680_bus_reset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
u8 reset;
@@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
pci_write_config_byte(pdev, addr, reset | 0x03);
udelay(25);
pci_write_config_byte(pdev, addr, reset);
- return ata_std_softreset(ap, classes, deadline);
+ return ata_std_softreset(link, classes, deadline);
}
static void sil680_error_handler(struct ata_port *ap)
@@ -237,7 +238,6 @@ static struct scsi_host_template sil680_sht = {
};
static struct ata_port_operations sil680_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sil680_set_piomode,
.set_dmamode = sil680_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -266,9 +266,8 @@ static struct ata_port_operations sil680_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
@@ -280,7 +279,7 @@ static struct ata_port_operations sil680_port_ops = {
* Returns the final clock settings.
*/
-static u8 sil680_init_chip(struct pci_dev *pdev)
+static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
{
u32 class_rev = 0;
u8 tmpbyte = 0;
@@ -298,6 +297,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev)
dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n",
tmpbyte & 1, tmpbyte & 0x30);
+ *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
+
switch(tmpbyte & 0x30) {
case 0x00:
/* 133 clock attempt to force it on */
@@ -362,25 +363,76 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
};
const struct ata_port_info *ppi[] = { &info, NULL };
static int printed_version;
+ struct ata_host *host;
+ void __iomem *mmio_base;
+ int rc, try_mmio;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- switch(sil680_init_chip(pdev))
- {
+ switch (sil680_init_chip(pdev, &try_mmio)) {
case 0:
ppi[0] = &info_slow;
break;
case 0x30:
return -ENODEV;
}
+
+ if (!try_mmio)
+ goto use_ioports;
+
+ /* Try to acquire MMIO resources and fallback to PIO if
+ * that fails
+ */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+ rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
+ if (rc)
+ goto use_ioports;
+
+ /* Allocate host and set it up */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+ host->iomap = pcim_iomap_table(pdev);
+
+ /* Setup DMA masks */
+ 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;
+ pci_set_master(pdev);
+
+ /* Get MMIO base and initialize port addresses */
+ mmio_base = host->iomap[SIL680_MMIO_BAR];
+ host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00;
+ host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80;
+ host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a;
+ host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a;
+ ata_std_ports(&host->ports[0]->ioaddr);
+ host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08;
+ host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0;
+ host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca;
+ host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca;
+ ata_std_ports(&host->ports[1]->ioaddr);
+
+ /* Register & activate */
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &sil680_sht);
+
+use_ioports:
return ata_pci_init_one(pdev, ppi);
}
#ifdef CONFIG_PM
static int sil680_reinit_one(struct pci_dev *pdev)
{
- sil680_init_chip(pdev);
+ int try_mmio;
+
+ sil680_init_chip(pdev, &try_mmio);
return ata_pci_device_resume(pdev);
}
#endif
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index cce2834b2b6..3b5be77e861 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev)
static int sis_old_port_base(struct ata_device *adev)
{
- return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
+ return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno);
}
/**
@@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap)
/**
* sis_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sis_enable_bits[] = {
{ 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
@@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
/* Clear the FIFO settings. We can't enable the FIFO until
we know we are poking at a disk */
pci_write_config_byte(pdev, 0x4B, 0);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -530,7 +531,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -558,13 +558,11 @@ static const struct ata_port_operations sis_133_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_for_sata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -592,13 +590,11 @@ static const struct ata_port_operations sis_133_for_sata_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_early_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_133_early_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -626,13 +622,11 @@ static const struct ata_port_operations sis_133_early_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_100_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -660,13 +654,11 @@ static const struct ata_port_operations sis_100_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_66_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -694,13 +686,11 @@ static const struct ata_port_operations sis_66_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_old_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_old_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -728,9 +718,8 @@ static const struct ata_port_operations sis_old_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_info sis_info = {
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index c0f43bb2595..1388cef52c0 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -43,23 +43,24 @@ enum {
/**
* sl82c105_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sl82c105_enable_bits[] = {
{ 0x40, 1, 0x01, 0x01 },
{ 0x40, 1, 0x10, 0x10 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -224,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = {
};
static struct ata_port_operations sl82c105_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sl82c105_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -253,9 +253,8 @@ static struct ata_port_operations sl82c105_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index af21f443db6..403eafcffe1 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -47,25 +47,26 @@
/**
* triflex_prereset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
+static int triflex_prereset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits triflex_enable_bits[] = {
{ 0x80, 1, 0x01, 0x01 },
{ 0x80, 1, 0x02, 0x02 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -197,7 +198,6 @@ static struct scsi_host_template triflex_sht = {
};
static struct ata_port_operations triflex_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = triflex_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -226,9 +226,8 @@ static struct ata_port_operations triflex_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index f143db4559e..5d41b6612d7 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -184,11 +184,15 @@ static int via_cable_detect(struct ata_port *ap) {
two drives */
if (ata66 & (0x10100000 >> (16 * ap->port_no)))
return ATA_CBL_PATA80;
+ /* Check with ACPI so we can spot BIOS reported SATA bridges */
+ if (ata_acpi_cbl_80wire(ap))
+ return ATA_CBL_PATA80;
return ATA_CBL_PATA40;
}
-static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int via_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
const struct via_isa_bridge *config = ap->host->private_data;
if (!(config->flags & VIA_NO_ENABLES)) {
@@ -201,7 +205,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
return -ENOENT;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -344,7 +348,6 @@ static struct scsi_host_template via_sht = {
};
static struct ata_port_operations via_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -374,13 +377,11 @@ static struct ata_port_operations via_port_ops = {
.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,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations via_port_ops_noirq = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -410,9 +411,8 @@ static struct ata_port_operations via_port_ops_noirq = {
.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,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 83abfeca405..549cbbe9fd0 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = {
};
static struct ata_port_operations winbond_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = winbond_set_piomode,
.tf_load = ata_tf_load,
@@ -160,9 +159,8 @@ static struct ata_port_operations winbond_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -199,6 +197,7 @@ static __init int winbond_init_one(unsigned long port)
for (i = 0; i < 2 ; i ++) {
unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ unsigned long ctl_port = cmd_port + 0x206;
struct ata_host *host;
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
@@ -214,14 +213,16 @@ static __init int winbond_init_one(unsigned long port)
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
goto err_unregister;
+ ap = host->ports[0];
rc = -ENOMEM;
cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
if (!cmd_addr || !ctl_addr)
goto err_unregister;
- ap = host->ports[0];
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
+
ap->ops = &winbond_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5c79271401a..8d1b03d5bcb 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -92,6 +92,8 @@ enum {
/* CPB bits */
cDONE = (1 << 0),
+ cATERR = (1 << 3),
+
cVLD = (1 << 0),
cDAT = (1 << 2),
cIEN = (1 << 3),
@@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev,
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);
-static void adma_phy_reset(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void adma_bmdma_stop(struct ata_queued_cmd *qc);
static u8 adma_bmdma_status(struct ata_port *ap);
static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
+static void adma_freeze(struct ata_port *ap);
+static void adma_thaw(struct ata_port *ap);
+static void adma_error_handler(struct ata_port *ap);
static struct scsi_host_template adma_ata_sht = {
.module = THIS_MODULE,
@@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = {
};
static const struct ata_port_operations adma_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .phy_reset = adma_phy_reset,
.check_atapi_dma = adma_check_atapi_dma,
.data_xfer = ata_data_xfer,
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
- .eng_timeout = adma_eng_timeout,
+ .freeze = adma_freeze,
+ .thaw = adma_thaw,
+ .error_handler = adma_error_handler,
.irq_clear = adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = adma_port_start,
.port_stop = adma_port_stop,
.host_stop = adma_host_stop,
@@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ .flags = ATA_FLAG_SLAVE_POSS |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
@@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap)
readb(chan + ADMA_STATUS); /* flush */
}
-static void adma_phy_reset(struct ata_port *ap)
+static void adma_freeze(struct ata_port *ap)
{
- struct adma_port_priv *pp = ap->private_data;
+ void __iomem *chan = ADMA_PORT_REGS(ap);
+
+ /* mask/clear ATA interrupts */
+ writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
+ ata_check_status(ap);
- pp->state = adma_state_idle;
+ /* reset ADMA to idle state */
+ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+ udelay(2);
+ writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
+ udelay(2);
+}
+
+static void adma_thaw(struct ata_port *ap)
+{
adma_reinit_engine(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
}
-static void adma_eng_timeout(struct ata_port *ap)
+static int adma_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct adma_port_priv *pp = ap->private_data;
if (pp->state != adma_state_idle) /* healthy paranoia */
pp->state = adma_state_mmio;
adma_reinit_engine(ap);
- ata_eng_timeout(ap);
+
+ return ata_std_prereset(link, deadline);
+}
+
+static void adma_error_handler(struct ata_port *ap)
+{
+ ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
static int adma_fill_sg(struct ata_queued_cmd *qc)
@@ -464,14 +484,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
pp = ap->private_data;
if (!pp || pp->state != adma_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- if ((status & (aPERR | aPSD | aUIRQ)))
+ if (status & aPERR)
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ else if ((status & (aPSD | aUIRQ)))
qc->err_mask |= AC_ERR_OTHER;
+
+ if (pp->pkt[0] & cATERR)
+ qc->err_mask |= AC_ERR_DEV;
else if (pp->pkt[0] != cDONE)
qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "ADMA-status 0x%02X", status);
+ ata_ehi_push_desc(ehi,
+ "pkt[0] 0x%02X", pp->pkt[0]);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
}
}
return handled;
@@ -489,7 +528,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
struct adma_port_priv *pp = ap->private_data;
if (!pp || pp->state != adma_state_mmio)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
@@ -502,7 +541,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
/* complete taskfile transaction */
pp->state = adma_state_idle;
qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi =
+ &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "status 0x%02X", status);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
handled = 1;
}
}
@@ -652,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev,
if (rc)
return rc;
- 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));
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
+ struct ata_port *ap = host->ports[port_no];
+ void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
+ unsigned int offset = port_base - mmio_base;
+
+ adma_ata_setup_port(&ap->ioaddr, port_base);
+
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
+ }
/* initialize adapter */
adma_host_init(host, board_idx);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index fdbed8ecdfc..08595f34b3e 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap)
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 irq_stat;
/* fetch and clear irq */
@@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap)
writeb(irq_stat, port_base + PORT_IRQ_STAT);
if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc =
+ ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
ata_chk_status(ap); /* clear ATA interrupt */
@@ -416,12 +417,13 @@ static void inic_thaw(struct ata_port *ap)
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
*/
-static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+static int inic_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
u16 val;
int rc;
@@ -434,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
msleep(1);
writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link after reset (errno=%d)\n", rc);
return rc;
}
*class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
struct ata_taskfile tf;
/* wait a while before checking status */
@@ -451,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"after hardreset (errno=%d)\n", rc);
return rc;
}
@@ -550,7 +552,6 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -567,7 +568,6 @@ static struct ata_port_operations inic_port_ops = {
.irq_clear = inic_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.qc_prep = ata_qc_prep,
.qc_issue = inic_qc_issue,
@@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
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;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *port = &ap->ioaddr;
+ unsigned int offset = 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;
+ port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
ata_std_ports(port);
+
+ ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 2 * i),
+ (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
+ ATA_PCI_CTL_OFS);
}
hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index d9832e234e4..4df8311968e 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -483,8 +483,6 @@ static struct scsi_host_template mv6_sht = {
};
static const struct ata_port_operations mv5_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -499,7 +497,6 @@ static const struct ata_port_operations mv5_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -514,8 +511,6 @@ static const struct ata_port_operations mv5_ops = {
};
static const struct ata_port_operations mv6_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -530,7 +525,6 @@ static const struct ata_port_operations mv6_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -545,8 +539,6 @@ static const struct ata_port_operations mv6_ops = {
};
static const struct ata_port_operations mv_iie_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -561,7 +553,6 @@ static const struct ata_port_operations mv_iie_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -1415,7 +1406,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
unsigned int action = 0, err_mask = 0;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
@@ -1423,8 +1414,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
/* just a guess: do we need to do this? should we
* expand this, and do it in all cases?
*/
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
}
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -1468,8 +1459,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
}
if (edma_err_cause & EDMA_ERR_SERR) {
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
err_mask = AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
}
@@ -1508,7 +1499,7 @@ static void mv_intr_pio(struct ata_port *ap)
return;
/* get active ATA command */
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc)) /* no active tag */
return;
if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
@@ -1543,7 +1534,7 @@ static void mv_intr_edma(struct ata_port *ap)
/* 50xx: get active ATA command */
if (IS_GEN_I(hpriv))
- tag = ap->active_tag;
+ tag = ap->link.active_tag;
/* Gen II/IIE: get active ATA command via tag, to enable
* support for queueing. this works transparently for
@@ -1646,7 +1637,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
if (unlikely(have_err_bits)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
continue;
@@ -1687,15 +1678,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i];
- if (!ata_port_offline(ap)) {
- ehi = &ap->eh_info;
+ if (!ata_link_offline(&ap->link)) {
+ ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
if (!printed++)
ata_ehi_push_desc(ehi,
"PCI err cause 0x%08x", err_cause);
err_mask = AC_ERR_HOST_BUS;
ehi->action = ATA_EH_HARDRESET;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc)
qc->err_mask |= err_mask;
else
@@ -2198,14 +2189,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
/* Issue COMRESET via SControl */
comreset_retry:
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
msleep(1);
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
msleep(20);
do {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
break;
@@ -2230,7 +2221,7 @@ comreset_retry:
}
#endif
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(&ap->link)) {
*class = ATA_DEV_NONE;
return;
}
@@ -2257,7 +2248,7 @@ comreset_retry:
*/
/* finally, read device signature from TF registers */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(ap->link.device, 1, NULL);
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2266,10 +2257,11 @@ comreset_retry:
VPRINTK("EXIT\n");
}
-static int mv_prereset(struct ata_port *ap, unsigned long deadline)
+static int mv_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
int rc;
rc = mv_stop_dma(ap);
@@ -2285,7 +2277,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
rc = ata_wait_ready(ap, deadline);
else
rc = -ENODEV;
@@ -2293,9 +2285,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
return rc;
}
-static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+static int mv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
@@ -2308,16 +2301,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class,
return 0;
}
-static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+static void mv_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serr;
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(link, SCR_ERROR, &serr);
+ sata_scr_write_flush(link, SCR_ERROR, serr);
/* bail out if no device is present */
if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -2590,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
}
for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&host->ports[port]->ioaddr, port_mmio);
+ unsigned int offset = port_mmio - mmio;
+
+ mv_port_init(&ap->ioaddr, port_mmio);
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
}
for (hc = 0; hc < n_hc; hc++) {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 40dc7313985..240a8920d0b 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -169,6 +169,35 @@ enum {
NV_ADMA_PORT_REGISTER_MODE = (1 << 0),
NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1),
+ /* MCP55 reg offset */
+ NV_CTL_MCP55 = 0x400,
+ NV_INT_STATUS_MCP55 = 0x440,
+ NV_INT_ENABLE_MCP55 = 0x444,
+ NV_NCQ_REG_MCP55 = 0x448,
+
+ /* MCP55 */
+ NV_INT_ALL_MCP55 = 0xffff,
+ NV_INT_PORT_SHIFT_MCP55 = 16, /* each port occupies 16 bits */
+ NV_INT_MASK_MCP55 = NV_INT_ALL_MCP55 & 0xfffd,
+
+ /* SWNCQ ENABLE BITS*/
+ NV_CTL_PRI_SWNCQ = 0x02,
+ NV_CTL_SEC_SWNCQ = 0x04,
+
+ /* SW NCQ status bits*/
+ NV_SWNCQ_IRQ_DEV = (1 << 0),
+ NV_SWNCQ_IRQ_PM = (1 << 1),
+ NV_SWNCQ_IRQ_ADDED = (1 << 2),
+ NV_SWNCQ_IRQ_REMOVED = (1 << 3),
+
+ NV_SWNCQ_IRQ_BACKOUT = (1 << 4),
+ NV_SWNCQ_IRQ_SDBFIS = (1 << 5),
+ NV_SWNCQ_IRQ_DHREGFIS = (1 << 6),
+ NV_SWNCQ_IRQ_DMASETUP = (1 << 7),
+
+ NV_SWNCQ_IRQ_HOTPLUG = NV_SWNCQ_IRQ_ADDED |
+ NV_SWNCQ_IRQ_REMOVED,
+
};
/* ADMA Physical Region Descriptor - one SG segment */
@@ -226,6 +255,42 @@ struct nv_host_priv {
unsigned long type;
};
+struct defer_queue {
+ u32 defer_bits;
+ unsigned int head;
+ unsigned int tail;
+ unsigned int tag[ATA_MAX_QUEUE];
+};
+
+enum ncq_saw_flag_list {
+ ncq_saw_d2h = (1U << 0),
+ ncq_saw_dmas = (1U << 1),
+ ncq_saw_sdb = (1U << 2),
+ ncq_saw_backout = (1U << 3),
+};
+
+struct nv_swncq_port_priv {
+ struct ata_prd *prd; /* our SG list */
+ dma_addr_t prd_dma; /* and its DMA mapping */
+ void __iomem *sactive_block;
+ void __iomem *irq_block;
+ void __iomem *tag_block;
+ u32 qc_active;
+
+ unsigned int last_issue_tag;
+
+ /* fifo circular queue to store deferral command */
+ struct defer_queue defer_queue;
+
+ /* for NCQ interrupt analysis */
+ u32 dhfis_bits;
+ u32 dmafis_bits;
+ u32 sdbfis_bits;
+
+ unsigned int ncq_flags;
+};
+
+
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -263,13 +328,29 @@ 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);
+static void nv_mcp55_thaw(struct ata_port *ap);
+static void nv_mcp55_freeze(struct ata_port *ap);
+static void nv_swncq_error_handler(struct ata_port *ap);
+static int nv_swncq_slave_config(struct scsi_device *sdev);
+static int nv_swncq_port_start(struct ata_port *ap);
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc);
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance);
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_swncq_port_resume(struct ata_port *ap);
+#endif
+
enum nv_host_type
{
GENERIC,
NFORCE2,
NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
CK804,
- ADMA
+ ADMA,
+ SWNCQ,
};
static const struct pci_device_id nv_pci_tbl[] = {
@@ -280,13 +361,13 @@ static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), SWNCQ },
{ } /* terminate list */
};
@@ -339,8 +420,26 @@ static struct scsi_host_template nv_adma_sht = {
.bios_param = ata_std_bios_param,
};
+static struct scsi_host_template nv_swncq_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = ATA_MAX_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 = nv_swncq_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
static const struct ata_port_operations nv_generic_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -359,14 +458,12 @@ static const struct ata_port_operations nv_generic_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_nf2_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -385,14 +482,12 @@ static const struct ata_port_operations nv_nf2_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_ck804_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -411,7 +506,6 @@ static const struct ata_port_operations nv_ck804_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
@@ -419,7 +513,6 @@ 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 = nv_adma_tf_read,
.check_atapi_dma = nv_adma_check_atapi_dma,
@@ -430,6 +523,7 @@ static const struct ata_port_operations nv_adma_ops = {
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = nv_adma_qc_prep,
.qc_issue = nv_adma_qc_issue,
.freeze = nv_adma_freeze,
@@ -439,7 +533,6 @@ static const struct ata_port_operations nv_adma_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = nv_adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
@@ -451,12 +544,41 @@ static const struct ata_port_operations nv_adma_ops = {
.host_stop = nv_adma_host_stop,
};
+static const struct ata_port_operations nv_swncq_ops = {
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
+ .qc_prep = nv_swncq_qc_prep,
+ .qc_issue = nv_swncq_qc_issue,
+ .freeze = nv_mcp55_freeze,
+ .thaw = nv_mcp55_thaw,
+ .error_handler = nv_swncq_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_data_xfer,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+#ifdef CONFIG_PM
+ .port_suspend = nv_swncq_port_suspend,
+ .port_resume = nv_swncq_port_resume,
+#endif
+ .port_start = nv_swncq_port_start,
+};
+
static const struct ata_port_info nv_port_info[] = {
/* generic */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -466,8 +588,8 @@ static const struct ata_port_info nv_port_info[] = {
/* nforce2/3 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -477,8 +599,8 @@ static const struct ata_port_info nv_port_info[] = {
/* ck804 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -489,14 +611,26 @@ static const struct ata_port_info nv_port_info[] = {
{
.sht = &nv_adma_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME |
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_adma_ops,
.irq_handler = nv_adma_interrupt,
},
+ /* SWNCQ */
+ {
+ .sht = &nv_swncq_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_NCQ,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_swncq_ops,
+ .irq_handler = nv_swncq_interrupt,
+ },
};
MODULE_AUTHOR("NVIDIA");
@@ -506,6 +640,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
static int adma_enabled = 1;
+static int swncq_enabled;
static void nv_adma_register_mode(struct ata_port *ap)
{
@@ -594,7 +729,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
/* Not a proper libata device, ignore */
return rc;
- if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+ if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
/*
* NVIDIA reports that ADMA mode does not support ATAPI commands.
* Therefore ATAPI commands are sent through the legacy interface.
@@ -711,7 +846,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
flags & (NV_CPB_RESP_ATA_ERR |
NV_CPB_RESP_CMD_ERR |
NV_CPB_RESP_CPB_ERR)))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
int freeze = 0;
ata_ehi_clear_desc(ehi);
@@ -747,7 +882,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
DPRINTK("Completing qc from tag %d\n",cpb_num);
ata_qc_complete(qc);
} else {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
/* Notifier bits set without a command may indicate the drive
is misbehaving. Raise host state machine violation on this
condition. */
@@ -764,7 +899,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
/* freeze if hotplugged */
if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -817,7 +952,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
>> (NV_INT_PORT_SHIFT * i);
- if(ata_tag_valid(ap->active_tag))
+ if(ata_tag_valid(ap->link.active_tag))
/** NV_INT_DEV indication seems unreliable at times
at least in ADMA mode. Force it on always when a
command is active, to prevent losing interrupts. */
@@ -852,7 +987,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
NV_ADMA_STAT_HOTUNPLUG |
NV_ADMA_STAT_TIMEOUT |
NV_ADMA_STAT_SERROR))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
__ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
@@ -879,10 +1014,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
u32 check_commands;
int pos, error = 0;
- if(ata_tag_valid(ap->active_tag))
- check_commands = 1 << ap->active_tag;
+ if(ata_tag_valid(ap->link.active_tag))
+ check_commands = 1 << ap->link.active_tag;
else
- check_commands = ap->sactive;
+ check_commands = ap->link.sactive;
/** Check CPBs for completed commands */
while ((pos = ffs(check_commands)) && !error) {
@@ -1333,7 +1468,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
else
@@ -1459,7 +1594,35 @@ static void nv_ck804_thaw(struct ata_port *ap)
writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
}
-static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+static void nv_mcp55_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+ int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+ u32 mask;
+
+ writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+ mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+ mask &= ~(NV_INT_ALL_MCP55 << shift);
+ writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+ ata_bmdma_freeze(ap);
+}
+
+static void nv_mcp55_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+ int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+ u32 mask;
+
+ writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+ mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+ mask |= (NV_INT_MASK_MCP55 << shift);
+ writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+ ata_bmdma_thaw(ap);
+}
+
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
unsigned int dummy;
@@ -1468,7 +1631,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class,
* some controllers. Don't classify on hardreset. For more
* info, see http://bugme.osdl.org/show_bug.cgi?id=3352
*/
- return sata_std_hardreset(ap, &dummy, deadline);
+ return sata_std_hardreset(link, &dummy, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -1485,7 +1648,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
int i;
u16 tmp;
- if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+ if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
@@ -1501,8 +1664,8 @@ static void nv_adma_error_handler(struct ata_port *ap)
for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
struct nv_adma_cpb *cpb = &pp->cpb[i];
- if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
- ap->sactive & (1 << i) )
+ if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+ ap->link.sactive & (1 << i) )
ata_port_printk(ap, KERN_ERR,
"CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
i, cpb->ctl_flags, cpb->resp_flags);
@@ -1532,6 +1695,663 @@ static void nv_adma_error_handler(struct ata_port *ap)
nv_hardreset, ata_std_postreset);
}
+static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+
+ /* queue is full */
+ WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE);
+ dq->defer_bits |= (1 << qc->tag);
+ dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag;
+}
+
+static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+ unsigned int tag;
+
+ if (dq->head == dq->tail) /* null queue */
+ return NULL;
+
+ tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)];
+ dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON;
+ WARN_ON(!(dq->defer_bits & (1 << tag)));
+ dq->defer_bits &= ~(1 << tag);
+
+ return ata_qc_from_tag(ap, tag);
+}
+
+static void nv_swncq_fis_reinit(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ pp->dhfis_bits = 0;
+ pp->dmafis_bits = 0;
+ pp->sdbfis_bits = 0;
+ pp->ncq_flags = 0;
+}
+
+static void nv_swncq_pp_reinit(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+
+ dq->head = 0;
+ dq->tail = 0;
+ dq->defer_bits = 0;
+ pp->qc_active = 0;
+ pp->last_issue_tag = ATA_TAG_POISON;
+ nv_swncq_fis_reinit(ap);
+}
+
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ writew(fis, pp->irq_block);
+}
+
+static void __ata_bmdma_stop(struct ata_port *ap)
+{
+ struct ata_queued_cmd qc;
+
+ qc.ap = ap;
+ ata_bmdma_stop(&qc);
+}
+
+static void nv_swncq_ncq_stop(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ unsigned int i;
+ u32 sactive;
+ u32 done_mask;
+
+ ata_port_printk(ap, KERN_ERR,
+ "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
+ ap->qc_active, ap->link.sactive);
+ ata_port_printk(ap, KERN_ERR,
+ "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n "
+ "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n",
+ pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag,
+ pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits);
+
+ ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n",
+ ap->ops->check_status(ap),
+ ioread8(ap->ioaddr.error_addr));
+
+ sactive = readl(pp->sactive_block);
+ done_mask = pp->qc_active ^ sactive;
+
+ ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n");
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ u8 err = 0;
+ if (pp->qc_active & (1 << i))
+ err = 0;
+ else if (done_mask & (1 << i))
+ err = 1;
+ else
+ continue;
+
+ ata_port_printk(ap, KERN_ERR,
+ "tag 0x%x: %01x %01x %01x %01x %s\n", i,
+ (pp->dhfis_bits >> i) & 0x1,
+ (pp->dmafis_bits >> i) & 0x1,
+ (pp->sdbfis_bits >> i) & 0x1,
+ (sactive >> i) & 0x1,
+ (err ? "error! tag doesn't exit" : " "));
+ }
+
+ nv_swncq_pp_reinit(ap);
+ ap->ops->irq_clear(ap);
+ __ata_bmdma_stop(ap);
+ nv_swncq_irq_clear(ap, 0xffff);
+}
+
+static void nv_swncq_error_handler(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->link.eh_context;
+
+ if (ap->link.sactive) {
+ nv_swncq_ncq_stop(ap);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+ nv_hardreset, ata_std_postreset);
+}
+
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ u32 tmp;
+
+ /* clear irq */
+ writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+ /* disable irq */
+ writel(0, mmio + NV_INT_ENABLE_MCP55);
+
+ /* disable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ);
+ writel(tmp, mmio + NV_CTL_MCP55);
+
+ return 0;
+}
+
+static int nv_swncq_port_resume(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ u32 tmp;
+
+ /* clear irq */
+ writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+ /* enable irq */
+ writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+ /* enable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+ return 0;
+}
+#endif
+
+static void nv_swncq_host_init(struct ata_host *host)
+{
+ u32 tmp;
+ void __iomem *mmio = host->iomap[NV_MMIO_BAR];
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ u8 regval;
+
+ /* disable ECO 398 */
+ pci_read_config_byte(pdev, 0x7f, &regval);
+ regval &= ~(1 << 7);
+ pci_write_config_byte(pdev, 0x7f, regval);
+
+ /* enable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ VPRINTK("HOST_CTL:0x%X\n", tmp);
+ writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+ /* enable irq intr */
+ tmp = readl(mmio + NV_INT_ENABLE_MCP55);
+ VPRINTK("HOST_ENABLE:0x%X\n", tmp);
+ writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+ /* clear port irq */
+ writel(~0x0, mmio + NV_INT_STATUS_MCP55);
+}
+
+static int nv_swncq_slave_config(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *dev;
+ int rc;
+ u8 rev;
+ u8 check_maxtor = 0;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ rc = ata_scsi_slave_config(sdev);
+ if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun)
+ /* Not a proper libata device, ignore */
+ return rc;
+
+ dev = &ap->link.device[sdev->id];
+ if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI)
+ return rc;
+
+ /* if MCP51 and Maxtor, then disable ncq */
+ if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA ||
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2)
+ check_maxtor = 1;
+
+ /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */
+ if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA ||
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) {
+ pci_read_config_byte(pdev, 0x8, &rev);
+ if (rev <= 0xa2)
+ check_maxtor = 1;
+ }
+
+ if (!check_maxtor)
+ return rc;
+
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+ if (strncmp(model_num, "Maxtor", 6) == 0) {
+ ata_scsi_change_queue_depth(sdev, 1);
+ ata_dev_printk(dev, KERN_NOTICE,
+ "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
+ }
+
+ return rc;
+}
+
+static int nv_swncq_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ struct nv_swncq_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE,
+ &pp->prd_dma, GFP_KERNEL);
+ if (!pp->prd)
+ return -ENOMEM;
+ memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE);
+
+ ap->private_data = pp;
+ pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE;
+ pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2;
+ pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2;
+
+ return 0;
+}
+
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (qc->tf.protocol != ATA_PROT_NCQ) {
+ ata_qc_prep(qc);
+ return;
+ }
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ nv_swncq_fill_sg(qc);
+}
+
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+ unsigned int idx;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_prd *prd;
+
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+ prd = pp->prd + ATA_MAX_PRD * qc->tag;
+
+ idx = 0;
+ ata_for_each_sg(sg, qc) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32)sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ prd[idx].addr = cpu_to_le32(addr);
+ prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ if (idx)
+ prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ if (qc == NULL)
+ return 0;
+
+ DPRINTK("Enter\n");
+
+ writel((1 << qc->tag), pp->sactive_block);
+ pp->last_issue_tag = qc->tag;
+ pp->dhfis_bits &= ~(1 << qc->tag);
+ pp->dmafis_bits &= ~(1 << qc->tag);
+ pp->qc_active |= (0x1 << qc->tag);
+
+ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->exec_command(ap, &qc->tf);
+
+ DPRINTK("Issued tag %u\n", qc->tag);
+
+ return 0;
+}
+
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ if (qc->tf.protocol != ATA_PROT_NCQ)
+ return ata_qc_issue_prot(qc);
+
+ DPRINTK("Enter\n");
+
+ if (!pp->qc_active)
+ nv_swncq_issue_atacmd(ap, qc);
+ else
+ nv_swncq_qc_to_dq(ap, qc); /* add qc to defer queue */
+
+ return 0;
+}
+
+static void nv_swncq_hotplug(struct ata_port *ap, u32 fis)
+{
+ u32 serror;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ ata_ehi_clear_desc(ehi);
+
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ sata_scr_read(&ap->link, SCR_ERROR, &serror);
+ sata_scr_write(&ap->link, SCR_ERROR, serror);
+
+ /* analyze @irq_stat */
+ if (fis & NV_SWNCQ_IRQ_ADDED)
+ ata_ehi_push_desc(ehi, "hot plug");
+ else if (fis & NV_SWNCQ_IRQ_REMOVED)
+ ata_ehi_push_desc(ehi, "hot unplug");
+
+ ata_ehi_hotplugged(ehi);
+
+ /* okay, let's hand over to EH */
+ ehi->serror |= serror;
+
+ ata_port_freeze(ap);
+}
+
+static int nv_swncq_sdbfis(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u32 sactive;
+ int nr_done = 0;
+ u32 done_mask;
+ int i;
+ u8 host_stat;
+ u8 lack_dhfis = 0;
+
+ host_stat = ap->ops->bmdma_status(ap);
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+ ehi->err_mask |= AC_ERR_HOST_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
+ return -EINVAL;
+ }
+
+ ap->ops->irq_clear(ap);
+ __ata_bmdma_stop(ap);
+
+ sactive = readl(pp->sactive_block);
+ done_mask = pp->qc_active ^ sactive;
+
+ if (unlikely(done_mask & sactive)) {
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
+ "(%08x->%08x)", pp->qc_active, sactive);
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_HARDRESET;
+ return -EINVAL;
+ }
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ if (!(done_mask & (1 << i)))
+ continue;
+
+ qc = ata_qc_from_tag(ap, i);
+ if (qc) {
+ ata_qc_complete(qc);
+ pp->qc_active &= ~(1 << i);
+ pp->dhfis_bits &= ~(1 << i);
+ pp->dmafis_bits &= ~(1 << i);
+ pp->sdbfis_bits |= (1 << i);
+ nr_done++;
+ }
+ }
+
+ if (!ap->qc_active) {
+ DPRINTK("over\n");
+ nv_swncq_pp_reinit(ap);
+ return nr_done;
+ }
+
+ if (pp->qc_active & pp->dhfis_bits)
+ return nr_done;
+
+ if ((pp->ncq_flags & ncq_saw_backout) ||
+ (pp->qc_active ^ pp->dhfis_bits))
+ /* if the controller cann't get a device to host register FIS,
+ * The driver needs to reissue the new command.
+ */
+ lack_dhfis = 1;
+
+ DPRINTK("id 0x%x QC: qc_active 0x%x,"
+ "SWNCQ:qc_active 0x%X defer_bits %X "
+ "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
+ ap->print_id, ap->qc_active, pp->qc_active,
+ pp->defer_queue.defer_bits, pp->dhfis_bits,
+ pp->dmafis_bits, pp->last_issue_tag);
+
+ nv_swncq_fis_reinit(ap);
+
+ if (lack_dhfis) {
+ qc = ata_qc_from_tag(ap, pp->last_issue_tag);
+ nv_swncq_issue_atacmd(ap, qc);
+ return nr_done;
+ }
+
+ if (pp->defer_queue.defer_bits) {
+ /* send deferral queue command */
+ qc = nv_swncq_qc_from_dq(ap);
+ WARN_ON(qc == NULL);
+ nv_swncq_issue_atacmd(ap, qc);
+ }
+
+ return nr_done;
+}
+
+static inline u32 nv_swncq_tag(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ u32 tag;
+
+ tag = readb(pp->tag_block) >> 2;
+ return (tag & 0x1f);
+}
+
+static int nv_swncq_dmafis(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ unsigned int rw;
+ u8 dmactl;
+ u32 tag;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ __ata_bmdma_stop(ap);
+ tag = nv_swncq_tag(ap);
+
+ DPRINTK("dma setup tag 0x%x\n", tag);
+ qc = ata_qc_from_tag(ap, tag);
+
+ if (unlikely(!qc))
+ return 0;
+
+ rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+ /* load PRD table addr. */
+ iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag,
+ ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~ATA_DMA_WR;
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+
+ iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ return 1;
+}
+
+static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u32 serror;
+ u8 ata_stat;
+ int rc = 0;
+
+ ata_stat = ap->ops->check_status(ap);
+ nv_swncq_irq_clear(ap, fis);
+ if (!fis)
+ return;
+
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ return;
+
+ if (fis & NV_SWNCQ_IRQ_HOTPLUG) {
+ nv_swncq_hotplug(ap, fis);
+ return;
+ }
+
+ if (!pp->qc_active)
+ return;
+
+ if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+ return;
+ ap->ops->scr_write(ap, SCR_ERROR, serror);
+
+ if (ata_stat & ATA_ERR) {
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis);
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->serror |= serror;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_BACKOUT) {
+ /* If the IRQ is backout, driver must issue
+ * the new command again some time later.
+ */
+ pp->ncq_flags |= ncq_saw_backout;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_SDBFIS) {
+ pp->ncq_flags |= ncq_saw_sdb;
+ DPRINTK("id 0x%x SWNCQ: qc_active 0x%X "
+ "dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
+ ap->print_id, pp->qc_active, pp->dhfis_bits,
+ pp->dmafis_bits, readl(pp->sactive_block));
+ rc = nv_swncq_sdbfis(ap);
+ if (rc < 0)
+ goto irq_error;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_DHREGFIS) {
+ /* The interrupt indicates the new command
+ * was transmitted correctly to the drive.
+ */
+ pp->dhfis_bits |= (0x1 << pp->last_issue_tag);
+ pp->ncq_flags |= ncq_saw_d2h;
+ if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) {
+ ata_ehi_push_desc(ehi, "illegal fis transaction");
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_HARDRESET;
+ goto irq_error;
+ }
+
+ if (!(fis & NV_SWNCQ_IRQ_DMASETUP) &&
+ !(pp->ncq_flags & ncq_saw_dmas)) {
+ ata_stat = ap->ops->check_status(ap);
+ if (ata_stat & ATA_BUSY)
+ goto irq_exit;
+
+ if (pp->defer_queue.defer_bits) {
+ DPRINTK("send next command\n");
+ qc = nv_swncq_qc_from_dq(ap);
+ nv_swncq_issue_atacmd(ap, qc);
+ }
+ }
+ }
+
+ if (fis & NV_SWNCQ_IRQ_DMASETUP) {
+ /* program the dma controller with appropriate PRD buffers
+ * and start the DMA transfer for requested command.
+ */
+ pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
+ pp->ncq_flags |= ncq_saw_dmas;
+ rc = nv_swncq_dmafis(ap);
+ }
+
+irq_exit:
+ return;
+irq_error:
+ ata_ehi_push_desc(ehi, "fis:0x%x", fis);
+ ata_port_freeze(ap);
+ return;
+}
+
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+ u32 irq_stat;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ if (ap->link.sactive) {
+ nv_swncq_host_interrupt(ap, (u16)irq_stat);
+ handled = 1;
+ } else {
+ if (irq_stat) /* reserve Hotplug */
+ nv_swncq_irq_clear(ap, 0xfff0);
+
+ handled += nv_host_intr(ap, (u8)irq_stat);
+ }
+ }
+ irq_stat >>= NV_INT_PORT_SHIFT_MCP55;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1558,7 +2378,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
/* determine type and allocate host */
- if (type >= CK804 && adma_enabled) {
+ if (type == CK804 && adma_enabled) {
dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
type = ADMA;
}
@@ -1604,6 +2424,9 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = nv_adma_host_init(host);
if (rc)
return rc;
+ } else if (type == SWNCQ && swncq_enabled) {
+ dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n");
+ nv_swncq_host_init(host);
}
pci_set_master(pdev);
@@ -1703,3 +2526,6 @@ module_init(nv_init);
module_exit(nv_exit);
module_param_named(adma, adma_enabled, bool, 0444);
MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+module_param_named(swncq, swncq_enabled, bool, 0444);
+MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: false)");
+
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 25698cf0dce..903213153b5 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = {
};
static const struct ata_port_operations pdc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -185,7 +184,6 @@ static const struct ata_port_operations pdc_sata_ops = {
.data_xfer = ata_data_xfer,
.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,
@@ -194,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = {
/* First-generation chips need a more restrictive ->check_atapi_dma op */
static const struct ata_port_operations pdc_old_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -212,7 +209,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
.data_xfer = ata_data_xfer,
.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,
@@ -220,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
};
static const struct ata_port_operations pdc_pata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -238,7 +233,6 @@ static const struct ata_port_operations pdc_pata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_common_port_start,
};
@@ -475,7 +469,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
buf32[2] = 0; /* no next-packet */
/* select drive */
- if (sata_scr_valid(ap)) {
+ if (sata_scr_valid(&ap->link)) {
dev_sel = PDC_DEVICE_SATA;
} else {
dev_sel = ATA_DEVICE_OBS;
@@ -626,7 +620,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
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;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned int ac_err_mask = 0;
ata_ehi_clear_desc(ehi);
@@ -643,7 +637,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS;
- if (sata_scr_valid(ap)) {
+ if (sata_scr_valid(&ap->link)) {
u32 serror;
pdc_sata_scr_read(ap, SCR_ERROR, &serror);
@@ -773,7 +767,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
tmp = hotplug_status & (0x11 << ata_no);
if (tmp && ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
@@ -788,7 +782,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
@@ -1009,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- pdc_ata_setup_port(host->ports[i],
- base + 0x200 + ata_no * 0x80,
- base + 0x400 + ata_no * 0x100);
+ unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+ pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 5e1dfdda698..c4c4cd29eeb 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = {
};
static const struct ata_port_operations qs_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -159,7 +158,6 @@ static const struct ata_port_operations qs_ata_ops = {
.eng_timeout = qs_eng_timeout,
.irq_clear = qs_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
@@ -404,7 +402,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* successful CPB */
@@ -437,7 +435,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
@@ -637,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev,
return rc;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
- void __iomem *chan =
- host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
- qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
+ struct ata_port *ap = host->ports[port_no];
+ unsigned int offset = port_no * 0x4000;
+ void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset;
+
+ qs_ata_setup_port(&ap->ioaddr, chan);
+
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 8c72e714b45..ea3a0ab7e02 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -59,7 +59,8 @@ enum {
SIL_FLAG_MOD15WRITE = (1 << 30),
SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+ ATA_FLAG_MMIO,
+ SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME,
/*
* Controller IDs
@@ -117,7 +118,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_device *dev);
static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -185,7 +186,6 @@ static struct scsi_host_template sil_sht = {
};
static const struct ata_port_operations sil_ops = {
- .port_disable = ata_port_disable,
.dev_config = sil_dev_config,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -206,7 +206,6 @@ static const struct ata_port_operations sil_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
@@ -216,6 +215,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -225,6 +225,7 @@ static const struct ata_port_info sil_port_info[] = {
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -233,6 +234,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3512 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -241,6 +243,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3114 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -290,35 +293,33 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
/**
* sil_set_mode - wrap set_mode functions
- * @ap: port to set up
+ * @link: link 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)
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- struct ata_host *host = ap->host;
- struct ata_device *dev;
- void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+ struct ata_port *ap = link->ap;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
- u32 tmp, dev_mode[2];
- unsigned int i;
+ struct ata_device *dev;
+ u32 tmp, dev_mode[2] = { };
int rc;
- rc = ata_do_set_mode(ap, r_failed);
+ rc = ata_do_set_mode(link, r_failed);
if (rc)
return rc;
- for (i = 0; i < 2; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
- dev_mode[i] = 0; /* PIO0/1/2 */
+ dev_mode[dev->devno] = 0; /* PIO0/1/2 */
else if (dev->flags & ATA_DFLAG_PIO)
- dev_mode[i] = 1; /* PIO3/4 */
+ dev_mode[dev->devno] = 1; /* PIO3/4 */
else
- dev_mode[i] = 3; /* UDMA */
+ dev_mode[dev->devno] = 3; /* UDMA */
/* value 2 indicates MDMA */
}
@@ -374,8 +375,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
{
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 status;
if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -394,8 +395,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* repeat probing needlessly.
*/
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
- ata_ehi_hotplugged(&ap->eh_info);
- ap->eh_info.serror |= serror;
+ ata_ehi_hotplugged(&ap->link.eh_info);
+ ap->link.eh_info.serror |= serror;
}
goto freeze;
@@ -562,8 +563,8 @@ static void sil_thaw(struct ata_port *ap)
*/
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;
+ struct ata_port *ap = dev->link->ap;
+ int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -686,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
mmio_base = host->iomap[SIL_MMIO_BAR];
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
ioaddr->altstatus_addr =
@@ -694,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
ioaddr->scr_addr = mmio_base + sil_port[i].scr;
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
}
/* initialize and activate */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 233e8869339..b0619278454 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
/*
* Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@ enum {
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
@@ -237,8 +237,9 @@ enum {
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_AN | ATA_FLAG_PMP,
+ SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
IRQ_STAT_4PORTS = 0xf,
@@ -322,6 +323,7 @@ struct sil24_port_priv {
union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
dma_addr_t cmd_block_dma; /* DMA base addr for them */
struct ata_taskfile tf; /* Cached taskfile registers */
+ int do_port_rst;
};
static void sil24_dev_config(struct ata_device *dev);
@@ -329,9 +331,12 @@ static u8 sil24_check_status(struct ata_port *ap);
static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
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 void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
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);
@@ -340,6 +345,7 @@ static int sil24_port_start(struct ata_port *ap);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
@@ -384,8 +390,6 @@ static struct scsi_host_template sil24_sht = {
};
static const struct ata_port_operations sil24_ops = {
- .port_disable = ata_port_disable,
-
.dev_config = sil24_dev_config,
.check_status = sil24_check_status,
@@ -394,22 +398,28 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
+ .qc_defer = sil24_qc_defer,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
.irq_clear = sil24_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
+ .pmp_attach = sil24_pmp_attach,
+ .pmp_detach = sil24_pmp_detach,
+
.freeze = sil24_freeze,
.thaw = sil24_thaw,
.error_handler = sil24_error_handler,
.post_internal_cmd = sil24_post_internal_cmd,
.port_start = sil24_port_start,
+
+#ifdef CONFIG_PM
+ .port_resume = sil24_port_resume,
+#endif
};
/*
@@ -424,6 +434,7 @@ static const struct ata_port_info sil24_port_info[] = {
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -432,6 +443,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3132 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -440,6 +452,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3131/sil_3531 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -456,7 +469,7 @@ static int sil24_tag(int tag)
static void sil24_dev_config(struct ata_device *dev)
{
- void __iomem *port = dev->ap->ioaddr.cmd_addr;
+ void __iomem *port = dev->link->ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -520,19 +533,78 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*tf = pp->tf;
}
+static void sil24_config_port(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ /* configure IRQ WoC */
+ if (ap->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);
+
+ /* zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* clear port multiplier enable and resume bits */
+ writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ if (attached)
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+ int i;
+
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+ void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+ writel(0, pmp_base + PORT_PMP_STATUS);
+ writel(0, pmp_base + PORT_PMP_QACTIVE);
+ }
+}
+
static int sil24_init_port(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
u32 tmp;
+ /* clear PMP error status */
+ if (ap->nr_pmp_links)
+ sil24_clear_pmp(ap);
+
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_INIT, PORT_CS_INIT, 10, 100);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_RDY, 0, 10, 100);
- if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+ pp->do_port_rst = 1;
+ ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
return -EIO;
+ }
+
return 0;
}
@@ -583,9 +655,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
return rc;
}
-static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned long timeout_msec = 0;
struct ata_taskfile tf;
const char *reason;
@@ -593,7 +666,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
goto out;
@@ -609,7 +682,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
if (time_after(deadline, jiffies))
timeout_msec = jiffies_to_msecs(deadline - jiffies);
- ata_tf_init(ap->device, &tf); /* doesn't really matter */
+ ata_tf_init(link->device, &tf); /* doesn't really matter */
rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
timeout_msec);
if (rc == -EBUSY) {
@@ -631,29 +704,54 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
return 0;
err:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return -EIO;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- return sil24_do_softreset(ap, class, 0, deadline);
+ return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
}
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+static int sil24_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
+ int did_port_rst = 0;
const char *reason;
int tout_msec, rc;
u32 tmp;
+ retry:
+ /* Sometimes, DEV_RST is not enough to recover the controller.
+ * This happens often after PM DMA CS errata.
+ */
+ if (pp->do_port_rst) {
+ ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+ "state, performing PORT_RST\n");
+
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+ msleep(10);
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+ 10, 5000);
+
+ /* restore port configuration */
+ sil24_config_port(ap);
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+
+ pp->do_port_rst = 0;
+ did_port_rst = 1;
+ }
+
/* sil24 does the right thing(tm) without any protection */
- sata_set_spd(ap);
+ sata_set_spd(link);
tout_msec = 100;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
tout_msec = 5000;
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -663,14 +761,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
+ rc = sata_link_debounce(link, sata_deb_timing_long, deadline);
if (rc) {
reason = "PHY debouncing failed";
goto err;
}
if (tmp & PORT_CS_DEV_RST) {
- if (ata_port_offline(ap))
+ if (ata_link_offline(link))
return 0;
reason = "link not ready";
goto err;
@@ -685,7 +783,12 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
return -EAGAIN;
err:
- ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+ if (!did_port_rst) {
+ pp->do_port_rst = 1;
+ goto retry;
+ }
+
+ ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
return -EIO;
}
@@ -705,6 +808,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
}
}
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ u8 prot = qc->tf.protocol;
+ int is_atapi = (prot == ATA_PROT_ATAPI ||
+ prot == ATA_PROT_ATAPI_NODATA ||
+ prot == ATA_PROT_ATAPI_DMA);
+
+ /* ATAPI commands completing with CHECK_SENSE cause various
+ * weird problems if other commands are active. PMP DMA CS
+ * errata doesn't cover all and HSM violation occurs even with
+ * only one other device active. Always run an ATAPI command
+ * by itself.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ } else
+ return ATA_DEFER_PORT;
+ } else if (unlikely(is_atapi)) {
+ ap->excl_link = link;
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ }
+
+ return ata_std_qc_defer(qc);
+}
+
static void sil24_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -748,7 +883,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
@@ -777,6 +912,39 @@ static void sil24_irq_clear(struct ata_port *ap)
/* unused */
}
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, 1);
+ sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+ sil24_init_port(ap);
+ sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int rc;
+
+ rc = sil24_init_port(link->ap);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "hardreset failed (port not ready)\n");
+ return rc;
+ }
+
+ return sata_pmp_std_hardreset(link, class, deadline);
+}
+
static void sil24_freeze(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
@@ -804,8 +972,10 @@ static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- int freeze = 0;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_link *link;
+ struct ata_eh_info *ehi;
+ int abort = 0, freeze = 0;
u32 irq_stat;
/* on error, we need to clear IRQ explicitly */
@@ -813,10 +983,17 @@ static void sil24_error_intr(struct ata_port *ap)
writel(irq_stat, port + PORT_IRQ_STAT);
/* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+ ata_ehi_push_desc(ehi, "SDB notify");
+ sata_async_notification(ap);
+ }
+
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "%s",
@@ -836,8 +1013,44 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & PORT_IRQ_ERROR) {
struct sil24_cerr_info *ci = NULL;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- u32 cerr;
+ u32 context, cerr;
+ int pmp;
+
+ abort = 1;
+
+ /* DMA Context Switch Failure in Port Multiplier Mode
+ * errata. If we have active commands to 3 or more
+ * devices, any error condition on active devices can
+ * corrupt DMA context switching.
+ */
+ if (ap->nr_active_links >= 3) {
+ ehi->err_mask |= AC_ERR_OTHER;
+ ehi->action |= ATA_EH_HARDRESET;
+ ata_ehi_push_desc(ehi, "PMP DMA CS errata");
+ pp->do_port_rst = 1;
+ freeze = 1;
+ }
+
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ context = readl(port + PORT_CONTEXT);
+ pmp = (context >> 5) & 0xf;
+
+ if (pmp < ap->nr_pmp_links) {
+ link = &ap->pmp_link[pmp];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x",
+ irq_stat);
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else
+ qc = ata_qc_from_tag(ap, link->active_tag);
/* analyze CMD_ERR */
cerr = readl(port + PORT_CMD_ERR);
@@ -856,7 +1069,6 @@ static void sil24_error_intr(struct ata_port *ap)
}
/* record error info */
- qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
@@ -864,13 +1076,21 @@ static void sil24_error_intr(struct ata_port *ap)
ehi->err_mask |= err_mask;
ehi->action |= action;
+
+ /* if PMP, resume */
+ if (ap->nr_pmp_links)
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
}
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sil24_finish_qc(struct ata_queued_cmd *qc)
@@ -910,7 +1130,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
if (rc > 0)
return;
if (rc < 0) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
ata_port_freeze(ap);
@@ -921,7 +1141,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
- slot_stat, ap->active_tag, ap->sactive);
+ slot_stat, ap->link.active_tag, ap->link.sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
@@ -963,16 +1183,18 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
static void sil24_error_handler(struct ata_port *ap)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct sil24_port_priv *pp = ap->private_data;
- if (sil24_init_port(ap)) {
+ if (sil24_init_port(ap))
ata_eh_freeze_port(ap);
- ehc->i.action |= ATA_EH_HARDRESET;
- }
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
- ata_std_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset, sata_pmp_std_prereset,
+ sil24_pmp_softreset, sil24_pmp_hardreset,
+ sata_pmp_std_postreset);
+
+ pp->do_port_rst = 0;
}
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -980,8 +1202,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
- sil24_init_port(ap);
+ if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+ ata_eh_freeze_port(ap);
}
static int sil24_port_start(struct ata_port *ap)
@@ -1019,7 +1241,6 @@ static int sil24_port_start(struct ata_port *ap)
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;
@@ -1031,7 +1252,8 @@ static void sil24_init_controller(struct ata_host *host)
/* init ports */
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port = ap->ioaddr.cmd_addr;
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
@@ -1048,26 +1270,8 @@ static void sil24_init_controller(struct ata_host *host)
"failed to clear port RST\n");
}
- /* Configure 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);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
- port + PORT_CTRL_CLR);
+ /* configure port */
+ sil24_config_port(ap);
}
/* Turn on interrupts */
@@ -1118,12 +1322,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap;
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ size_t offset = ap->port_no * PORT_REGS_SIZE;
+ void __iomem *port = iomap[SIL24_PORT_BAR] + offset;
host->ports[i]->ioaddr.cmd_addr = port;
host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
- ata_std_ports(&host->ports[i]->ioaddr);
+ ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host");
+ ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port");
}
/* configure and activate the device */
@@ -1179,6 +1386,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+ return 0;
+}
#endif
static int __init sil24_init(void)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 41c1d6e8f1f..8d98a9fb0a4 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -123,7 +122,6 @@ static const struct ata_port_operations sis_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index d9678e7bc3a..12d613c48c1 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = {
static const struct ata_port_operations k2_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = k2_sata_tf_load,
.tf_read = k2_sata_tf_read,
.check_status = k2_stat_check_status,
@@ -349,7 +348,6 @@ static const struct ata_port_operations k2_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
@@ -445,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* 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);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = i * K2_SATA_PORT_OFFSET;
+
+ k2_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, 5, -1, "mmio");
+ ata_port_pbar_desc(ap, 5, offset, "port");
+ }
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 97aefdd87be..9f9f7b30654 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = {
};
static const struct ata_port_operations pdc_20621_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -267,7 +266,6 @@ static const struct ata_port_operations pdc_20621_ops = {
.eng_timeout = pdc_eng_timeout,
.irq_clear = pdc20621_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
};
@@ -854,7 +852,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
@@ -881,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -1383,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
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;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1411,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
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);
+ for (i = 0; i < 4; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+ unsigned int offset = 0x200 + i * 0x80;
+
+ pdc_sata_setup_port(&ap->ioaddr, base + offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
+ }
/* configure and activate */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index e6b8b45279a..d394da085ae 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = {
};
static const struct ata_port_operations uli_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -117,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
@@ -242,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 0) + 8,
+ ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 16);
+
ioaddr = &host->ports[3]->ioaddr;
ioaddr->cmd_addr = iomap[2] + 8;
ioaddr->altstatus_addr =
@@ -250,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
ata_std_ports(ioaddr);
+
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 2) + 9,
+ ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 24);
+
break;
case uli_5289:
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 57fd30de8f0..cc6ee0890f5 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -57,7 +57,6 @@ enum {
SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
- SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
PATA_PIO_TIMING = 0xAB, /* PATA timing register */
@@ -68,7 +67,6 @@ enum {
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
- SATA_2DEV = (1 << 5), /* SATA is master/slave */
};
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -122,8 +120,6 @@ static struct scsi_host_template svia_sht = {
};
static const struct ata_port_operations vt6420_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -146,14 +142,11 @@ static const struct ata_port_operations vt6420_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_pata_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
@@ -180,14 +173,11 @@ static const struct ata_port_operations vt6421_pata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -211,7 +201,6 @@ static const struct ata_port_operations vt6421_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
@@ -276,7 +265,7 @@ static void svia_noop_freeze(struct ata_port *ap)
/**
* vt6420_prereset - prereset for vt6420
- * @ap: target ATA port
+ * @link: target ATA link
* @deadline: deadline jiffies for the operation
*
* SCR registers on vt6420 are pieces of shit and may hang the
@@ -294,9 +283,10 @@ static void svia_noop_freeze(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
unsigned long timeout = jiffies + (HZ * 5);
u32 sstatus, scontrol;
int online;
@@ -407,6 +397,9 @@ static void vt6421_init_addrs(struct ata_port *ap)
ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, ap->port_no, -1, "port");
+ ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
}
static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
@@ -512,8 +505,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
struct ata_host *host;
int board_id = (int) ent->driver_data;
- const int *bar_sizes;
- u8 tmp8;
+ const unsigned *bar_sizes;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -522,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if (board_id == vt6420) {
- pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
- if (tmp8 & SATA_2DEV) {
- dev_printk(KERN_ERR, &pdev->dev,
- "SATA master/slave not supported (0x%x)\n",
- (int) tmp8);
- return -EIO;
- }
-
+ if (board_id == vt6420)
bar_sizes = &svia_bar_sizes[0];
- } else {
+ else
bar_sizes = &vt6421_bar_sizes[0];
- }
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
if ((pci_resource_start(pdev, i) == 0) ||
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1920915dfa2..0d9be168487 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -240,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
return;
}
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled = ata_host_intr(ap, qc);
@@ -317,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = {
static const struct ata_port_operations vsc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = vsc_sata_tf_load,
.tf_read = vsc_sata_tf_read,
.exec_command = ata_exec_command,
@@ -336,7 +335,6 @@ static const struct ata_port_operations vsc_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
@@ -408,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
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);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
+
+ vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
+ }
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 8296420ceae..ff2a303cbe0 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -626,7 +626,7 @@ typedef struct {
struct amb_dev {
u8 irq;
- long flags;
+ unsigned long flags;
u32 iobase;
u32 * membase;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 737cea49f87..94ebc9dc40f 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1295,7 +1295,7 @@ static const struct atmdev_ops ops = {
static void __devinit undocumented_pci_fix (struct pci_dev *pdev)
{
- int tint;
+ u32 tint;
/* The Windows driver says: */
/* Switch off FireStream Retry Limit Threshold
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index 4461229f56a..b48859d0d43 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -423,7 +423,7 @@ struct hrz_dev {
wait_queue_head_t tx_queue;
u8 irq;
- long flags;
+ unsigned long flags;
u8 tx_last;
u8 tx_idle;
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5d6312e3349..d7da109c24f 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -1,5 +1,13 @@
menu "Generic Driver Options"
+config UEVENT_HELPER_PATH
+ string "path to uevent helper"
+ depends on HOTPLUG
+ default "/sbin/hotplug"
+ help
+ Path to uevent helper program forked by the kernel for
+ every uevent.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 47eb02d9f1a..10b2fb6c9ce 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -18,8 +18,6 @@ extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev);
extern void bus_attach_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 61c67526a65..9a19b071c57 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -30,6 +30,17 @@
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+ return bus ? container_of(kset_get(&bus->subsys),
+ struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+ kset_put(&bus->subsys);
+}
+
static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
@@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj)
*/
}
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
@@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = {
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
} else
error = -EINVAL;
return error;
@@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
}
}
@@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data)
static ssize_t driver_unbind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
err = count;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
static ssize_t driver_bind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv,
err = -ENODEV;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
*/
int bus_add_device(struct device * dev)
{
- struct bus_type * bus = get_bus(dev->bus);
+ struct bus_type * bus = bus_get(dev->bus);
int error = 0;
if (bus) {
@@ -459,7 +470,7 @@ out_subsys:
out_id:
device_remove_attrs(bus, dev);
out_put:
- put_bus(dev->bus);
+ bus_put(dev->bus);
return error;
}
@@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev)
}
pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
device_release_driver(dev);
- put_bus(dev->bus);
+ bus_put(dev->bus);
}
}
@@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv)
driver_remove_file(drv, &driver_attr_unbind);
}
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+ show_drivers_autoprobe, store_drivers_autoprobe);
+
static int add_probe_files(struct bus_type *bus)
{
int retval;
- bus->drivers_probe_attr.attr.name = "drivers_probe";
- bus->drivers_probe_attr.attr.mode = S_IWUSR;
- bus->drivers_probe_attr.store = store_drivers_probe;
- retval = bus_create_file(bus, &bus->drivers_probe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_probe);
if (retval)
goto out;
- bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
- bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
- bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
- bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
- retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
if (retval)
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
out:
return retval;
}
static void remove_probe_files(struct bus_type *bus)
{
- bus_remove_file(bus, &bus->drivers_autoprobe_attr);
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
}
#else
static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; }
static inline void remove_probe_files(struct bus_type *bus) {}
#endif
+static ssize_t driver_uevent_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&drv->kobj, action);
+ return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
@@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {}
*/
int bus_add_driver(struct device_driver *drv)
{
- struct bus_type * bus = get_bus(drv->bus);
+ struct bus_type * bus = bus_get(drv->bus);
int error = 0;
if (!bus)
@@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
+ error = driver_create_file(drv, &driver_attr_uevent);
+ if (error) {
+ printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv)
out_unregister:
kobject_unregister(&drv->kobj);
out_put_bus:
- put_bus(bus);
+ bus_put(bus);
return error;
}
@@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv)
remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
+ driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->knode_bus);
pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
driver_detach(drv);
module_remove_driver(drv);
kobject_unregister(&drv->kobj);
- put_bus(drv->bus);
+ bus_put(drv->bus);
}
@@ -729,18 +754,6 @@ int device_reprobe(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_reprobe);
-struct bus_type *get_bus(struct bus_type *bus)
-{
- return bus ? container_of(subsys_get(&bus->subsys),
- struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
- subsys_put(&bus->subsys);
-}
-
-
/**
* find_bus - locate bus by name.
* @name: name of bus.
@@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n)
put_device(dev);
}
+static ssize_t bus_uevent_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&bus->subsys.kobj, action);
+ return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
/**
* bus_register - register a bus with the system.
* @bus: bus.
@@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus)
if (retval)
goto out;
- subsys_set_kset(bus, bus_subsys);
+ bus->subsys.kobj.kset = &bus_subsys;
+
retval = subsystem_register(&bus->subsys);
if (retval)
goto out;
+ retval = bus_create_file(bus, &bus_attr_uevent);
+ if (retval)
+ goto bus_uevent_fail;
+
kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.kobj.parent = &bus->subsys.kobj;
retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus)
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.kobj.parent = &bus->subsys.kobj;
- bus->drivers.ktype = &ktype_driver;
+ bus->drivers.ktype = &driver_ktype;
retval = kset_register(&bus->drivers);
if (retval)
goto bus_drivers_fail;
@@ -866,6 +895,8 @@ bus_probe_files_fail:
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
+ bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
subsystem_unregister(&bus->subsys);
out:
return retval;
@@ -876,7 +907,7 @@ out:
* @bus: bus.
*
* Unregister the child subsystems and the bus itself.
- * Finally, we call put_bus() to release the refcount
+ * Finally, we call bus_put() to release the refcount
*/
void bus_unregister(struct bus_type * bus)
{
@@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus)
remove_probe_files(bus);
kset_unregister(&bus->drivers);
kset_unregister(&bus->devices);
+ bus_remove_file(bus, &bus_attr_uevent);
subsystem_unregister(&bus->subsys);
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d2222618b7..a863bb091e1 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = {
.store = class_attr_store,
};
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
};
/* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
static struct class *class_get(struct class *cls)
{
if (cls)
- return container_of(subsys_get(&cls->subsys), struct class, subsys);
+ return container_of(kset_get(&cls->subsys), struct class, subsys);
return NULL;
}
static void class_put(struct class * cls)
{
if (cls)
- subsys_put(&cls->subsys);
+ kset_put(&cls->subsys);
}
@@ -149,7 +149,7 @@ int class_register(struct class * cls)
if (error)
return error;
- subsys_set_kset(cls, class_subsys);
+ cls->subsys.kobj.kset = &class_subsys;
error = subsystem_register(&cls->subsys);
if (!error) {
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev)
/* needed to allow these devices to have parent class devices */
static int class_device_create_uevent(struct class_device *class_dev,
- char **envp, int num_envp,
- char *buffer, int buffer_size)
+ struct kobj_uevent_env *env)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
return 0;
@@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
.sysfs_ops = &class_dev_sysfs_ops,
.release = class_dev_release,
};
@@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_class_device) {
+ if (ktype == &class_device_ktype) {
struct class_device *class_dev = to_class_dev(kobj);
if (class_dev->class)
return 1;
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd)
{ }
#endif
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct class_device *class_dev = to_class_dev(kobj);
struct device *dev = class_dev->dev;
- int i = 0;
- int length = 0;
int retval = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (MAJOR(class_dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(class_dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(class_dev->devt));
+ add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
}
if (dev) {
const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
if (path) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
if (class_dev->uevent) {
/* have the class device specific function add its stuff */
- retval = class_dev->uevent(class_dev, envp, num_envp,
- buffer, buffer_size);
+ retval = class_dev->uevent(class_dev, env);
if (retval)
pr_debug("class_dev->uevent() returned %d\n", retval);
} else if (class_dev->class->uevent) {
/* have the class specific function add its stuff */
- retval = class_dev->class->uevent(class_dev, envp, num_envp,
- buffer, buffer_size);
+ retval = class_dev->class->uevent(class_dev, env);
if (retval)
pr_debug("class->uevent() returned %d\n", retval);
}
@@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = {
.uevent = class_uevent,
};
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@ int __init classes_init(void)
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs... */
- subsystem_init(&class_obj_subsys);
+ kset_init(&class_obj_subsys);
if (!class_obj_subsys.kobj.parent)
class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ec86d6fc236..c1343414d28 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
};
@@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_device) {
+ if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj);
if (dev->uevent_suppress)
return 0;
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
return NULL;
}
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct device *dev = to_dev(kobj);
- int i = 0;
- int length = 0;
int retval = 0;
/* add the major/minor if present */
if (MAJOR(dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+ add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
if (dev->type && dev->type->name)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVTYPE=%s", dev->type->name);
+ add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "DRIVER=%s", dev->driver->name);
#ifdef CONFIG_SYSFS_DEPRECATED
if (dev->class) {
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
path = kobject_get_path(&parent->kobj, GFP_KERNEL);
if (path) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", parent->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
if (parent->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", parent->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s",
+ parent->driver->name);
}
} else if (dev->bus) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
#endif
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
+ /* have the bus specific function add its stuff */
if (dev->bus && dev->bus->uevent) {
- /* have the bus specific function add its stuff */
- retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the class specific function add its stuff */
if (dev->class && dev->class->dev_uevent) {
- /* have the class specific function add its stuff */
- retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("%s: class uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the device type specific fuction add its stuff */
if (dev->type && dev->type->uevent) {
- /* have the device type specific fuction add its stuff */
- retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("%s: dev_type uevent() returned %d\n",
__FUNCTION__, retval);
@@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
{
struct kobject *top_kobj;
struct kset *kset;
- char *envp[32];
- char *data = NULL;
- char *pos;
+ struct kobj_uevent_env *env = NULL;
int i;
size_t count = 0;
int retval;
/* search the kset, the device belongs to */
top_kobj = &dev->kobj;
- if (!top_kobj->kset && top_kobj->parent) {
- do {
- top_kobj = top_kobj->parent;
- } while (!top_kobj->kset && top_kobj->parent);
- }
+ while (!top_kobj->kset && top_kobj->parent)
+ top_kobj = top_kobj->parent;
if (!top_kobj->kset)
goto out;
+
kset = top_kobj->kset;
if (!kset->uevent_ops || !kset->uevent_ops->uevent)
goto out;
@@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
if (!kset->uevent_ops->filter(kset, &dev->kobj))
goto out;
- data = (char *)get_zeroed_page(GFP_KERNEL);
- if (!data)
+ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ if (!env)
return -ENOMEM;
/* let the kset specific function add its keys */
- pos = data;
- memset(envp, 0, sizeof(envp));
- retval = kset->uevent_ops->uevent(kset, &dev->kobj,
- envp, ARRAY_SIZE(envp),
- pos, PAGE_SIZE);
+ retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
if (retval)
goto out;
/* copy keys to file */
- for (i = 0; envp[i]; i++) {
- pos = &buf[count];
- count += sprintf(pos, "%s\n", envp[i]);
- }
+ for (i = 0; i < env->envp_idx; i++)
+ count += sprintf(&buf[count], "%s\n", env->envp[i]);
out:
- free_page((unsigned long)data);
+ kfree(env);
return count;
}
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- size_t len = count;
enum kobject_action action;
- if (len && buf[len-1] == '\n')
- len--;
-
- for (action = 0; action < KOBJ_MAX; action++) {
- if (strncmp(kobject_actions[action], buf, len) != 0)
- continue;
- if (kobject_actions[action][len] != '\0')
- continue;
+ if (kobject_action_type(buf, count, &action) == 0) {
kobject_uevent(&dev->kobj, action);
goto out;
}
@@ -449,7 +405,7 @@ static struct device_attribute devt_attr =
* devices_subsys - structure to be registered with kobject core.
*/
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
/**
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b24efd4e3e3..0295855a3ee 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
static void fw_dev_release(struct device *dev);
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "FIRMWARE=%s", fw_priv->fw_id))
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "TIMEOUT=%i", loading_timeout))
+ if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
@@ -297,8 +292,7 @@ firmware_class_timeout(u_long data)
static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
{
- /* XXX warning we should watch out for name collisions */
- strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+ snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
}
static int fw_register_device(struct device **dev_p, const char *fw_name,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 74b96795d2f..7a1390cd6aa 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
return MEMORY_CLASS_NAME;
}
-static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
{
int retval = 0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 869ff8c0014..fb560924148 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev)
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
- *
- * This device will be marked as not supporting hotpluggable drivers; no
- * device add/remove uevents will be generated. In the unusual case that
- * the device isn't being dynamically allocated as a legacy "probe the
- * hardware" driver, infrastructure code should reverse this marking.
*/
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
-
- /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
- * legacy probe-the-hardware drivers, which don't properly split
- * out device enumeration logic from drivers.
- */
- pa->pdev.dev.uevent_suppress = 1;
}
return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev)
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
- snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+ snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
+ pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
@@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
* the Linux driver model. In particular, when such drivers are built
* as modules, they can't be "hotplugged".
*/
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
struct resource *res, unsigned int num)
{
struct platform_device *pdev;
@@ -530,7 +520,7 @@ static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
- int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+ int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = {
__ATTR_NULL,
};
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+ add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
return 0;
}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 9caeaea753a..a803733c839 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
obj-y := shutdown.o
-obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o
+obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index eb9f38d0aa5..0ab4ab21f56 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,19 +20,24 @@
*/
#include <linux/device.h>
+#include <linux/kallsyms.h>
#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
+#include "../base.h"
#include "power.h"
LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
int device_pm_add(struct device *dev)
{
int error;
@@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev)
}
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ * resume_device - Restore state for one device.
+ * @dev: Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+
+ down(&dev->sem);
+
+ if (dev->bus && dev->bus->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->bus->resume(dev);
+ }
+
+ if (!error && dev->type && dev->type->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->type->resume(dev);
+ }
+
+ if (!error && dev->class && dev->class->resume) {
+ dev_dbg(dev,"class resume\n");
+ error = dev->class->resume(dev);
+ }
+
+ up(&dev->sem);
+
+ TRACE_RESUME(error);
+ return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+ if (dev->bus && dev->bus->resume_early) {
+ dev_dbg(dev,"EARLY resume\n");
+ error = dev->bus->resume_early(dev);
+ }
+ TRACE_RESUME(error);
+ return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+ mutex_lock(&dpm_list_mtx);
+ while(!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.next;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ list_move_tail(entry, &dpm_active);
+
+ mutex_unlock(&dpm_list_mtx);
+ resume_device(dev);
+ mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ * device_resume - Restore state of each device in system.
+ *
+ * Walk the dpm_off list, remove each entry, resume the device,
+ * then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ dpm_resume();
+ mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ * dpm_power_up - Power on some devices.
+ *
+ * Walk the dpm_off_irq list and power each device up. This
+ * is used for devices that required they be powered down with
+ * interrupts disabled. As devices are powered on, they are moved
+ * to the dpm_active list.
+ *
+ * Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+ while(!list_empty(&dpm_off_irq)) {
+ struct list_head * entry = dpm_off_irq.next;
+ struct device * dev = to_device(entry);
+
+ list_move_tail(entry, &dpm_off);
+ resume_device_early(dev);
+ }
+}
+
+
+/**
+ * device_power_up - Turn on all devices that need special attention.
+ *
+ * Power on system devices then devices that required we shut them down
+ * with interrupts disabled.
+ * Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+ sysdev_resume();
+ dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+ switch (event) {
+ case PM_EVENT_SUSPEND: return "suspend";
+ case PM_EVENT_FREEZE: return "freeze";
+ case PM_EVENT_PRETHAW: return "prethaw";
+ default: return "(unknown suspend event)";
+ }
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+ dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+ ", may wakeup" : "");
+}
+
+/**
+ * suspend_device - Save state of one device.
+ * @dev: Device.
+ * @state: Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+ int error = 0;
+
+ down(&dev->sem);
+ if (dev->power.power_state.event) {
+ dev_dbg(dev, "PM: suspend %d-->%d\n",
+ dev->power.power_state.event, state.event);
+ }
+
+ if (dev->class && dev->class->suspend) {
+ suspend_device_dbg(dev, state, "class ");
+ error = dev->class->suspend(dev, state);
+ suspend_report_result(dev->class->suspend, error);
+ }
+
+ if (!error && dev->type && dev->type->suspend) {
+ suspend_device_dbg(dev, state, "type ");
+ error = dev->type->suspend(dev, state);
+ suspend_report_result(dev->type->suspend, error);
+ }
+
+ if (!error && dev->bus && dev->bus->suspend) {
+ suspend_device_dbg(dev, state, "");
+ error = dev->bus->suspend(dev, state);
+ suspend_report_result(dev->bus->suspend, error);
+ }
+ up(&dev->sem);
+ return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+ int error = 0;
+
+ if (dev->bus && dev->bus->suspend_late) {
+ suspend_device_dbg(dev, state, "LATE ");
+ error = dev->bus->suspend_late(dev, state);
+ suspend_report_result(dev->bus->suspend_late, error);
+ }
+ return error;
+}
+
+/**
+ * device_suspend - Save state and stop all devices in system.
+ * @state: Power state to put each device in.
+ *
+ * Walk the dpm_active list, call ->suspend() for each device, and move
+ * it to the dpm_off list.
+ *
+ * (For historical reasons, if it returns -EAGAIN, that used to mean
+ * that the device would be called again with interrupts disabled.
+ * These days, we use the "suspend_late()" callback for that, so we
+ * print a warning and consider it an error).
+ *
+ * If we get a different error, try and back out.
+ *
+ * If we hit a failure with any of the devices, call device_resume()
+ * above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+ int error = 0;
+
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ mutex_lock(&dpm_list_mtx);
+ while (!list_empty(&dpm_active) && error == 0) {
+ struct list_head * entry = dpm_active.prev;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+
+ error = suspend_device(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
+
+ /* Check if the device got removed */
+ if (!list_empty(&dev->power.entry)) {
+ /* Move it to the dpm_off list */
+ if (!error)
+ list_move(&dev->power.entry, &dpm_off);
+ }
+ if (error)
+ printk(KERN_ERR "Could not suspend device %s: "
+ "error %d%s\n",
+ kobject_name(&dev->kobj), error,
+ error == -EAGAIN ? " (please convert to suspend_late)" : "");
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ if (error)
+ dpm_resume();
+
+ mutex_unlock(&dpm_mtx);
+ return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ * device_power_down - Shut down special devices.
+ * @state: Power state to enter.
+ *
+ * Walk the dpm_off_irq list, calling ->power_down() for each device that
+ * couldn't power down the device with interrupts enabled. When we're
+ * done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+ int error = 0;
+ struct device * dev;
+
+ while (!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.prev;
+
+ dev = to_device(entry);
+ error = suspend_device_late(dev, state);
+ if (error)
+ goto Error;
+ list_move(&dev->power.entry, &dpm_off_irq);
+ }
+
+ error = sysdev_suspend(state);
+ Done:
+ return error;
+ Error:
+ printk(KERN_ERR "Could not power down device %s: "
+ "error %d\n", kobject_name(&dev->kobj), error);
+ dpm_power_up();
+ goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+ if (ret) {
+ printk(KERN_ERR "%s(): ", function);
+ print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+ printk("%d\n", ret);
+ }
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 8ba0830cbc0..5c4efd493fa 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -11,32 +11,11 @@ extern void device_shutdown(void);
* main.c
*/
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
- return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active; /* The active device list */
static inline struct device * to_device(struct list_head * entry)
{
- return container_of(to_pm_info(entry), struct device, power);
+ return container_of(entry, struct device, power.entry);
}
extern int device_pm_add(struct device *);
@@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *);
extern int dpm_sysfs_add(struct device *);
extern void dpm_sysfs_remove(struct device *);
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
#else /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644
index 00fd84ae6e6..00000000000
--- a/drivers/base/power/resume.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- * resume_device - Restore state for one device.
- * @dev: Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
-
- down(&dev->sem);
-
- if (dev->bus && dev->bus->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->bus->resume(dev);
- }
-
- if (!error && dev->type && dev->type->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->type->resume(dev);
- }
-
- if (!error && dev->class && dev->class->resume) {
- dev_dbg(dev,"class resume\n");
- error = dev->class->resume(dev);
- }
-
- up(&dev->sem);
-
- TRACE_RESUME(error);
- return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
- if (dev->bus && dev->bus->resume_early) {
- dev_dbg(dev,"EARLY resume\n");
- error = dev->bus->resume_early(dev);
- }
- TRACE_RESUME(error);
- return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
- mutex_lock(&dpm_list_mtx);
- while(!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.next;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- list_move_tail(entry, &dpm_active);
-
- mutex_unlock(&dpm_list_mtx);
- resume_device(dev);
- mutex_lock(&dpm_list_mtx);
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- * device_resume - Restore state of each device in system.
- *
- * Walk the dpm_off list, remove each entry, resume the device,
- * then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
- might_sleep();
- mutex_lock(&dpm_mtx);
- dpm_resume();
- mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- * dpm_power_up - Power on some devices.
- *
- * Walk the dpm_off_irq list and power each device up. This
- * is used for devices that required they be powered down with
- * interrupts disabled. As devices are powered on, they are moved
- * to the dpm_active list.
- *
- * Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
- while(!list_empty(&dpm_off_irq)) {
- struct list_head * entry = dpm_off_irq.next;
- struct device * dev = to_device(entry);
-
- list_move_tail(entry, &dpm_off);
- resume_device_early(dev);
- }
-}
-
-
-/**
- * device_power_up - Turn on all devices that need special attention.
- *
- * Power on system devices then devices that required we shut them down
- * with interrupts disabled.
- * Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
- sysdev_resume();
- dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644
index 26df9b23173..00000000000
--- a/drivers/base/power/suspend.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
- switch (event) {
- case PM_EVENT_SUSPEND: return "suspend";
- case PM_EVENT_FREEZE: return "freeze";
- case PM_EVENT_PRETHAW: return "prethaw";
- default: return "(unknown suspend event)";
- }
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
- dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
- ", may wakeup" : "");
-}
-
-/**
- * suspend_device - Save state of one device.
- * @dev: Device.
- * @state: Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- down(&dev->sem);
- if (dev->power.power_state.event) {
- dev_dbg(dev, "PM: suspend %d-->%d\n",
- dev->power.power_state.event, state.event);
- }
-
- if (dev->class && dev->class->suspend) {
- suspend_device_dbg(dev, state, "class ");
- error = dev->class->suspend(dev, state);
- suspend_report_result(dev->class->suspend, error);
- }
-
- if (!error && dev->type && dev->type->suspend) {
- suspend_device_dbg(dev, state, "type ");
- error = dev->type->suspend(dev, state);
- suspend_report_result(dev->type->suspend, error);
- }
-
- if (!error && dev->bus && dev->bus->suspend) {
- suspend_device_dbg(dev, state, "");
- error = dev->bus->suspend(dev, state);
- suspend_report_result(dev->bus->suspend, error);
- }
- up(&dev->sem);
- return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
- int error = 0;
-
- if (dev->bus && dev->bus->suspend_late) {
- suspend_device_dbg(dev, state, "LATE ");
- error = dev->bus->suspend_late(dev, state);
- suspend_report_result(dev->bus->suspend_late, error);
- }
- return error;
-}
-
-/**
- * device_suspend - Save state and stop all devices in system.
- * @state: Power state to put each device in.
- *
- * Walk the dpm_active list, call ->suspend() for each device, and move
- * it to the dpm_off list.
- *
- * (For historical reasons, if it returns -EAGAIN, that used to mean
- * that the device would be called again with interrupts disabled.
- * These days, we use the "suspend_late()" callback for that, so we
- * print a warning and consider it an error).
- *
- * If we get a different error, try and back out.
- *
- * If we hit a failure with any of the devices, call device_resume()
- * above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
- int error = 0;
-
- might_sleep();
- mutex_lock(&dpm_mtx);
- mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_active) && error == 0) {
- struct list_head * entry = dpm_active.prev;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- mutex_unlock(&dpm_list_mtx);
-
- error = suspend_device(dev, state);
-
- mutex_lock(&dpm_list_mtx);
-
- /* Check if the device got removed */
- if (!list_empty(&dev->power.entry)) {
- /* Move it to the dpm_off list */
- if (!error)
- list_move(&dev->power.entry, &dpm_off);
- }
- if (error)
- printk(KERN_ERR "Could not suspend device %s: "
- "error %d%s\n",
- kobject_name(&dev->kobj), error,
- error == -EAGAIN ? " (please convert to suspend_late)" : "");
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
- if (error)
- dpm_resume();
-
- mutex_unlock(&dpm_mtx);
- return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- * device_power_down - Shut down special devices.
- * @state: Power state to enter.
- *
- * Walk the dpm_off_irq list, calling ->power_down() for each device that
- * couldn't power down the device with interrupts enabled. When we're
- * done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
- int error = 0;
- struct device * dev;
-
- while (!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.prev;
-
- dev = to_device(entry);
- error = suspend_device_late(dev, state);
- if (error)
- goto Error;
- list_move(&dev->power.entry, &dpm_off_irq);
- }
-
- error = sysdev_suspend(state);
- Done:
- return error;
- Error:
- printk(KERN_ERR "Could not power down device %s: "
- "error %d\n", kobject_name(&dev->kobj), error);
- dpm_power_up();
- goto Done;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-void __suspend_report_result(const char *function, void *fn, int ret)
-{
- if (ret) {
- printk(KERN_ERR "%s(): ", function);
- print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
- printk("%d\n", ret);
- }
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 18febe26caa..ac7ff6d0c6e 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls)
kobject_name(&cls->kset.kobj));
INIT_LIST_HEAD(&cls->drivers);
cls->kset.kobj.parent = &system_subsys.kobj;
- kset_set_kset_s(cls, system_subsys);
+ cls->kset.kobj.kset = &system_subsys;
return kset_register(&cls->kset);
}
@@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls)
EXPORT_SYMBOL_GPL(sysdev_class_register);
EXPORT_SYMBOL_GPL(sysdev_class_unregister);
-
-static LIST_HEAD(sysdev_drivers);
static DEFINE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
- * @cls: Device class driver belongs to.
+ * @cls: Device class driver belongs to.
* @drv: Driver.
*
- * If @cls is valid, then @drv is inserted into @cls->drivers to be
+ * @drv is inserted into @cls->drivers to be
* called on each operation on devices of that class. The refcount
* of @cls is incremented.
- * Otherwise, @drv is inserted into sysdev_drivers, and called for
- * each device.
*/
-int sysdev_driver_register(struct sysdev_class * cls,
- struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
{
+ int err = 0;
+
mutex_lock(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls,
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->add(dev);
}
- } else
- list_add_tail(&drv->entry, &sysdev_drivers);
+ } else {
+ err = -EINVAL;
+ printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+ WARN_ON(1);
+ }
mutex_unlock(&sysdev_drivers_lock);
- return 0;
+ return err;
}
@@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev)
* code that should have called us.
*/
- /* Notify global drivers */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->add)
- drv->add(sysdev);
- }
-
/* Notify class auxillary drivers */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->add)
@@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev)
struct sysdev_driver * drv;
mutex_lock(&sysdev_drivers_lock);
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->remove)
- drv->remove(sysdev);
- }
-
list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
@@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev)
*
* Loop over each class of system devices, and the devices in each
* of those classes. For each device, we call the shutdown method for
- * each driver registered for the device - the globals, the auxillaries,
+ * each driver registered for the device - the auxillaries,
* and the class driver.
*
* Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@ void sysdev_shutdown(void)
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->shutdown)
- drv->shutdown(sysdev);
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
@@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev)
if (drv->resume)
drv->resume(dev);
}
-
- /* Call global drivers. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->resume)
- drv->resume(dev);
- }
}
/**
@@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state)
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->suspend) {
- ret = drv->suspend(sysdev, state);
- if (ret)
- goto gbl_driver;
- }
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->suspend) {
ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@ aux_driver:
if (err_drv->resume)
err_drv->resume(sysdev);
}
- drv = NULL;
-gbl_driver:
- if (drv)
- printk(KERN_ERR "sysdev driver suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
- list_for_each_entry(err_drv, &sysdev_drivers, entry) {
- if (err_drv == drv)
- break;
- if (err_drv->resume)
- err_drv->resume(sysdev);
- }
/* resume other sysdevs in current class */
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
if (err_dev == sysdev)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4245b7f80a4..ca4d7f0d09b 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE
default "4096"
help
The default value is 4096 kilobytes. Only change this if you know
- what are you doing. If you are using IBM S/390, then set this to
- 8192.
+ what are you doing.
config BLK_DEV_RAM_BLOCKSIZE
int "Default RAM disk block size (bytes)"
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 28d145756f6..55c3237fb1b 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3101,7 +3101,7 @@ static void cciss_getgeometry(int cntl_num)
int i;
int listlength = 0;
__u32 lunid = 0;
- int block_size;
+ unsigned block_size;
sector_t total_size;
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 8955e7ff759..b83824c4132 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -58,6 +58,9 @@ struct gatt_mask {
* devices this will probably be ignored */
};
+#define AGP_PAGE_DESTROY_UNMAP 1
+#define AGP_PAGE_DESTROY_FREE 2
+
struct aper_size_info_8 {
int size;
int num_entries;
@@ -113,7 +116,7 @@ struct agp_bridge_driver {
struct agp_memory *(*alloc_by_type) (size_t, int);
void (*free_by_type)(struct agp_memory *);
void *(*agp_alloc_page)(struct agp_bridge_data *);
- void (*agp_destroy_page)(void *);
+ void (*agp_destroy_page)(void *, int flags);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
};
@@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
void agp_generic_free_by_type(struct agp_memory *curr);
void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
-void agp_generic_destroy_page(void *addr);
+void agp_generic_destroy_page(void *addr, int flags);
void agp_free_key(int key);
int agp_num_entries(void);
u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 4941ddb7893..aa5ddb716ff 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
return addr;
}
-static void ali_destroy_page(void * addr)
+static void ali_destroy_page(void * addr, int flags)
{
if (addr) {
- global_cache_flush(); /* is this really needed? --hch */
- agp_generic_destroy_page(addr);
- global_flush_tlb();
+ if (flags & AGP_PAGE_DESTROY_UNMAP) {
+ global_cache_flush(); /* is this really needed? --hch */
+ agp_generic_destroy_page(addr, flags);
+ global_flush_tlb();
+ } else
+ agp_generic_destroy_page(addr, flags);
}
}
-static void m1541_destroy_page(void * addr)
+static void m1541_destroy_page(void * addr, int flags)
{
u32 temp;
if (addr == NULL)
return;
- global_cache_flush();
+ if (flags & AGP_PAGE_DESTROY_UNMAP) {
+ global_cache_flush();
- pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
- pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
- (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
- agp_generic_destroy_page(addr);
+ pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
+ pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+ (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+ virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
+ }
+ agp_generic_destroy_page(addr, flags);
}
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index f60bca70d1f..1405a42585e 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables)
for (i = 0; i < nr_tables; i++) {
entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
+ tables[i] = entry;
if (entry == NULL) {
- while (i > 0) {
- kfree(tables[i-1]);
- i--;
- }
- kfree(tables);
retval = -ENOMEM;
break;
}
- tables[i] = entry;
retval = amd_create_page_map(entry);
if (retval != 0)
break;
}
- amd_irongate_private.num_tables = nr_tables;
+ amd_irongate_private.num_tables = i;
amd_irongate_private.gatt_pages = tables;
if (retval != 0)
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 1b47c89a1b9..832ded20fe7 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
err_out:
if (bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(
- gart_to_virt(bridge->scratch_page_real));
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_UNMAP);
flush_agp_mappings();
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_FREE);
}
if (got_gatt)
bridge->driver->free_gatt_table(bridge);
@@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(
- gart_to_virt(bridge->scratch_page_real));
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_UNMAP);
flush_agp_mappings();
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_FREE);
}
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3db4f4076ed..64b2f6d7059 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
}
if (curr->page_count != 0) {
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
+ curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
}
flush_agp_mappings();
+ for (i = 0; i < curr->page_count; i++) {
+ curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
+ }
}
agp_free_key(curr->key);
agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
EXPORT_SYMBOL(agp_generic_alloc_page);
-void agp_generic_destroy_page(void *addr)
+void agp_generic_destroy_page(void *addr, int flags)
{
struct page *page;
@@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr)
return;
page = virt_to_page(addr);
- unmap_page_from_agp(page);
- put_page(page);
- free_page((unsigned long)addr);
- atomic_dec(&agp_bridge->current_memory_agp);
+ if (flags & AGP_PAGE_DESTROY_UNMAP)
+ unmap_page_from_agp(page);
+
+ if (flags & AGP_PAGE_DESTROY_FREE) {
+ put_page(page);
+ free_page((unsigned long)addr);
+ atomic_dec(&agp_bridge->current_memory_agp);
+ }
}
EXPORT_SYMBOL(agp_generic_destroy_page);
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 75d2aca6353..70117df4d06 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -536,10 +536,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
return page;
}
-static void i460_destroy_page (void *page)
+static void i460_destroy_page (void *page, int flags)
{
if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
- agp_generic_destroy_page(page);
+ agp_generic_destroy_page(page, flags);
global_flush_tlb();
}
}
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 141ca176c39..d87961993cc 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -400,9 +400,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
if (curr->page_count == 4)
i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
else {
- agp_bridge->driver->agp_destroy_page(
- gart_to_virt(curr->memory[0]));
+ agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ AGP_PAGE_DESTROY_UNMAP);
global_flush_tlb();
+ agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ AGP_PAGE_DESTROY_FREE);
}
agp_free_page_array(curr);
}
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 2d6f2d0bd02..82fb3d0d278 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -63,27 +63,9 @@
#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
#endif
-#define XFREE86_VERSION(major,minor,patch,snap) \
- ((major << 16) | (minor << 8) | patch)
-
-#ifndef CONFIG_XFREE86_VERSION
-#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
-#endif
-
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-#define DRM_PROC_DEVICES "/proc/devices"
-#define DRM_PROC_MISC "/proc/misc"
-#define DRM_PROC_DRM "/proc/drm"
-#define DRM_DEV_DRM "/dev/drm"
-#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-#define DRM_DEV_UID 0
-#define DRM_DEV_GID 0
-#endif
-
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
#define DRM_MAJOR 226
#define DRM_MAX_MINOR 15
-#endif
+
#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */
#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */
#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 0df87fc3dcb..9dd0760dd87 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -80,6 +80,9 @@
#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
+struct drm_file;
+struct drm_device;
+
#include "drm_os_linux.h"
#include "drm_hashtab.h"
@@ -231,12 +234,13 @@
* \param dev DRM device.
* \param filp file pointer of the caller.
*/
-#define LOCK_TEST_WITH_RETURN( dev, filp ) \
+#define LOCK_TEST_WITH_RETURN( dev, file_priv ) \
do { \
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
- dev->lock.filp != filp ) { \
- DRM_ERROR( "%s called without lock held\n", \
- __FUNCTION__ ); \
+ dev->lock.file_priv != file_priv ) { \
+ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
+ __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+ dev->lock.file_priv, file_priv ); \
return -EINVAL; \
} \
} while (0)
@@ -257,12 +261,12 @@ do { \
* Ioctl function type.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private pointer.
* \param cmd command.
* \param arg argument.
*/
-typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+typedef int drm_ioctl_t(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
unsigned long arg);
@@ -271,10 +275,18 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
#define DRM_MASTER 0x2
#define DRM_ROOT_ONLY 0x4
-typedef struct drm_ioctl_desc {
+struct drm_ioctl_desc {
+ unsigned int cmd;
drm_ioctl_t *func;
int flags;
-} drm_ioctl_desc_t;
+};
+
+/**
+ * Creates a driver or general drm_ioctl_desc array entry for the given
+ * ioctl, for use by drm_ioctl().
+ */
+#define DRM_IOCTL_DEF(ioctl, func, flags) \
+ [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
struct drm_magic_entry {
struct list_head head;
@@ -304,7 +316,7 @@ struct drm_buf {
__volatile__ int waiting; /**< On kernel DMA queue */
__volatile__ int pending; /**< On hardware DMA queue */
wait_queue_head_t dma_wait; /**< Processes waiting */
- struct file *filp; /**< Pointer to holding file descr */
+ struct drm_file *file_priv; /**< Private of holding file descr */
int context; /**< Kernel queue for this buffer */
int while_locked; /**< Dispatch this buffer while locked */
enum {
@@ -377,6 +389,7 @@ struct drm_file {
int remove_auth_on_close;
unsigned long lock_count;
void *driver_priv;
+ struct file *filp;
};
/** Wait queue */
@@ -403,7 +416,7 @@ struct drm_queue {
*/
struct drm_lock_data {
struct drm_hw_lock *hw_lock; /**< Hardware lock */
- struct file *filp; /**< File descr of lock holder (0=kernel) */
+ struct drm_file *file_priv; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
spinlock_t spinlock;
@@ -552,11 +565,11 @@ struct drm_driver {
int (*load) (struct drm_device *, unsigned long flags);
int (*firstopen) (struct drm_device *);
int (*open) (struct drm_device *, struct drm_file *);
- void (*preclose) (struct drm_device *, struct file * filp);
+ void (*preclose) (struct drm_device *, struct drm_file *file_priv);
void (*postclose) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *);
int (*unload) (struct drm_device *);
- int (*dma_ioctl) (DRM_IOCTL_ARGS);
+ int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *);
int (*context_ctor) (struct drm_device *dev, int context);
@@ -587,11 +600,12 @@ struct drm_driver {
void (*irq_preinstall) (struct drm_device *dev);
void (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev);
- void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
+ void (*reclaim_buffers) (struct drm_device *dev,
+ struct drm_file * file_priv);
void (*reclaim_buffers_locked) (struct drm_device *dev,
- struct file *filp);
+ struct drm_file *file_priv);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
- struct file * filp);
+ struct drm_file *file_priv);
unsigned long (*get_map_ofs) (struct drm_map * map);
unsigned long (*get_reg_ofs) (struct drm_device *dev);
void (*set_version) (struct drm_device *dev,
@@ -606,7 +620,7 @@ struct drm_driver {
u32 driver_features;
int dev_priv_size;
- drm_ioctl_desc_t *ioctls;
+ struct drm_ioctl_desc *ioctls;
int num_ioctls;
struct file_operations fops;
struct pci_driver pci_driver;
@@ -850,70 +864,70 @@ extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
extern int drm_unbind_agp(DRM_AGP_MEM * handle);
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int drm_irq_by_busid(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_setunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getmap(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getclient(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getstats(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_setversion(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_noop(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_irq_by_busid(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_setunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getmap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getclient(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getstats(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_setversion(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_noop(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Context IOCTL support (drm_context.h) */
-extern int drm_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_resctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_addctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_modctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_switchctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_newctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_ctxbitmap_init(struct drm_device *dev);
extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
-extern int drm_setsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_setsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Drawable IOCTL support (drm_drawable.h) */
-extern int drm_adddraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmdraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_adddraw(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmdraw(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_update_drawable_info(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
drm_drawable_t id);
extern void drm_drawable_free_all(struct drm_device *dev);
/* Authentication IOCTL support (drm_auth.h) */
-extern int drm_getmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_authmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_getmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_authmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Locking IOCTL support (drm_lock.h) */
-extern int drm_lock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_unlock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_lock(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_unlock(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
extern void drm_idlelock_take(struct drm_lock_data *lock_data);
@@ -924,8 +938,7 @@ extern void drm_idlelock_release(struct drm_lock_data *lock_data);
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
*/
-extern int drm_i_have_hw_lock(struct file *filp);
-extern int drm_kernel_take_hw_lock(struct file *filp);
+extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv);
/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
@@ -933,24 +946,23 @@ extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request
extern int drm_addmap(struct drm_device *dev, unsigned int offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags, drm_local_map_t ** map_ptr);
-extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmmap(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
+extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_addbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_infobufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_markbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_freebufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_mapbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_order(unsigned long size);
-extern int drm_addbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_mapbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
extern unsigned long drm_get_resource_start(struct drm_device *dev,
unsigned int resource);
extern unsigned long drm_get_resource_len(struct drm_device *dev,
@@ -960,19 +972,20 @@ extern unsigned long drm_get_resource_len(struct drm_device *dev,
extern int drm_dma_setup(struct drm_device *dev);
extern void drm_dma_takedown(struct drm_device *dev);
extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
-extern void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp);
+extern void drm_core_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *filp);
/* IRQ support (drm_irq.h) */
-extern int drm_control(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_control(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
extern int drm_irq_uninstall(struct drm_device *dev);
extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev);
-extern int drm_wait_vblank(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
extern void drm_vbl_send_signals(struct drm_device *dev);
extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
@@ -980,31 +993,30 @@ extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_de
/* AGP/GART support (drm_agpsupport.h) */
extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
extern int drm_agp_acquire(struct drm_device *dev);
-extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_release(struct drm_device *dev);
-extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
-extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info * info);
-extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info);
+extern int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge,
- size_t pages, u32 type);
+extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
@@ -1033,10 +1045,11 @@ extern int drm_proc_cleanup(int minor,
/* Scatter Gather Support (drm_scatter.h) */
extern void drm_sg_cleanup(struct drm_sg_mem * entry);
-extern int drm_sg_alloc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_sg_free(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request);
+extern int drm_sg_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* ATI PCIGART support (ati_pcigart.h) */
extern int drm_ati_pcigart_init(struct drm_device *dev,
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
index 354f0e3674b..214f4fbcba7 100644
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -40,7 +40,7 @@
* Get AGP information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a (output) drm_agp_info structure.
* \return zero on success or a negative number on failure.
@@ -71,20 +71,16 @@ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
EXPORT_SYMBOL(drm_agp_info);
-int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_info info;
+ struct drm_agp_info *info = data;
int err;
- err = drm_agp_info(dev, &info);
+ err = drm_agp_info(dev, info);
if (err)
return err;
- if (copy_to_user((struct drm_agp_info __user *) arg, &info, sizeof(info)))
- return -EFAULT;
return 0;
}
@@ -115,7 +111,7 @@ EXPORT_SYMBOL(drm_agp_acquire);
* Acquire the AGP device (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or a negative number on failure.
@@ -123,12 +119,10 @@ EXPORT_SYMBOL(drm_agp_acquire);
* Verifies the AGP device hasn't been acquired before and calls
* \c agp_backend_acquire.
*/
-int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
-
- return drm_agp_acquire((struct drm_device *) priv->head->dev);
+ return drm_agp_acquire((struct drm_device *) file_priv->head->dev);
}
/**
@@ -149,12 +143,9 @@ int drm_agp_release(struct drm_device * dev)
}
EXPORT_SYMBOL(drm_agp_release);
-int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
return drm_agp_release(dev);
}
@@ -182,24 +173,19 @@ int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
EXPORT_SYMBOL(drm_agp_enable);
-int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_mode mode;
-
- if (copy_from_user(&mode, (struct drm_agp_mode __user *) arg, sizeof(mode)))
- return -EFAULT;
+ struct drm_agp_mode *mode = data;
- return drm_agp_enable(dev, mode);
+ return drm_agp_enable(dev, *mode);
}
/**
* Allocate AGP memory.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv file private pointer.
* \param cmd command.
* \param arg pointer to a drm_agp_buffer structure.
* \return zero on success or a negative number on failure.
@@ -241,35 +227,13 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
}
EXPORT_SYMBOL(drm_agp_alloc);
-int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_buffer request;
- struct drm_agp_buffer __user *argp = (void __user *)arg;
- int err;
-
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
- err = drm_agp_alloc(dev, &request);
- if (err)
- return err;
-
- if (copy_to_user(argp, &request, sizeof(request))) {
- struct drm_agp_mem *entry;
- list_for_each_entry(entry, &dev->agp->memory, head) {
- if (entry->handle == request.handle)
- break;
- }
- list_del(&entry->head);
- drm_free_agp(entry->memory, entry->pages);
- drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
- return -EFAULT;
- }
+int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_buffer *request = data;
- return 0;
+ return drm_agp_alloc(dev, request);
}
/**
@@ -297,7 +261,7 @@ static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
* Unbind AGP memory from the GATT (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_binding structure.
* \return zero on success or a negative number on failure.
@@ -323,25 +287,20 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
}
EXPORT_SYMBOL(drm_agp_unbind);
-int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_binding request;
- if (copy_from_user
- (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
- return -EFAULT;
+int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_binding *request = data;
- return drm_agp_unbind(dev, &request);
+ return drm_agp_unbind(dev, request);
}
/**
* Bind AGP memory into the GATT (ioctl)
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_binding structure.
* \return zero on success or a negative number on failure.
@@ -372,25 +331,20 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
}
EXPORT_SYMBOL(drm_agp_bind);
-int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_binding request;
- if (copy_from_user
- (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
- return -EFAULT;
+int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_binding *request = data;
- return drm_agp_bind(dev, &request);
+ return drm_agp_bind(dev, request);
}
/**
* Free AGP memory (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_buffer structure.
* \return zero on success or a negative number on failure.
@@ -419,18 +373,14 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
}
EXPORT_SYMBOL(drm_agp_free);
-int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_buffer request;
- if (copy_from_user
- (&request, (struct drm_agp_buffer __user *) arg, sizeof(request)))
- return -EFAULT;
- return drm_agp_free(dev, &request);
+int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_buffer *request = data;
+
+ return drm_agp_free(dev, request);
}
/**
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index 7f777da872c..a73462723d2 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -128,42 +128,38 @@ static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
* Get a unique magic number (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a resulting drm_auth structure.
* \return zero on success, or a negative number on failure.
*
* If there is a magic number in drm_file::magic then use it, otherwise
* searches an unique non-zero magic number and add it associating it with \p
- * filp.
+ * file_priv.
*/
-int drm_getmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
static drm_magic_t sequence = 0;
static DEFINE_SPINLOCK(lock);
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_auth auth;
+ struct drm_auth *auth = data;
/* Find unique magic */
- if (priv->magic) {
- auth.magic = priv->magic;
+ if (file_priv->magic) {
+ auth->magic = file_priv->magic;
} else {
do {
spin_lock(&lock);
if (!sequence)
++sequence; /* reserve 0 */
- auth.magic = sequence++;
+ auth->magic = sequence++;
spin_unlock(&lock);
- } while (drm_find_file(dev, auth.magic));
- priv->magic = auth.magic;
- drm_add_magic(dev, priv, auth.magic);
+ } while (drm_find_file(dev, auth->magic));
+ file_priv->magic = auth->magic;
+ drm_add_magic(dev, file_priv, auth->magic);
}
- DRM_DEBUG("%u\n", auth.magic);
- if (copy_to_user((struct drm_auth __user *) arg, &auth, sizeof(auth)))
- return -EFAULT;
+ DRM_DEBUG("%u\n", auth->magic);
+
return 0;
}
@@ -171,27 +167,23 @@ int drm_getmagic(struct inode *inode, struct file *filp,
* Authenticate with a magic.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_auth structure.
* \return zero if authentication successed, or a negative number otherwise.
*
- * Checks if \p filp is associated with the magic number passed in \arg.
+ * Checks if \p file_priv is associated with the magic number passed in \arg.
*/
-int drm_authmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_authmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_auth auth;
+ struct drm_auth *auth = data;
struct drm_file *file;
- if (copy_from_user(&auth, (struct drm_auth __user *) arg, sizeof(auth)))
- return -EFAULT;
- DRM_DEBUG("%u\n", auth.magic);
- if ((file = drm_find_file(dev, auth.magic))) {
+ DRM_DEBUG("%u\n", auth->magic);
+ if ((file = drm_find_file(dev, auth->magic))) {
file->authenticated = 1;
- drm_remove_magic(dev, auth.magic);
+ drm_remove_magic(dev, auth->magic);
return 0;
}
return -EINVAL;
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index c115b39b851..856774fbe02 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -92,7 +92,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_map structure.
* \return zero on success or a negative value on error.
@@ -332,38 +332,24 @@ int drm_addmap(struct drm_device * dev, unsigned int offset,
EXPORT_SYMBOL(drm_addmap);
-int drm_addmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map map;
+ struct drm_map *map = data;
struct drm_map_list *maplist;
- struct drm_map __user *argp = (void __user *)arg;
int err;
- if (!(filp->f_mode & 3))
- return -EACCES; /* Require read/write */
-
- if (copy_from_user(&map, argp, sizeof(map))) {
- return -EFAULT;
- }
-
- if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
+ if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP))
return -EPERM;
- err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
- &maplist);
+ err = drm_addmap_core(dev, map->offset, map->size, map->type,
+ map->flags, &maplist);
if (err)
return err;
- if (copy_to_user(argp, maplist->map, sizeof(struct drm_map)))
- return -EFAULT;
-
/* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
- if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle))
- return -EFAULT;
+ map->handle = (void *)(unsigned long)maplist->user_token;
return 0;
}
@@ -372,7 +358,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
* isn't in use.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_map structure.
* \return zero on success or a negative value on error.
@@ -453,24 +439,18 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
* gets used by drivers that the server doesn't need to care about. This seems
* unlikely.
*/
-int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map request;
+ struct drm_map *request = data;
drm_local_map_t *map = NULL;
struct drm_map_list *r_list;
int ret;
- if (copy_from_user(&request, (struct drm_map __user *) arg, sizeof(request))) {
- return -EFAULT;
- }
-
mutex_lock(&dev->struct_mutex);
list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map &&
- r_list->user_token == (unsigned long)request.handle &&
+ r_list->user_token == (unsigned long)request->handle &&
r_list->map->flags & _DRM_REMOVABLE) {
map = r_list->map;
break;
@@ -661,7 +641,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -872,7 +852,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size,
@@ -1050,7 +1030,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1211,7 +1191,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1275,7 +1255,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
* Add buffers for DMA transfers (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_buf_desc request.
* \return zero on success or a negative number on failure.
@@ -1285,38 +1265,27 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
* addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent
* PCI memory respectively.
*/
-int drm_addbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_buf_desc request;
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_buf_desc *request = data;
int ret;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
return -EINVAL;
- if (copy_from_user(&request, (struct drm_buf_desc __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
#if __OS_HAS_AGP
- if (request.flags & _DRM_AGP_BUFFER)
- ret = drm_addbufs_agp(dev, &request);
+ if (request->flags & _DRM_AGP_BUFFER)
+ ret = drm_addbufs_agp(dev, request);
else
#endif
- if (request.flags & _DRM_SG_BUFFER)
- ret = drm_addbufs_sg(dev, &request);
- else if (request.flags & _DRM_FB_BUFFER)
- ret = drm_addbufs_fb(dev, &request);
+ if (request->flags & _DRM_SG_BUFFER)
+ ret = drm_addbufs_sg(dev, request);
+ else if (request->flags & _DRM_FB_BUFFER)
+ ret = drm_addbufs_fb(dev, request);
else
- ret = drm_addbufs_pci(dev, &request);
+ ret = drm_addbufs_pci(dev, request);
- if (ret == 0) {
- if (copy_to_user((void __user *)arg, &request, sizeof(request))) {
- ret = -EFAULT;
- }
- }
return ret;
}
@@ -1328,7 +1297,7 @@ int drm_addbufs(struct inode *inode, struct file *filp,
* large buffers can be used for image transfer).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_info structure.
* \return zero on success or a negative number on failure.
@@ -1337,14 +1306,11 @@ int drm_addbufs(struct inode *inode, struct file *filp,
* lock, preventing of allocating more buffers after this call. Information
* about each requested buffer is then copied into user space.
*/
-int drm_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_infobufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_info request;
- struct drm_buf_info __user *argp = (void __user *)arg;
+ struct drm_buf_info *request = data;
int i;
int count;
@@ -1362,9 +1328,6 @@ int drm_infobufs(struct inode *inode, struct file *filp,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
if (dma->bufs[i].buf_count)
++count;
@@ -1372,11 +1335,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
DRM_DEBUG("count = %d\n", count);
- if (request.count >= count) {
+ if (request->count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
if (dma->bufs[i].buf_count) {
struct drm_buf_desc __user *to =
- &request.list[count];
+ &request->list[count];
struct drm_buf_entry *from = &dma->bufs[i];
struct drm_freelist *list = &dma->bufs[i].freelist;
if (copy_to_user(&to->count,
@@ -1403,10 +1366,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
}
}
}
- request.count = count;
-
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
+ request->count = count;
return 0;
}
@@ -1415,7 +1375,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
* Specifies a low and high water mark for buffer allocation
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg a pointer to a drm_buf_desc structure.
* \return zero on success or a negative number on failure.
@@ -1425,13 +1385,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
*
* \note This ioctl is deprecated and mostly never used.
*/
-int drm_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_markbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_desc request;
+ struct drm_buf_desc *request = data;
int order;
struct drm_buf_entry *entry;
@@ -1441,24 +1399,20 @@ int drm_markbufs(struct inode *inode, struct file *filp,
if (!dma)
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_buf_desc __user *) arg, sizeof(request)))
- return -EFAULT;
-
DRM_DEBUG("%d, %d, %d\n",
- request.size, request.low_mark, request.high_mark);
- order = drm_order(request.size);
+ request->size, request->low_mark, request->high_mark);
+ order = drm_order(request->size);
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
return -EINVAL;
entry = &dma->bufs[order];
- if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+ if (request->low_mark < 0 || request->low_mark > entry->buf_count)
return -EINVAL;
- if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+ if (request->high_mark < 0 || request->high_mark > entry->buf_count)
return -EINVAL;
- entry->freelist.low_mark = request.low_mark;
- entry->freelist.high_mark = request.high_mark;
+ entry->freelist.low_mark = request->low_mark;
+ entry->freelist.high_mark = request->high_mark;
return 0;
}
@@ -1467,7 +1421,7 @@ int drm_markbufs(struct inode *inode, struct file *filp,
* Unreserve the buffers in list, previously reserved using drmDMA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_free structure.
* \return zero on success or a negative number on failure.
@@ -1475,13 +1429,11 @@ int drm_markbufs(struct inode *inode, struct file *filp,
* Calls free_buffer() for each used buffer.
* This function is primarily used for debugging.
*/
-int drm_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_freebufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_free request;
+ struct drm_buf_free *request = data;
int i;
int idx;
struct drm_buf *buf;
@@ -1492,13 +1444,9 @@ int drm_freebufs(struct inode *inode, struct file *filp,
if (!dma)
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_buf_free __user *) arg, sizeof(request)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", request.count);
- for (i = 0; i < request.count; i++) {
- if (copy_from_user(&idx, &request.list[i], sizeof(idx)))
+ DRM_DEBUG("%d\n", request->count);
+ for (i = 0; i < request->count; i++) {
+ if (copy_from_user(&idx, &request->list[i], sizeof(idx)))
return -EFAULT;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("Index %d (of %d max)\n",
@@ -1506,7 +1454,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
return -EINVAL;
}
buf = dma->buflist[idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("Process %d freeing buffer not owned\n",
current->pid);
return -EINVAL;
@@ -1521,7 +1469,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* Maps all of the DMA buffers into client-virtual space (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_map structure.
* \return zero on success or a negative number on failure.
@@ -1531,18 +1479,15 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
* drm_mmap_dma().
*/
-int drm_mapbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_mapbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_map __user *argp = (void __user *)arg;
int retcode = 0;
const int zero = 0;
unsigned long virtual;
unsigned long address;
- struct drm_buf_map request;
+ struct drm_buf_map *request = data;
int i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1559,10 +1504,7 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
dev->buf_use++; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
- if (request.count >= dma->buf_count) {
+ if (request->count >= dma->buf_count) {
if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
|| (drm_core_check_feature(dev, DRIVER_SG)
&& (dma->flags & _DRM_DMA_USE_SG))
@@ -1575,15 +1517,15 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
retcode = -EINVAL;
goto done;
}
-
down_write(&current->mm->mmap_sem);
- virtual = do_mmap(filp, 0, map->size,
+ virtual = do_mmap(file_priv->filp, 0, map->size,
PROT_READ | PROT_WRITE,
- MAP_SHARED, token);
+ MAP_SHARED,
+ token);
up_write(&current->mm->mmap_sem);
} else {
down_write(&current->mm->mmap_sem);
- virtual = do_mmap(filp, 0, dma->byte_count,
+ virtual = do_mmap(file_priv->filp, 0, dma->byte_count,
PROT_READ | PROT_WRITE,
MAP_SHARED, 0);
up_write(&current->mm->mmap_sem);
@@ -1593,28 +1535,28 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
retcode = (signed long)virtual;
goto done;
}
- request.virtual = (void __user *)virtual;
+ request->virtual = (void __user *)virtual;
for (i = 0; i < dma->buf_count; i++) {
- if (copy_to_user(&request.list[i].idx,
+ if (copy_to_user(&request->list[i].idx,
&dma->buflist[i]->idx,
- sizeof(request.list[0].idx))) {
+ sizeof(request->list[0].idx))) {
retcode = -EFAULT;
goto done;
}
- if (copy_to_user(&request.list[i].total,
+ if (copy_to_user(&request->list[i].total,
&dma->buflist[i]->total,
- sizeof(request.list[0].total))) {
+ sizeof(request->list[0].total))) {
retcode = -EFAULT;
goto done;
}
- if (copy_to_user(&request.list[i].used,
+ if (copy_to_user(&request->list[i].used,
&zero, sizeof(zero))) {
retcode = -EFAULT;
goto done;
}
address = virtual + dma->buflist[i]->offset; /* *** */
- if (copy_to_user(&request.list[i].address,
+ if (copy_to_user(&request->list[i].address,
&address, sizeof(address))) {
retcode = -EFAULT;
goto done;
@@ -1622,11 +1564,8 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
}
}
done:
- request.count = dma->buf_count;
- DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
-
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
+ request->count = dma->buf_count;
+ DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
return retcode;
}
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index 61ad986baa8..17fe69e7bfc 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -131,7 +131,7 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
* Get per-context SAREA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
@@ -139,22 +139,16 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
* Gets the map from drm_device::ctx_idr with the handle specified and
* returns its handle.
*/
-int drm_getsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx_priv_map __user *argp = (void __user *)arg;
- struct drm_ctx_priv_map request;
+ struct drm_ctx_priv_map *request = data;
struct drm_map *map;
struct drm_map_list *_entry;
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
mutex_lock(&dev->struct_mutex);
- map = idr_find(&dev->ctx_idr, request.ctx_id);
+ map = idr_find(&dev->ctx_idr, request->ctx_id);
if (!map) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
@@ -162,19 +156,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
mutex_unlock(&dev->struct_mutex);
- request.handle = NULL;
+ request->handle = NULL;
list_for_each_entry(_entry, &dev->maplist, head) {
if (_entry->map == map) {
- request.handle =
+ request->handle =
(void *)(unsigned long)_entry->user_token;
break;
}
}
- if (request.handle == NULL)
+ if (request->handle == NULL)
return -EINVAL;
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
return 0;
}
@@ -182,7 +174,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* Set per-context SAREA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
@@ -190,24 +182,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* Searches the mapping specified in \p arg and update the entry in
* drm_device::ctx_idr with it.
*/
-int drm_setsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_setsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx_priv_map request;
+ struct drm_ctx_priv_map *request = data;
struct drm_map *map = NULL;
struct drm_map_list *r_list = NULL;
- if (copy_from_user(&request,
- (struct drm_ctx_priv_map __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
mutex_lock(&dev->struct_mutex);
list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map
- && r_list->user_token == (unsigned long)request.handle)
+ && r_list->user_token == (unsigned long) request->handle)
goto found;
}
bad:
@@ -219,10 +204,11 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
if (!map)
goto bad;
- if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id)))
+ if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
goto bad;
mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -292,34 +278,28 @@ static int drm_context_switch_complete(struct drm_device * dev, int new)
* Reserve contexts.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_res structure.
* \return zero on success or a negative number on failure.
*/
-int drm_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_resctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_ctx_res res;
- struct drm_ctx_res __user *argp = (void __user *)arg;
+ struct drm_ctx_res *res = data;
struct drm_ctx ctx;
int i;
- if (copy_from_user(&res, argp, sizeof(res)))
- return -EFAULT;
-
- if (res.count >= DRM_RESERVED_CONTEXTS) {
+ if (res->count >= DRM_RESERVED_CONTEXTS) {
memset(&ctx, 0, sizeof(ctx));
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
ctx.handle = i;
- if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx)))
+ if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
return -EFAULT;
}
}
- res.count = DRM_RESERVED_CONTEXTS;
+ res->count = DRM_RESERVED_CONTEXTS;
- if (copy_to_user(argp, &res, sizeof(res)))
- return -EFAULT;
return 0;
}
@@ -327,40 +307,34 @@ int drm_resctx(struct inode *inode, struct file *filp,
* Add context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Get a new handle for the context and copy to userspace.
*/
-int drm_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_ctx_list *ctx_entry;
- struct drm_ctx __user *argp = (void __user *)arg;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, argp, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
- ctx.handle = drm_ctxbitmap_next(dev);
- if (ctx.handle == DRM_KERNEL_CONTEXT) {
+ ctx->handle = drm_ctxbitmap_next(dev);
+ if (ctx->handle == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
- ctx.handle = drm_ctxbitmap_next(dev);
+ ctx->handle = drm_ctxbitmap_next(dev);
}
- DRM_DEBUG("%d\n", ctx.handle);
- if (ctx.handle == -1) {
+ DRM_DEBUG("%d\n", ctx->handle);
+ if (ctx->handle == -1) {
DRM_DEBUG("Not enough free contexts.\n");
/* Should this return -EBUSY instead? */
return -ENOMEM;
}
- if (ctx.handle != DRM_KERNEL_CONTEXT) {
+ if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_ctor)
- if (!dev->driver->context_ctor(dev, ctx.handle)) {
+ if (!dev->driver->context_ctor(dev, ctx->handle)) {
DRM_DEBUG("Running out of ctxs or memory.\n");
return -ENOMEM;
}
@@ -373,21 +347,18 @@ int drm_addctx(struct inode *inode, struct file *filp,
}
INIT_LIST_HEAD(&ctx_entry->head);
- ctx_entry->handle = ctx.handle;
- ctx_entry->tag = priv;
+ ctx_entry->handle = ctx->handle;
+ ctx_entry->tag = file_priv;
mutex_lock(&dev->ctxlist_mutex);
list_add(&ctx_entry->head, &dev->ctxlist);
++dev->ctx_count;
mutex_unlock(&dev->ctxlist_mutex);
- if (copy_to_user(argp, &ctx, sizeof(ctx)))
- return -EFAULT;
return 0;
}
-int drm_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
/* This does nothing */
return 0;
@@ -397,25 +368,18 @@ int drm_modctx(struct inode *inode, struct file *filp,
* Get context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*/
-int drm_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_ctx __user *argp = (void __user *)arg;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, argp, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
/* This is 0, because we don't handle any context flags */
- ctx.flags = 0;
+ ctx->flags = 0;
- if (copy_to_user(argp, &ctx, sizeof(ctx)))
- return -EFAULT;
return 0;
}
@@ -423,50 +387,40 @@ int drm_getctx(struct inode *inode, struct file *filp,
* Switch context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Calls context_switch().
*/
-int drm_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_switchctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
+ struct drm_ctx *ctx = data;
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", ctx.handle);
- return drm_context_switch(dev, dev->last_context, ctx.handle);
+ DRM_DEBUG("%d\n", ctx->handle);
+ return drm_context_switch(dev, dev->last_context, ctx->handle);
}
/**
* New context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Calls context_switch_complete().
*/
-int drm_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_newctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
+ struct drm_ctx *ctx = data;
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", ctx.handle);
- drm_context_switch_complete(dev, ctx.handle);
+ DRM_DEBUG("%d\n", ctx->handle);
+ drm_context_switch_complete(dev, ctx->handle);
return 0;
}
@@ -475,31 +429,26 @@ int drm_newctx(struct inode *inode, struct file *filp,
* Remove context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* If not the special kernel context, calls ctxbitmap_free() to free the specified context.
*/
-int drm_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_rmctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
- DRM_DEBUG("%d\n", ctx.handle);
- if (ctx.handle == DRM_KERNEL_CONTEXT + 1) {
- priv->remove_auth_on_close = 1;
+ DRM_DEBUG("%d\n", ctx->handle);
+ if (ctx->handle == DRM_KERNEL_CONTEXT + 1) {
+ file_priv->remove_auth_on_close = 1;
}
- if (ctx.handle != DRM_KERNEL_CONTEXT) {
+ if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor)
- dev->driver->context_dtor(dev, ctx.handle);
- drm_ctxbitmap_free(dev, ctx.handle);
+ dev->driver->context_dtor(dev, ctx->handle);
+ drm_ctxbitmap_free(dev, ctx->handle);
}
mutex_lock(&dev->ctxlist_mutex);
@@ -507,7 +456,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
struct drm_ctx_list *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
- if (pos->handle == ctx.handle) {
+ if (pos->handle == ctx->handle) {
list_del(&pos->head);
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
--dev->ctx_count;
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 802fbdbfe1b..7a8e2fba467 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -136,7 +136,7 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
buf->waiting = 0;
buf->pending = 0;
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->used = 0;
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)
@@ -148,11 +148,12 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
/**
* Reclaim the buffers.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
*
- * Frees each buffer associated with \p filp not already on the hardware.
+ * Frees each buffer associated with \p file_priv not already on the hardware.
*/
-void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
+void drm_core_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -160,7 +161,7 @@ void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
if (!dma)
return;
for (i = 0; i < dma->buf_count; i++) {
- if (dma->buflist[i]->filp == filp) {
+ if (dma->buflist[i]->file_priv == file_priv) {
switch (dma->buflist[i]->list) {
case DRM_LIST_NONE:
drm_free_buffer(dev, dma->buflist[i]);
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index d6cdba5644e..1839c57663c 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -40,11 +40,10 @@
/**
* Allocate drawable ID and memory to store information about it.
*/
-int drm_adddraw(DRM_IOCTL_ARGS)
+int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
unsigned long irqflags;
- struct drm_draw draw;
+ struct drm_draw *draw = data;
int new_id = 0;
int ret;
@@ -63,11 +62,9 @@ again:
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- draw.handle = new_id;
+ draw->handle = new_id;
- DRM_DEBUG("%d\n", draw.handle);
-
- DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw));
+ DRM_DEBUG("%d\n", draw->handle);
return 0;
}
@@ -75,72 +72,64 @@ again:
/**
* Free drawable ID and memory to store information about it.
*/
-int drm_rmdraw(DRM_IOCTL_ARGS)
+int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_draw draw;
+ struct drm_draw *draw = data;
unsigned long irqflags;
- DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data,
- sizeof(draw));
-
spin_lock_irqsave(&dev->drw_lock, irqflags);
- drm_free(drm_get_drawable_info(dev, draw.handle),
+ drm_free(drm_get_drawable_info(dev, draw->handle),
sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
- idr_remove(&dev->drw_idr, draw.handle);
+ idr_remove(&dev->drw_idr, draw->handle);
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_DEBUG("%d\n", draw.handle);
+ DRM_DEBUG("%d\n", draw->handle);
return 0;
}
-int drm_update_drawable_info(DRM_IOCTL_ARGS)
+int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_update_draw update;
+ struct drm_update_draw *update = data;
unsigned long irqflags;
struct drm_clip_rect *rects;
struct drm_drawable_info *info;
int err;
- DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data,
- sizeof(update));
-
- info = idr_find(&dev->drw_idr, update.handle);
+ info = idr_find(&dev->drw_idr, update->handle);
if (!info) {
info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
if (!info)
return -ENOMEM;
- if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) {
- DRM_ERROR("No such drawable %d\n", update.handle);
+ if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
+ DRM_ERROR("No such drawable %d\n", update->handle);
drm_free(info, sizeof(*info), DRM_MEM_BUFS);
return -EINVAL;
}
}
- switch (update.type) {
+ switch (update->type) {
case DRM_DRAWABLE_CLIPRECTS:
- if (update.num != info->num_rects) {
- rects = drm_alloc(update.num * sizeof(struct drm_clip_rect),
+ if (update->num != info->num_rects) {
+ rects = drm_alloc(update->num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
} else
rects = info->rects;
- if (update.num && !rects) {
+ if (update->num && !rects) {
DRM_ERROR("Failed to allocate cliprect memory\n");
- err = DRM_ERR(ENOMEM);
+ err = -ENOMEM;
goto error;
}
- if (update.num && DRM_COPY_FROM_USER(rects,
+ if (update->num && DRM_COPY_FROM_USER(rects,
(struct drm_clip_rect __user *)
- (unsigned long)update.data,
- update.num *
+ (unsigned long)update->data,
+ update->num *
sizeof(*rects))) {
DRM_ERROR("Failed to copy cliprects from userspace\n");
- err = DRM_ERR(EFAULT);
+ err = -EFAULT;
goto error;
}
@@ -152,23 +141,23 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS)
}
info->rects = rects;
- info->num_rects = update.num;
+ info->num_rects = update->num;
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Updated %d cliprects for drawable %d\n",
- info->num_rects, update.handle);
+ info->num_rects, update->handle);
break;
default:
- DRM_ERROR("Invalid update type %d\n", update.type);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Invalid update type %d\n", update->type);
+ return -EINVAL;
}
return 0;
error:
if (rects != info->rects)
- drm_free(rects, update.num * sizeof(struct drm_clip_rect),
+ drm_free(rects, update->num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
return err;
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 19994cd865d..72668b15e5c 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -49,73 +49,74 @@
#include "drmP.h"
#include "drm_core.h"
-static int drm_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+static int drm_version(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/** Ioctl table */
-static drm_ioctl_desc_t drm_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
- [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH},
+static struct drm_ioctl_desc drm_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
- [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH},
+ DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH),
- [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#if __OS_HAS_AGP
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#endif
- [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+ DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
- [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -224,7 +225,7 @@ int drm_lastclose(struct drm_device * dev)
if (dev->lock.hw_lock) {
dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
- dev->lock.filp = NULL;
+ dev->lock.file_priv = NULL;
wake_up_interruptible(&dev->lock.lock_queue);
}
mutex_unlock(&dev->struct_mutex);
@@ -418,27 +419,19 @@ module_exit(drm_core_exit);
*
* Fills in the version information in \p arg.
*/
-static int drm_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int drm_version(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_version __user *argp = (void __user *)arg;
- struct drm_version version;
+ struct drm_version *version = data;
int len;
- if (copy_from_user(&version, argp, sizeof(version)))
- return -EFAULT;
+ version->version_major = dev->driver->major;
+ version->version_minor = dev->driver->minor;
+ version->version_patchlevel = dev->driver->patchlevel;
+ DRM_COPY(version->name, dev->driver->name);
+ DRM_COPY(version->date, dev->driver->date);
+ DRM_COPY(version->desc, dev->driver->desc);
- version.version_major = dev->driver->major;
- version.version_minor = dev->driver->minor;
- version.version_patchlevel = dev->driver->patchlevel;
- DRM_COPY(version.name, dev->driver->name);
- DRM_COPY(version.date, dev->driver->date);
- DRM_COPY(version.desc, dev->driver->desc);
-
- if (copy_to_user(argp, &version, sizeof(version)))
- return -EFAULT;
return 0;
}
@@ -446,7 +439,7 @@ static int drm_version(struct inode *inode, struct file *filp,
* Called whenever a process performs an ioctl on /dev/drm.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or negative number on failure.
@@ -457,21 +450,22 @@ static int drm_version(struct inode *inode, struct file *filp,
int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_ioctl_desc_t *ioctl;
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->head->dev;
+ struct drm_ioctl_desc *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
int retcode = -EINVAL;
+ char *kdata = NULL;
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
- ++priv->ioctl_count;
+ ++file_priv->ioctl_count;
DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
current->pid, cmd, nr,
- (long)old_encode_dev(priv->head->device),
- priv->authenticated);
+ (long)old_encode_dev(file_priv->head->device),
+ file_priv->authenticated);
if ((nr >= DRM_CORE_IOCTL_COUNT) &&
((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
@@ -489,18 +483,40 @@ int drm_ioctl(struct inode *inode, struct file *filp,
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
func = dev->driver->dma_ioctl;
+
if (!func) {
DRM_DEBUG("no function\n");
retcode = -EINVAL;
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
- ((ioctl->flags & DRM_AUTH) && !priv->authenticated) ||
- ((ioctl->flags & DRM_MASTER) && !priv->master)) {
+ ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
+ ((ioctl->flags & DRM_MASTER) && !file_priv->master)) {
retcode = -EACCES;
} else {
- retcode = func(inode, filp, cmd, arg);
+ if (cmd & (IOC_IN | IOC_OUT)) {
+ kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (!kdata)
+ return -ENOMEM;
+ }
+
+ if (cmd & IOC_IN) {
+ if (copy_from_user(kdata, (void __user *)arg,
+ _IOC_SIZE(cmd)) != 0) {
+ retcode = -EACCES;
+ goto err_i1;
+ }
+ }
+ retcode = func(dev, kdata, file_priv);
+
+ if (cmd & IOC_OUT) {
+ if (copy_to_user((void __user *)arg, kdata,
+ _IOC_SIZE(cmd)) != 0)
+ retcode = -EACCES;
+ }
}
err_i1:
+ if (kdata)
+ kfree(kdata);
atomic_dec(&dev->ioctl_count);
if (retcode)
DRM_DEBUG("ret = %x\n", retcode);
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 7bc51bac450..f383fc37190 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -242,6 +242,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
memset(priv, 0, sizeof(*priv));
filp->private_data = priv;
+ priv->filp = filp;
priv->uid = current->euid;
priv->pid = current->pid;
priv->minor = minor;
@@ -312,7 +313,7 @@ EXPORT_SYMBOL(drm_fasync);
* Release file.
*
* \param inode device inode
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \return zero on success or a negative number on failure.
*
* If the hardware lock is held then free it, and take it again for the kernel
@@ -322,29 +323,28 @@ EXPORT_SYMBOL(drm_fasync);
*/
int drm_release(struct inode *inode, struct file *filp)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev;
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->head->dev;
int retcode = 0;
lock_kernel();
- dev = priv->head->dev;
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (dev->driver->preclose)
- dev->driver->preclose(dev, filp);
+ dev->driver->preclose(dev, file_priv);
/* ========================================================
* Begin inline drm_release
*/
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
- current->pid, (long)old_encode_dev(priv->head->device),
+ current->pid, (long)old_encode_dev(file_priv->head->device),
dev->open_count);
if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
- if (drm_i_have_hw_lock(filp)) {
- dev->driver->reclaim_buffers_locked(dev, filp);
+ if (drm_i_have_hw_lock(dev, file_priv)) {
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
} else {
unsigned long _end=jiffies + 3*DRM_HZ;
int locked = 0;
@@ -370,7 +370,7 @@ int drm_release(struct inode *inode, struct file *filp)
"\tI will go on reclaiming the buffers anyway.\n");
}
- dev->driver->reclaim_buffers_locked(dev, filp);
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
drm_idlelock_release(&dev->lock);
}
}
@@ -378,12 +378,12 @@ int drm_release(struct inode *inode, struct file *filp)
if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
drm_idlelock_take(&dev->lock);
- dev->driver->reclaim_buffers_idlelocked(dev, filp);
+ dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
drm_idlelock_release(&dev->lock);
}
- if (drm_i_have_hw_lock(filp)) {
+ if (drm_i_have_hw_lock(dev, file_priv)) {
DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
@@ -394,7 +394,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) {
- dev->driver->reclaim_buffers(dev, filp);
+ dev->driver->reclaim_buffers(dev, file_priv);
}
drm_fasync(-1, filp, 0);
@@ -404,7 +404,7 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_ctx_list *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
- if (pos->tag == priv &&
+ if (pos->tag == file_priv &&
pos->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor)
dev->driver->context_dtor(dev,
@@ -421,18 +421,18 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_unlock(&dev->ctxlist_mutex);
mutex_lock(&dev->struct_mutex);
- if (priv->remove_auth_on_close == 1) {
+ if (file_priv->remove_auth_on_close == 1) {
struct drm_file *temp;
list_for_each_entry(temp, &dev->filelist, lhead)
temp->authenticated = 0;
}
- list_del(&priv->lhead);
+ list_del(&file_priv->lhead);
mutex_unlock(&dev->struct_mutex);
if (dev->driver->postclose)
- dev->driver->postclose(dev, priv);
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+ dev->driver->postclose(dev, file_priv);
+ drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
/* ========================================================
* End inline drm_release
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index 462f46f2049..2286f3312c5 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -1040,7 +1040,7 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
* Called whenever a 32-bit process running under a 64-bit kernel
* performs an ioctl on /dev/drm.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or negative number on failure.
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index b195e102e73..d9be1462452 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -42,30 +42,24 @@
* Get the bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
*
* Copies the bus id from drm_device::unique into user space.
*/
-int drm_getunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_unique __user *argp = (void __user *)arg;
- struct drm_unique u;
+ struct drm_unique *u = data;
- if (copy_from_user(&u, argp, sizeof(u)))
- return -EFAULT;
- if (u.unique_len >= dev->unique_len) {
- if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+ if (u->unique_len >= dev->unique_len) {
+ if (copy_to_user(u->unique, dev->unique, dev->unique_len))
return -EFAULT;
}
- u.unique_len = dev->unique_len;
- if (copy_to_user(argp, &u, sizeof(u)))
- return -EFAULT;
+ u->unique_len = dev->unique_len;
+
return 0;
}
@@ -73,7 +67,7 @@ int drm_getunique(struct inode *inode, struct file *filp,
* Set the bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
@@ -83,28 +77,23 @@ int drm_getunique(struct inode *inode, struct file *filp,
* in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater.
*/
-int drm_setunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_setunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_unique u;
+ struct drm_unique *u = data;
int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique)
return -EBUSY;
- if (copy_from_user(&u, (struct drm_unique __user *) arg, sizeof(u)))
- return -EFAULT;
-
- if (!u.unique_len || u.unique_len > 1024)
+ if (!u->unique_len || u->unique_len > 1024)
return -EINVAL;
- dev->unique_len = u.unique_len;
- dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+ dev->unique_len = u->unique_len;
+ dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
if (!dev->unique)
return -ENOMEM;
- if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+ if (copy_from_user(dev->unique, u->unique, dev->unique_len))
return -EFAULT;
dev->unique[dev->unique_len] = '\0';
@@ -123,7 +112,7 @@ int drm_setunique(struct inode *inode, struct file *filp,
*/
ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
domain = bus >> 8;
bus &= 0xff;
@@ -172,7 +161,7 @@ static int drm_set_busid(struct drm_device * dev)
* Get a mapping information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_map structure.
*
@@ -181,21 +170,16 @@ static int drm_set_busid(struct drm_device * dev)
* Searches for the mapping with the specified offset and copies its information
* into userspace
*/
-int drm_getmap(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getmap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map __user *argp = (void __user *)arg;
- struct drm_map map;
+ struct drm_map *map = data;
struct drm_map_list *r_list = NULL;
struct list_head *list;
int idx;
int i;
- if (copy_from_user(&map, argp, sizeof(map)))
- return -EFAULT;
- idx = map.offset;
+ idx = map->offset;
mutex_lock(&dev->struct_mutex);
if (idx < 0) {
@@ -216,16 +200,14 @@ int drm_getmap(struct inode *inode, struct file *filp,
return -EINVAL;
}
- map.offset = r_list->map->offset;
- map.size = r_list->map->size;
- map.type = r_list->map->type;
- map.flags = r_list->map->flags;
- map.handle = (void *)(unsigned long)r_list->user_token;
- map.mtrr = r_list->map->mtrr;
+ map->offset = r_list->map->offset;
+ map->size = r_list->map->size;
+ map->type = r_list->map->type;
+ map->flags = r_list->map->flags;
+ map->handle = (void *)(unsigned long) r_list->user_token;
+ map->mtrr = r_list->map->mtrr;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user(argp, &map, sizeof(map)))
- return -EFAULT;
return 0;
}
@@ -233,7 +215,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
* Get client information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_client structure.
*
@@ -242,20 +224,15 @@ int drm_getmap(struct inode *inode, struct file *filp,
* Searches for the client with the specified index and copies its information
* into userspace
*/
-int drm_getclient(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getclient(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_client __user *argp = (struct drm_client __user *)arg;
- struct drm_client client;
+ struct drm_client *client = data;
struct drm_file *pt;
int idx;
int i;
- if (copy_from_user(&client, argp, sizeof(client)))
- return -EFAULT;
- idx = client.idx;
+ idx = client->idx;
mutex_lock(&dev->struct_mutex);
if (list_empty(&dev->filelist)) {
@@ -269,15 +246,13 @@ int drm_getclient(struct inode *inode, struct file *filp,
break;
}
- client.auth = pt->authenticated;
- client.pid = pt->pid;
- client.uid = pt->uid;
- client.magic = pt->magic;
- client.iocs = pt->ioctl_count;
+ client->auth = pt->authenticated;
+ client->pid = pt->pid;
+ client->uid = pt->uid;
+ client->magic = pt->magic;
+ client->iocs = pt->ioctl_count;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user(argp, &client, sizeof(client)))
- return -EFAULT;
return 0;
}
@@ -285,39 +260,35 @@ int drm_getclient(struct inode *inode, struct file *filp,
* Get statistics information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_stats structure.
*
* \return zero on success or a negative number on failure.
*/
-int drm_getstats(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getstats(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_stats stats;
+ struct drm_stats *stats = data;
int i;
- memset(&stats, 0, sizeof(stats));
+ memset(stats, 0, sizeof(stats));
mutex_lock(&dev->struct_mutex);
for (i = 0; i < dev->counters; i++) {
if (dev->types[i] == _DRM_STAT_LOCK)
- stats.data[i].value
- = (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
+ stats->data[i].value =
+ (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
else
- stats.data[i].value = atomic_read(&dev->counts[i]);
- stats.data[i].type = dev->types[i];
+ stats->data[i].value = atomic_read(&dev->counts[i]);
+ stats->data[i].type = dev->types[i];
}
- stats.count = dev->counters;
+ stats->count = dev->counters;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user((struct drm_stats __user *) arg, &stats, sizeof(stats)))
- return -EFAULT;
return 0;
}
@@ -325,64 +296,59 @@ int drm_getstats(struct inode *inode, struct file *filp,
* Setversion ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Sets the requested interface version
*/
-int drm_setversion(DRM_IOCTL_ARGS)
+int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_set_version sv;
- struct drm_set_version retv;
- int if_version;
- struct drm_set_version __user *argp = (void __user *)data;
- int ret;
-
- if (copy_from_user(&sv, argp, sizeof(sv)))
- return -EFAULT;
-
- retv.drm_di_major = DRM_IF_MAJOR;
- retv.drm_di_minor = DRM_IF_MINOR;
- retv.drm_dd_major = dev->driver->major;
- retv.drm_dd_minor = dev->driver->minor;
-
- if (copy_to_user(argp, &retv, sizeof(retv)))
- return -EFAULT;
-
- if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != DRM_IF_MAJOR ||
- sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
- return -EINVAL;
- if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
+ struct drm_set_version *sv = data;
+ int if_version, retcode = 0;
+
+ if (sv->drm_di_major != -1) {
+ if (sv->drm_di_major != DRM_IF_MAJOR ||
+ sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
+ retcode = -EINVAL;
+ goto done;
+ }
+ if_version = DRM_IF_VERSION(sv->drm_di_major,
+ sv->drm_di_minor);
dev->if_version = max(if_version, dev->if_version);
- if (sv.drm_di_minor >= 1) {
+ if (sv->drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
*/
- ret = drm_set_busid(dev);
- if (ret)
- return ret;
+ drm_set_busid(dev);
}
}
- if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != dev->driver->major ||
- sv.drm_dd_minor < 0
- || sv.drm_dd_minor > dev->driver->minor)
- return -EINVAL;
+ if (sv->drm_dd_major != -1) {
+ if (sv->drm_dd_major != dev->driver->major ||
+ sv->drm_dd_minor < 0 || sv->drm_dd_minor >
+ dev->driver->minor) {
+ retcode = -EINVAL;
+ goto done;
+ }
if (dev->driver->set_version)
- dev->driver->set_version(dev, &sv);
+ dev->driver->set_version(dev, sv);
}
- return 0;
+
+done:
+ sv->drm_di_major = DRM_IF_MAJOR;
+ sv->drm_di_minor = DRM_IF_MINOR;
+ sv->drm_dd_major = dev->driver->major;
+ sv->drm_dd_minor = dev->driver->minor;
+
+ return retcode;
}
/** No-op ioctl. */
-int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int drm_noop(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
DRM_DEBUG("\n");
return 0;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 871d2fde09b..05eae63f85b 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -41,7 +41,7 @@
* Get interrupt from bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_irq_busid structure.
* \return zero on success or a negative number on failure.
@@ -50,30 +50,24 @@
* This IOCTL is deprecated, and will now return EINVAL for any busid not equal
* to that of the device that this DRM instance attached to.
*/
-int drm_irq_by_busid(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_irq_busid __user *argp = (void __user *)arg;
- struct drm_irq_busid p;
+ struct drm_irq_busid *p = data;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- if (copy_from_user(&p, argp, sizeof(p)))
- return -EFAULT;
-
- if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
- (p.busnum & 0xff) != dev->pdev->bus->number ||
- p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
+ if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+ (p->busnum & 0xff) != dev->pdev->bus->number ||
+ p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
return -EINVAL;
- p.irq = dev->irq;
+ p->irq = dev->irq;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+ p->irq);
- DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq);
- if (copy_to_user(argp, &p, sizeof(p)))
- return -EFAULT;
return 0;
}
@@ -187,31 +181,27 @@ EXPORT_SYMBOL(drm_irq_uninstall);
* IRQ control ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_control structure.
* \return zero on success or a negative number on failure.
*
* Calls irq_install() or irq_uninstall() according to \p arg.
*/
-int drm_control(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_control(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_control ctl;
+ struct drm_control *ctl = data;
/* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
- if (copy_from_user(&ctl, (struct drm_control __user *) arg, sizeof(ctl)))
- return -EFAULT;
- switch (ctl.func) {
+ switch (ctl->func) {
case DRM_INST_HANDLER:
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl.irq != dev->irq)
+ ctl->irq != dev->irq)
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
@@ -227,7 +217,7 @@ int drm_control(struct inode *inode, struct file *filp,
* Wait for VBLANK.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param data user argument, pointing to a drm_wait_vblank structure.
* \return zero on success or a negative number on failure.
@@ -242,31 +232,25 @@ int drm_control(struct inode *inode, struct file *filp,
*
* If a signal is not requested, then calls vblank_wait().
*/
-int drm_wait_vblank(DRM_IOCTL_ARGS)
+int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- union drm_wait_vblank __user *argp = (void __user *)data;
- union drm_wait_vblank vblwait;
+ union drm_wait_vblank *vblwait = data;
struct timeval now;
int ret = 0;
unsigned int flags, seq;
- if (!dev->irq)
+ if ((!dev->irq) || (!dev->irq_enabled))
return -EINVAL;
- if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
- return -EFAULT;
-
- if (vblwait.request.type &
+ if (vblwait->request.type &
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
- vblwait.request.type,
+ vblwait->request.type,
(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
return -EINVAL;
}
- flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+ flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
@@ -275,10 +259,10 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
: &dev->vbl_received);
- switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
+ switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
- vblwait.request.sequence += seq;
- vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ vblwait->request.sequence += seq;
+ vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case _DRM_VBLANK_ABSOLUTE:
break;
default:
@@ -286,8 +270,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
}
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
- (seq - vblwait.request.sequence) <= (1<<23)) {
- vblwait.request.sequence = seq + 1;
+ (seq - vblwait->request.sequence) <= (1<<23)) {
+ vblwait->request.sequence = seq + 1;
}
if (flags & _DRM_VBLANK_SIGNAL) {
@@ -303,12 +287,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
* that case
*/
list_for_each_entry(vbl_sig, vbl_sigs, head) {
- if (vbl_sig->sequence == vblwait.request.sequence
- && vbl_sig->info.si_signo == vblwait.request.signal
+ if (vbl_sig->sequence == vblwait->request.sequence
+ && vbl_sig->info.si_signo ==
+ vblwait->request.signal
&& vbl_sig->task == current) {
spin_unlock_irqrestore(&dev->vbl_lock,
irqflags);
- vblwait.reply.sequence = seq;
+ vblwait->reply.sequence = seq;
goto done;
}
}
@@ -330,8 +315,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
- vbl_sig->sequence = vblwait.request.sequence;
- vbl_sig->info.si_signo = vblwait.request.signal;
+ vbl_sig->sequence = vblwait->request.sequence;
+ vbl_sig->info.si_signo = vblwait->request.signal;
vbl_sig->task = current;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -340,25 +325,22 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- vblwait.reply.sequence = seq;
+ vblwait->reply.sequence = seq;
} else {
if (flags & _DRM_VBLANK_SECONDARY) {
if (dev->driver->vblank_wait2)
- ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+ ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
} else if (dev->driver->vblank_wait)
ret =
dev->driver->vblank_wait(dev,
- &vblwait.request.sequence);
+ &vblwait->request.sequence);
do_gettimeofday(&now);
- vblwait.reply.tval_sec = now.tv_sec;
- vblwait.reply.tval_usec = now.tv_usec;
+ vblwait->reply.tval_sec = now.tv_sec;
+ vblwait->reply.tval_usec = now.tv_usec;
}
done:
- if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
- return -EFAULT;
-
return ret;
}
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index c0534b5a8b7..c6b73e744d6 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -41,39 +41,33 @@ static int drm_notifier(void *priv);
* Lock ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Add the current task to the lock wait queue, and attempt to take to lock.
*/
-int drm_lock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
DECLARE_WAITQUEUE(entry, current);
- struct drm_lock lock;
+ struct drm_lock *lock = data;
int ret = 0;
- ++priv->lock_count;
+ ++file_priv->lock_count;
- if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
- return -EFAULT;
-
- if (lock.context == DRM_KERNEL_CONTEXT) {
+ if (lock->context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
- current->pid, lock.context);
+ current->pid, lock->context);
return -EINVAL;
}
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
- lock.context, current->pid,
- dev->lock.hw_lock->lock, lock.flags);
+ lock->context, current->pid,
+ dev->lock.hw_lock->lock, lock->flags);
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
- if (lock.context < 0)
+ if (lock->context < 0)
return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry);
@@ -87,8 +81,8 @@ int drm_lock(struct inode *inode, struct file *filp,
ret = -EINTR;
break;
}
- if (drm_lock_take(&dev->lock, lock.context)) {
- dev->lock.filp = filp;
+ if (drm_lock_take(&dev->lock, lock->context)) {
+ dev->lock.file_priv = file_priv;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
@@ -107,7 +101,8 @@ int drm_lock(struct inode *inode, struct file *filp,
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
- DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+ DRM_DEBUG("%d %s\n", lock->context,
+ ret ? "interrupted" : "has lock");
if (ret) return ret;
sigemptyset(&dev->sigmask);
@@ -115,24 +110,26 @@ int drm_lock(struct inode *inode, struct file *filp,
sigaddset(&dev->sigmask, SIGTSTP);
sigaddset(&dev->sigmask, SIGTTIN);
sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
+ dev->sigdata.context = lock->context;
dev->sigdata.lock = dev->lock.hw_lock;
block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
- if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
+ if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
dev->driver->dma_ready(dev);
- if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
+ if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
+ {
if (dev->driver->dma_quiescent(dev)) {
- DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
- return DRM_ERR(EBUSY);
+ DRM_DEBUG("%d waiting for DMA quiescent\n",
+ lock->context);
+ return -EBUSY;
}
}
if (dev->driver->kernel_context_switch &&
- dev->last_context != lock.context) {
+ dev->last_context != lock->context) {
dev->driver->kernel_context_switch(dev, dev->last_context,
- lock.context);
+ lock->context);
}
return 0;
@@ -142,27 +139,21 @@ int drm_lock(struct inode *inode, struct file *filp,
* Unlock ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Transfer and free the lock.
*/
-int drm_unlock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_lock lock;
+ struct drm_lock *lock = data;
unsigned long irqflags;
- if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
- return -EFAULT;
-
- if (lock.context == DRM_KERNEL_CONTEXT) {
+ if (lock->context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
- current->pid, lock.context);
+ current->pid, lock->context);
return -EINVAL;
}
@@ -184,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev);
else {
- if (drm_lock_free(&dev->lock,lock.context)) {
+ if (drm_lock_free(&dev->lock,lock->context)) {
/* FIXME: Should really bail out here. */
}
}
@@ -257,7 +248,7 @@ static int drm_lock_transfer(struct drm_lock_data *lock_data,
unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
- lock_data->filp = NULL;
+ lock_data->file_priv = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
@@ -390,13 +381,11 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
EXPORT_SYMBOL(drm_idlelock_release);
-int drm_i_have_hw_lock(struct file *filp)
+int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- return (priv->lock_count && dev->lock.hw_lock &&
+ return (file_priv->lock_count && dev->lock.hw_lock &&
_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
- dev->lock.filp == filp);
+ dev->lock.file_priv == file_priv);
}
EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 0b8d3433386..114e54e0f61 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -6,11 +6,6 @@
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
-/** File pointer type */
-#define DRMFILE struct file *
-/** Ioctl arguments */
-#define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data
-#define DRM_ERR(d) -(d)
/** Current process ID */
#define DRM_CURRENTPID current->pid
#define DRM_SUSER(p) capable(CAP_SYS_ADMIN)
@@ -33,9 +28,6 @@
#define DRM_WRITEMEMORYBARRIER() wmb()
/** Read/write memory barrier */
#define DRM_MEMORYBARRIER() mb()
-/** DRM device local declaration */
-#define DRM_DEVICE struct drm_file *priv = filp->private_data; \
- struct drm_device *dev = priv->head->dev
/** IRQ handler arguments and return type and values */
#define DRM_IRQ_ARGS int irq, void *arg
@@ -94,8 +86,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#define DRM_GET_USER_UNCHECKED(val, uaddr) \
__get_user(val, uaddr)
-#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
-
#define DRM_HZ HZ
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 30b200b0131..f3593974496 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -236,10 +236,8 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c
index 067d25daaf1..eb7fa437355 100644
--- a/drivers/char/drm/drm_scatter.c
+++ b/drivers/char/drm/drm_scatter.c
@@ -62,13 +62,8 @@ void drm_sg_cleanup(struct drm_sg_mem * entry)
# define ScatterHandle(x) (unsigned int)(x)
#endif
-int drm_sg_alloc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_scatter_gather __user *argp = (void __user *)arg;
- struct drm_scatter_gather request;
struct drm_sg_mem *entry;
unsigned long pages, i, j;
@@ -80,17 +75,13 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
if (dev->sg)
return -EINVAL;
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS);
if (!entry)
return -ENOMEM;
memset(entry, 0, sizeof(*entry));
-
- pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
- DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
+ pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
+ DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
entry->pages = pages;
entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
@@ -142,12 +133,7 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
SetPageReserved(entry->pagelist[j]);
}
- request.handle = entry->handle;
-
- if (copy_to_user(argp, &request, sizeof(request))) {
- drm_sg_cleanup(entry);
- return -EFAULT;
- }
+ request->handle = entry->handle;
dev->sg = entry;
@@ -197,27 +183,31 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
drm_sg_cleanup(entry);
return -ENOMEM;
}
+EXPORT_SYMBOL(drm_sg_alloc);
+
-int drm_sg_free(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_scatter_gather request;
+ struct drm_scatter_gather *request = data;
+
+ return drm_sg_alloc(dev, request);
+
+}
+
+int drm_sg_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_scatter_gather *request = data;
struct drm_sg_mem *entry;
if (!drm_core_check_feature(dev, DRIVER_SG))
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_scatter_gather __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
entry = dev->sg;
dev->sg = NULL;
- if (!entry || entry->handle != request.handle)
+ if (!entry || entry->handle != request->handle)
return -EINVAL;
DRM_DEBUG("sg free virtual = %p\n", entry->virtual);
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 68e36e51ba0..e8d50af5820 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -463,7 +463,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
/**
* mmap DMA memory.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param vma virtual memory area.
* \return zero on success or a negative number on failure.
*
@@ -533,7 +533,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
/**
* mmap DMA memory.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param vma virtual memory area.
* \return zero on success or a negative number on failure.
*
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index cb449999d0e..8e841bdee6d 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -120,10 +120,9 @@ static const struct file_operations i810_buffer_fops = {
.fasync = drm_fasync,
};
-static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = file_priv->head->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
drm_i810_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
@@ -133,14 +132,14 @@ static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
return -EINVAL;
down_write(&current->mm->mmap_sem);
- old_fops = filp->f_op;
- filp->f_op = &i810_buffer_fops;
+ old_fops = file_priv->filp->f_op;
+ file_priv->filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf;
- buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total,
PROT_READ | PROT_WRITE,
MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL;
- filp->f_op = old_fops;
+ file_priv->filp->f_op = old_fops;
if (IS_ERR(buf_priv->virtual)) {
/* Real error */
DRM_ERROR("mmap error\n");
@@ -173,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf)
}
static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
- struct file *filp)
+ struct drm_file *file_priv)
{
struct drm_buf *buf;
drm_i810_buf_priv_t *buf_priv;
@@ -186,13 +185,13 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
return retcode;
}
- retcode = i810_map_buffer(buf, filp);
+ retcode = i810_map_buffer(buf, file_priv);
if (retcode) {
i810_freelist_put(dev, buf);
DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
return retcode;
}
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf_priv = buf->dev_private;
d->granted = 1;
d->request_idx = buf->idx;
@@ -380,7 +379,7 @@ static int i810_dma_initialize(struct drm_device * dev,
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -430,99 +429,29 @@ static int i810_dma_initialize(struct drm_device * dev,
return 0;
}
-/* i810 DRM version 1.1 used a smaller init structure with different
- * ordering of values than is currently used (drm >= 1.2). There is
- * no defined way to detect the XFree version to correct this problem,
- * however by checking using this procedure we can detect the correct
- * thing to do.
- *
- * #1 Read the Smaller init structure from user-space
- * #2 Verify the overlay_physical is a valid physical address, or NULL
- * If it isn't then we have a v1.1 client. Fix up params.
- * If it is, then we have a 1.2 client... get the rest of the data.
- */
-static int i810_dma_init_compat(drm_i810_init_t * init, unsigned long arg)
+static int i810_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
-
- /* Get v1.1 init data */
- if (copy_from_user(init, (drm_i810_pre12_init_t __user *) arg,
- sizeof(drm_i810_pre12_init_t))) {
- return -EFAULT;
- }
-
- if ((!init->overlay_physical) || (init->overlay_physical > 4096)) {
-
- /* This is a v1.2 client, just get the v1.2 init data */
- DRM_INFO("Using POST v1.2 init.\n");
- if (copy_from_user(init, (drm_i810_init_t __user *) arg,
- sizeof(drm_i810_init_t))) {
- return -EFAULT;
- }
- } else {
-
- /* This is a v1.1 client, fix the params */
- DRM_INFO("Using PRE v1.2 init.\n");
- init->pitch_bits = init->h;
- init->pitch = init->w;
- init->h = init->overlay_physical;
- init->w = init->overlay_offset;
- init->overlay_physical = 0;
- init->overlay_offset = 0;
- }
-
- return 0;
-}
-
-static int i810_dma_init(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv;
- drm_i810_init_t init;
+ drm_i810_init_t *init = data;
int retcode = 0;
- /* Get only the init func */
- if (copy_from_user
- (&init, (void __user *)arg, sizeof(drm_i810_init_func_t)))
- return -EFAULT;
-
- switch (init.func) {
- case I810_INIT_DMA:
- /* This case is for backward compatibility. It
- * handles XFree 4.1.0 and 4.2.0, and has to
- * do some parameter checking as described below.
- * It will someday go away.
- */
- retcode = i810_dma_init_compat(&init, arg);
- if (retcode)
- return retcode;
-
- dev_priv = drm_alloc(sizeof(drm_i810_private_t),
- DRM_MEM_DRIVER);
- if (dev_priv == NULL)
- return -ENOMEM;
- retcode = i810_dma_initialize(dev, dev_priv, &init);
- break;
-
- default:
+ switch (init->func) {
case I810_INIT_DMA_1_4:
DRM_INFO("Using v1.4 init.\n");
- if (copy_from_user(&init, (drm_i810_init_t __user *) arg,
- sizeof(drm_i810_init_t))) {
- return -EFAULT;
- }
dev_priv = drm_alloc(sizeof(drm_i810_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;
- retcode = i810_dma_initialize(dev, dev_priv, &init);
+ retcode = i810_dma_initialize(dev, dev_priv, init);
break;
case I810_CLEANUP_DMA:
DRM_INFO("DMA Cleanup\n");
retcode = i810_dma_cleanup(dev);
break;
+ default:
+ return -EINVAL;
}
return retcode;
@@ -968,7 +897,8 @@ static int i810_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i810_reclaim_buffers(struct drm_device * dev,
+ struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -986,7 +916,7 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv) {
+ if (buf->file_priv == file_priv && buf_priv) {
int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
I810_BUF_FREE);
@@ -998,47 +928,38 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
}
}
-static int i810_flush_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i810_flush_queue(dev);
return 0;
}
-static int i810_dma_vertex(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_dma_vertex(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- drm_i810_vertex_t vertex;
-
- if (copy_from_user
- (&vertex, (drm_i810_vertex_t __user *) arg, sizeof(vertex)))
- return -EFAULT;
+ drm_i810_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
- vertex.idx, vertex.used, vertex.discard);
+ vertex->idx, vertex->used, vertex->discard);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
return -EINVAL;
i810_dma_dispatch_vertex(dev,
- dma->buflist[vertex.idx],
- vertex.discard, vertex.used);
+ dma->buflist[vertex->idx],
+ vertex->discard, vertex->used);
- atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_add(vertex->used, &dev->counts[_DRM_STAT_SECONDARY]);
atomic_inc(&dev->counts[_DRM_STAT_DMA]);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1046,48 +967,37 @@ static int i810_dma_vertex(struct inode *inode, struct file *filp,
return 0;
}
-static int i810_clear_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_clear_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_i810_clear_t clear;
+ drm_i810_clear_t *clear = data;
- if (copy_from_user
- (&clear, (drm_i810_clear_t __user *) arg, sizeof(clear)))
- return -EFAULT;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
if (!dev->dev_private) {
return -EINVAL;
}
- i810_dma_dispatch_clear(dev, clear.flags,
- clear.clear_color, clear.clear_depth);
+ i810_dma_dispatch_clear(dev, clear->flags,
+ clear->clear_color, clear->clear_depth);
return 0;
}
-static int i810_swap_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_swap_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
DRM_DEBUG("i810_swap_bufs\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i810_dma_dispatch_swap(dev);
return 0;
}
-static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_getage(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1097,46 +1007,39 @@ static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_getbuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
int retcode = 0;
- drm_i810_dma_t d;
+ drm_i810_dma_t *d = data;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- if (copy_from_user(&d, (drm_i810_dma_t __user *) arg, sizeof(d)))
- return -EFAULT;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- d.granted = 0;
+ d->granted = 0;
- retcode = i810_dma_get_buffer(dev, &d, filp);
+ retcode = i810_dma_get_buffer(dev, d, file_priv);
DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
- current->pid, retcode, d.granted);
+ current->pid, retcode, d->granted);
- if (copy_to_user((void __user *) arg, &d, sizeof(d)))
- return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
return retcode;
}
-static int i810_copybuf(struct inode *inode,
- struct file *filp, unsigned int cmd, unsigned long arg)
+static int i810_copybuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
}
-static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_docopy(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
@@ -1202,30 +1105,25 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
ADVANCE_LP_RING();
}
-static int i810_dma_mc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_dma_mc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- drm_i810_mc_t mc;
-
- if (copy_from_user(&mc, (drm_i810_mc_t __user *) arg, sizeof(mc)))
- return -EFAULT;
+ drm_i810_mc_t *mc = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (mc.idx >= dma->buf_count || mc.idx < 0)
+ if (mc->idx >= dma->buf_count || mc->idx < 0)
return -EINVAL;
- i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
- mc.last_render);
+ i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used,
+ mc->last_render);
- atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_add(mc->used, &dev->counts[_DRM_STAT_SECONDARY]);
atomic_inc(&dev->counts[_DRM_STAT_DMA]);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1233,52 +1131,41 @@ static int i810_dma_mc(struct inode *inode, struct file *filp,
return 0;
}
-static int i810_rstatus(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_rstatus(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
}
-static int i810_ov0_info(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_ov0_info(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- drm_i810_overlay_t data;
+ drm_i810_overlay_t *ov = data;
+
+ ov->offset = dev_priv->overlay_offset;
+ ov->physical = dev_priv->overlay_physical;
- data.offset = dev_priv->overlay_offset;
- data.physical = dev_priv->overlay_physical;
- if (copy_to_user
- ((drm_i810_overlay_t __user *) arg, &data, sizeof(data)))
- return -EFAULT;
return 0;
}
-static int i810_fstatus(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_fstatus(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return I810_READ(0x30008);
}
-static int i810_ov0_flip(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_ov0_flip(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
//Tell the overlay to update
I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
@@ -1310,16 +1197,14 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev)
return 0;
}
-static int i810_flip_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->page_flipping)
i810_do_init_pageflip(dev);
@@ -1345,7 +1230,7 @@ void i810_driver_lastclose(struct drm_device * dev)
i810_dma_cleanup(dev);
}
-void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1355,9 +1240,10 @@ void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
}
}
-void i810_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
- i810_reclaim_buffers(dev, filp);
+ i810_reclaim_buffers(dev, file_priv);
}
int i810_driver_dma_quiescent(struct drm_device * dev)
@@ -1366,22 +1252,22 @@ int i810_driver_dma_quiescent(struct drm_device * dev)
return 0;
}
-drm_ioctl_desc_t i810_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, DRM_AUTH}
+struct drm_ioctl_desc i810_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH)
};
int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h
index 614977dbce4..7a10bb6f2c0 100644
--- a/drivers/char/drm/i810_drm.h
+++ b/drivers/char/drm/i810_drm.h
@@ -102,13 +102,8 @@ typedef enum _drm_i810_init_func {
/* This is the init structure after v1.2 */
typedef struct _drm_i810_init {
drm_i810_init_func_t func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int ring_map_idx;
- int buffer_map_idx;
-#else
unsigned int mmio_offset;
unsigned int buffers_offset;
-#endif
int sarea_priv_offset;
unsigned int ring_start;
unsigned int ring_end;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index 648833844c7..0af45872f67 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -117,15 +117,16 @@ typedef struct drm_i810_private {
/* i810_dma.c */
extern int i810_driver_dma_quiescent(struct drm_device * dev);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i810_driver_load(struct drm_device *, unsigned long flags);
extern void i810_driver_lastclose(struct drm_device * dev);
-extern void i810_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i810_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i810_driver_device_is_agp(struct drm_device * dev);
-extern drm_ioctl_desc_t i810_ioctls[];
+extern struct drm_ioctl_desc i810_ioctls[];
extern int i810_max_ioctl;
#define I810_BASE(reg) ((unsigned long) \
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index dc20c1a7834..43a1f78712d 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -122,10 +122,9 @@ static const struct file_operations i830_buffer_fops = {
.fasync = drm_fasync,
};
-static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = file_priv->head->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
drm_i830_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
@@ -136,13 +135,13 @@ static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
return -EINVAL;
down_write(&current->mm->mmap_sem);
- old_fops = filp->f_op;
- filp->f_op = &i830_buffer_fops;
+ old_fops = file_priv->filp->f_op;
+ file_priv->filp->f_op = &i830_buffer_fops;
dev_priv->mmap_buffer = buf;
- virtual = do_mmap(filp, 0, buf->total, PROT_READ | PROT_WRITE,
+ virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE,
MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL;
- filp->f_op = old_fops;
+ file_priv->filp->f_op = old_fops;
if (IS_ERR((void *)virtual)) { /* ugh */
/* Real error */
DRM_ERROR("mmap error\n");
@@ -177,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf)
}
static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
- struct file *filp)
+ struct drm_file *file_priv)
{
struct drm_buf *buf;
drm_i830_buf_priv_t *buf_priv;
@@ -190,13 +189,13 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
return retcode;
}
- retcode = i830_map_buffer(buf, filp);
+ retcode = i830_map_buffer(buf, file_priv);
if (retcode) {
i830_freelist_put(dev, buf);
DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
return retcode;
}
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf_priv = buf->dev_private;
d->granted = 1;
d->request_idx = buf->idx;
@@ -389,7 +388,7 @@ static int i830_dma_initialize(struct drm_device * dev,
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -451,25 +450,20 @@ static int i830_dma_initialize(struct drm_device * dev,
return 0;
}
-static int i830_dma_init(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv;
- drm_i830_init_t init;
+ drm_i830_init_t *init = data;
int retcode = 0;
- if (copy_from_user(&init, (void *__user)arg, sizeof(init)))
- return -EFAULT;
-
- switch (init.func) {
+ switch (init->func) {
case I830_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i830_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;
- retcode = i830_dma_initialize(dev, dev_priv, &init);
+ retcode = i830_dma_initialize(dev, dev_priv, init);
break;
case I830_CLEANUP_DMA:
retcode = i830_dma_cleanup(dev);
@@ -1248,7 +1242,7 @@ static int i830_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -1266,7 +1260,7 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv) {
+ if (buf->file_priv == file_priv && buf_priv) {
int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
I830_BUF_FREE);
@@ -1278,45 +1272,36 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
}
}
-static int i830_flush_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i830_flush_queue(dev);
return 0;
}
-static int i830_dma_vertex(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_dma_vertex(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
dev_priv->sarea_priv;
- drm_i830_vertex_t vertex;
-
- if (copy_from_user
- (&vertex, (drm_i830_vertex_t __user *) arg, sizeof(vertex)))
- return -EFAULT;
+ drm_i830_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
- vertex.idx, vertex.used, vertex.discard);
+ vertex->idx, vertex->used, vertex->discard);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
return -EINVAL;
i830_dma_dispatch_vertex(dev,
- dma->buflist[vertex.idx],
- vertex.discard, vertex.used);
+ dma->buflist[vertex->idx],
+ vertex->discard, vertex->used);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1324,39 +1309,30 @@ static int i830_dma_vertex(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_clear_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_clear_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_i830_clear_t clear;
-
- if (copy_from_user
- (&clear, (drm_i830_clear_t __user *) arg, sizeof(clear)))
- return -EFAULT;
+ drm_i830_clear_t *clear = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
if (!dev->dev_private) {
return -EINVAL;
}
- i830_dma_dispatch_clear(dev, clear.flags,
- clear.clear_color,
- clear.clear_depth, clear.clear_depthmask);
+ i830_dma_dispatch_clear(dev, clear->flags,
+ clear->clear_color,
+ clear->clear_depth, clear->clear_depthmask);
return 0;
}
-static int i830_swap_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_swap_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
DRM_DEBUG("i830_swap_bufs\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i830_dma_dispatch_swap(dev);
return 0;
@@ -1386,16 +1362,14 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev)
return 0;
}
-static int i830_flip_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->page_flipping)
i830_do_init_pageflip(dev);
@@ -1404,11 +1378,9 @@ static int i830_flip_bufs(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_getage(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
@@ -1418,58 +1390,50 @@ static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_getbuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
int retcode = 0;
- drm_i830_dma_t d;
+ drm_i830_dma_t *d = data;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
dev_priv->sarea_priv;
DRM_DEBUG("getbuf\n");
- if (copy_from_user(&d, (drm_i830_dma_t __user *) arg, sizeof(d)))
- return -EFAULT;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- d.granted = 0;
+ d->granted = 0;
- retcode = i830_dma_get_buffer(dev, &d, filp);
+ retcode = i830_dma_get_buffer(dev, d, file_priv);
DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
- current->pid, retcode, d.granted);
+ current->pid, retcode, d->granted);
- if (copy_to_user((void __user *) arg, &d, sizeof(d)))
- return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
return retcode;
}
-static int i830_copybuf(struct inode *inode,
- struct file *filp, unsigned int cmd, unsigned long arg)
+static int i830_copybuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
}
-static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_docopy(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
return 0;
}
-static int i830_getparam(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_getparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_getparam_t param;
+ drm_i830_getparam_t *param = data;
int value;
if (!dev_priv) {
@@ -1477,11 +1441,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (copy_from_user
- (&param, (drm_i830_getparam_t __user *) arg, sizeof(param)))
- return -EFAULT;
-
- switch (param.param) {
+ switch (param->param) {
case I830_PARAM_IRQ_ACTIVE:
value = dev->irq_enabled;
break;
@@ -1489,7 +1449,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (copy_to_user(param.value, &value, sizeof(int))) {
+ if (copy_to_user(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return -EFAULT;
}
@@ -1497,26 +1457,20 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_setparam(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_setparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_setparam_t param;
+ drm_i830_setparam_t *param = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user
- (&param, (drm_i830_setparam_t __user *) arg, sizeof(param)))
- return -EFAULT;
-
- switch (param.param) {
+ switch (param->param) {
case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param.value;
+ dev_priv->use_mi_batchbuffer_start = param->value;
break;
default:
return -EINVAL;
@@ -1542,7 +1496,7 @@ void i830_driver_lastclose(struct drm_device * dev)
i830_dma_cleanup(dev);
}
-void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1552,9 +1506,9 @@ void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
}
}
-void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
{
- i830_reclaim_buffers(dev, filp);
+ i830_reclaim_buffers(dev, file_priv);
}
int i830_driver_dma_quiescent(struct drm_device * dev)
@@ -1563,21 +1517,21 @@ int i830_driver_dma_quiescent(struct drm_device * dev)
return 0;
}
-drm_ioctl_desc_t i830_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, DRM_AUTH}
+struct drm_ioctl_desc i830_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
};
int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index ddda67956de..db3a9fa8396 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -122,24 +122,25 @@ typedef struct drm_i830_private {
} drm_i830_private_t;
-extern drm_ioctl_desc_t i830_ioctls[];
+extern struct drm_ioctl_desc i830_ioctls[];
extern int i830_max_ioctl;
/* i830_irq.c */
-extern int i830_irq_emit(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i830_irq_wait(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int i830_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i830_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
extern void i830_driver_irq_preinstall(struct drm_device * dev);
extern void i830_driver_irq_postinstall(struct drm_device * dev);
extern void i830_driver_irq_uninstall(struct drm_device * dev);
extern int i830_driver_load(struct drm_device *, unsigned long flags);
-extern void i830_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i830_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern void i830_driver_lastclose(struct drm_device * dev);
extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i830_driver_dma_quiescent(struct drm_device * dev);
extern int i830_driver_device_is_agp(struct drm_device * dev);
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index a1b5c63c3c3..76403f4b620 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -114,29 +114,23 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr)
/* Needs the lock as it touches the ring.
*/
-int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i830_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_irq_emit_t emit;
+ drm_i830_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user
- (&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit)))
- return -EFAULT;
-
result = i830_emit_irq(dev);
- if (copy_to_user(emit.irq_seq, &result, sizeof(int))) {
+ if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return -EFAULT;
}
@@ -146,24 +140,18 @@ int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
/* Doesn't need the hardware lock.
*/
-int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i830_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_irq_wait_t irqwait;
+ drm_i830_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg,
- sizeof(irqwait)))
- return -EFAULT;
-
- return i830_wait_irq(dev, irqwait.irq_seq);
+ return i830_wait_irq(dev, irqwait->irq_seq);
}
/* drm_dma.h hooks
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 8e7d713a5a1..e61a43e5b3a 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -70,7 +70,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
last_head = ring->head;
}
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
void i915_kernel_lost_context(struct drm_device * dev)
@@ -137,7 +137,7 @@ static int i915_initialize(struct drm_device * dev,
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
@@ -145,7 +145,7 @@ static int i915_initialize(struct drm_device * dev,
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->sarea_priv = (drm_i915_sarea_t *)
@@ -169,7 +169,7 @@ static int i915_initialize(struct drm_device * dev,
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -200,7 +200,7 @@ static int i915_initialize(struct drm_device * dev,
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("Can not allocate hardware status page\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
@@ -221,24 +221,24 @@ static int i915_dma_resume(struct drm_device * dev)
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->mmio_map) {
DRM_ERROR("can not find mmio map!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
/* Program Hardware Status Page */
if (!dev_priv->hw_status_page) {
DRM_ERROR("Can not find hardware status page\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
@@ -251,23 +251,20 @@ static int i915_dma_resume(struct drm_device * dev)
return 0;
}
-static int i915_dma_init(DRM_IOCTL_ARGS)
+static int i915_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv;
- drm_i915_init_t init;
+ drm_i915_init_t *init = data;
int retcode = 0;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case I915_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
- retcode = i915_initialize(dev, dev_priv, &init);
+ return -ENOMEM;
+ retcode = i915_initialize(dev, dev_priv, init);
break;
case I915_CLEANUP_DMA:
retcode = i915_dma_cleanup(dev);
@@ -276,7 +273,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
retcode = i915_dma_resume(dev);
break;
default:
- retcode = DRM_ERR(EINVAL);
+ retcode = -EINVAL;
break;
}
@@ -366,7 +363,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
RING_LOCALS;
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_LP_RING((dwords+1)&~1);
@@ -374,17 +371,17 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
int cmd, sz;
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
- return DRM_ERR(EINVAL);
+ return -EINVAL;
if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
OUT_RING(cmd);
while (++i, --sz) {
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
sizeof(cmd))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
OUT_RING(cmd);
}
@@ -407,13 +404,13 @@ static int i915_emit_box(struct drm_device * dev,
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
DRM_ERROR("Bad box %d,%d..%d,%d\n",
box.x1, box.y1, box.x2, box.y2);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (IS_I965G(dev)) {
@@ -467,7 +464,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
if (cmd->sz & 0x3) {
DRM_ERROR("alignment");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
i915_kernel_lost_context(dev);
@@ -502,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
i915_kernel_lost_context(dev);
@@ -598,76 +595,69 @@ static int i915_quiescent(struct drm_device * dev)
return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
}
-static int i915_flush_ioctl(DRM_IOCTL_ARGS)
+static int i915_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return i915_quiescent(dev);
}
-static int i915_batchbuffer(DRM_IOCTL_ARGS)
+static int i915_batchbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
- drm_i915_batchbuffer_t batch;
+ drm_i915_batchbuffer_t *batch = data;
int ret;
if (!dev_priv->allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data,
- sizeof(batch));
-
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
- batch.start, batch.used, batch.num_cliprects);
+ batch->start, batch->used, batch->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
- batch.num_cliprects *
+ if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
+ batch->num_cliprects *
sizeof(struct drm_clip_rect)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- ret = i915_dispatch_batchbuffer(dev, &batch);
+ ret = i915_dispatch_batchbuffer(dev, batch);
sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
-static int i915_cmdbuffer(DRM_IOCTL_ARGS)
+static int i915_cmdbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
- drm_i915_cmdbuffer_t cmdbuf;
+ drm_i915_cmdbuffer_t *cmdbuf = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
-
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
- cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
+ cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (cmdbuf.num_cliprects &&
- DRM_VERIFYAREA_READ(cmdbuf.cliprects,
- cmdbuf.num_cliprects *
+ if (cmdbuf->num_cliprects &&
+ DRM_VERIFYAREA_READ(cmdbuf->cliprects,
+ cmdbuf->num_cliprects *
sizeof(struct drm_clip_rect))) {
DRM_ERROR("Fault accessing cliprects\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
+ ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
@@ -677,33 +667,29 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
return 0;
}
-static int i915_flip_bufs(DRM_IOCTL_ARGS)
+static int i915_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return i915_dispatch_flip(dev);
}
-static int i915_getparam(DRM_IOCTL_ARGS)
+static int i915_getparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_getparam_t param;
+ drm_i915_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data,
- sizeof(param));
-
- switch (param.param) {
+ switch (param->param) {
case I915_PARAM_IRQ_ACTIVE:
value = dev->irq ? 1 : 0;
break;
@@ -714,68 +700,64 @@ static int i915_getparam(DRM_IOCTL_ARGS)
value = READ_BREADCRUMB(dev_priv);
break;
default:
- DRM_ERROR("Unknown parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Unknown parameter %d\n", param->param);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("DRM_COPY_TO_USER failed\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int i915_setparam(DRM_IOCTL_ARGS)
+static int i915_setparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_setparam_t param;
+ drm_i915_setparam_t *param = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data,
- sizeof(param));
-
- switch (param.param) {
+ switch (param->param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
if (!IS_I965G(dev))
- dev_priv->use_mi_batchbuffer_start = param.value;
+ dev_priv->use_mi_batchbuffer_start = param->value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
- dev_priv->tex_lru_log_granularity = param.value;
+ dev_priv->tex_lru_log_granularity = param->value;
break;
case I915_SETPARAM_ALLOW_BATCHBUFFER:
- dev_priv->allow_batchbuffer = param.value;
+ dev_priv->allow_batchbuffer = param->value;
break;
default:
- DRM_ERROR("unknown parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("unknown parameter %d\n", param->param);
+ return -EINVAL;
}
return 0;
}
-static int i915_set_status_page(DRM_IOCTL_ARGS)
+static int i915_set_status_page(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_hws_addr_t hws;
+ drm_i915_hws_addr_t *hws = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data,
- sizeof(hws));
- printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr);
- dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12);
+ printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
+
+ dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
- dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr;
+ dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws->addr;
dev_priv->hws_map.size = 4*1024;
dev_priv->hws_map.type = 0;
dev_priv->hws_map.flags = 0;
@@ -788,7 +770,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->status_gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
" G33 hw status page\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->hw_status_page = dev_priv->hws_map.handle;
@@ -821,32 +803,32 @@ void i915_driver_lastclose(struct drm_device * dev)
i915_dma_cleanup(dev);
}
-void i915_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
- i915_mem_release(dev, filp, dev_priv->agp_heap);
+ i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}
}
-drm_ioctl_desc_t i915_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
- [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
- [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
- [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH},
+struct drm_ioctl_desc i915_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+ DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+ DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ),
+ DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 28b98733beb..e064292e703 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -70,7 +70,7 @@ struct mem_block {
struct mem_block *prev;
int start;
int size;
- DRMFILE filp; /* 0: free, -1: heap, other: real files */
+ struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};
typedef struct _drm_i915_vbl_swap {
@@ -116,21 +116,24 @@ typedef struct drm_i915_private {
unsigned int swaps_pending;
} drm_i915_private_t;
-extern drm_ioctl_desc_t i915_ioctls[];
+extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
/* i915_dma.c */
extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern void i915_driver_lastclose(struct drm_device * dev);
-extern void i915_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i915_driver_preclose(struct drm_device *dev,
+ struct drm_file *file_priv);
extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/* i915_irq.c */
-extern int i915_irq_emit(DRM_IOCTL_ARGS);
-extern int i915_irq_wait(DRM_IOCTL_ARGS);
+extern int i915_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
@@ -138,18 +141,25 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
extern void i915_driver_irq_postinstall(struct drm_device * dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
-extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
-extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
-extern int i915_vblank_swap(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_vblank_swap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* i915_mem.c */
-extern int i915_mem_alloc(DRM_IOCTL_ARGS);
-extern int i915_mem_free(DRM_IOCTL_ARGS);
-extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
-extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
+extern int i915_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_init_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(struct drm_device * dev,
- DRMFILE filp, struct mem_block *heap);
+ struct drm_file *file_priv, struct mem_block *heap);
#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg))
#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index bb8e9e9c820..a443f4a202e 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -311,7 +311,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
- if (ret == DRM_ERR(EBUSY)) {
+ if (ret == -EBUSY) {
DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
__FUNCTION__,
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
@@ -330,7 +330,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequ
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
@@ -355,28 +355,25 @@ int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
/* Needs the lock as it touches the ring.
*/
-int i915_irq_emit(DRM_IOCTL_ARGS)
+int i915_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_emit_t emit;
+ drm_i915_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
- sizeof(emit));
-
result = i915_emit_irq(dev);
- if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+ if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
@@ -384,21 +381,18 @@ int i915_irq_emit(DRM_IOCTL_ARGS)
/* Doesn't need the hardware lock.
*/
-int i915_irq_wait(DRM_IOCTL_ARGS)
+int i915_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_wait_t irqwait;
+ drm_i915_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
- sizeof(irqwait));
-
- return i915_wait_irq(dev, irqwait.irq_seq);
+ return i915_wait_irq(dev, irqwait->irq_seq);
}
static void i915_enable_interrupt (struct drm_device *dev)
@@ -417,64 +411,60 @@ static void i915_enable_interrupt (struct drm_device *dev)
/* Set the vblank monitor pipe
*/
-int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t pipe;
+ drm_i915_vblank_pipe_t *pipe = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
- sizeof(pipe));
-
- if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
DRM_ERROR("%s called with invalid pipe 0x%x\n",
- __FUNCTION__, pipe.pipe);
- return DRM_ERR(EINVAL);
+ __FUNCTION__, pipe->pipe);
+ return -EINVAL;
}
- dev_priv->vblank_pipe = pipe.pipe;
+ dev_priv->vblank_pipe = pipe->pipe;
i915_enable_interrupt (dev);
return 0;
}
-int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t pipe;
+ drm_i915_vblank_pipe_t *pipe = data;
u16 flag;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
flag = I915_READ(I915REG_INT_ENABLE_R);
- pipe.pipe = 0;
+ pipe->pipe = 0;
if (flag & VSYNC_PIPEA_FLAG)
- pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
+ pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
if (flag & VSYNC_PIPEB_FLAG)
- pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
- DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
- sizeof(pipe));
+ pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
+
return 0;
}
/**
* Schedule buffer swap at given vertical blank.
*/
-int i915_vblank_swap(DRM_IOCTL_ARGS)
+int i915_vblank_swap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_swap_t swap;
+ drm_i915_vblank_swap_t *swap = data;
drm_i915_vbl_swap_t *vbl_swap;
unsigned int pipe, seqtype, curseq;
unsigned long irqflags;
@@ -482,38 +472,35 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __func__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->sarea_priv->rotation) {
DRM_DEBUG("Rotation not supported\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
- sizeof(swap));
-
- if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
_DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
- DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
+ return -EINVAL;
}
- pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
- seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+ seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
if (!(dev_priv->vblank_pipe & (1 << pipe))) {
DRM_ERROR("Invalid pipe %d\n", pipe);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
spin_lock_irqsave(&dev->drw_lock, irqflags);
- if (!drm_get_drawable_info(dev, swap.drawable)) {
+ if (!drm_get_drawable_info(dev, swap->drawable)) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+ return -EINVAL;
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
@@ -521,14 +508,14 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
if (seqtype == _DRM_VBLANK_RELATIVE)
- swap.sequence += curseq;
+ swap->sequence += curseq;
- if ((curseq - swap.sequence) <= (1<<23)) {
- if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
- swap.sequence = curseq + 1;
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap->sequence = curseq + 1;
} else {
DRM_DEBUG("Missed target sequence\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -537,9 +524,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
list_for_each(list, &dev_priv->vbl_swaps.head) {
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
- if (vbl_swap->drw_id == swap.drawable &&
+ if (vbl_swap->drw_id == swap->drawable &&
vbl_swap->pipe == pipe &&
- vbl_swap->sequence == swap.sequence) {
+ vbl_swap->sequence == swap->sequence) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
return 0;
@@ -550,21 +537,21 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
if (dev_priv->swaps_pending >= 100) {
DRM_DEBUG("Too many swaps queued\n");
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
- vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+ vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
if (!vbl_swap) {
DRM_ERROR("Failed to allocate memory to queue swap\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
DRM_DEBUG("\n");
- vbl_swap->drw_id = swap.drawable;
+ vbl_swap->drw_id = swap->drawable;
vbl_swap->pipe = pipe;
- vbl_swap->sequence = swap.sequence;
+ vbl_swap->sequence = swap->sequence;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -573,9 +560,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
- DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
- sizeof(swap));
-
return 0;
}
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
index 50b4bacef0e..56fb9b30a5d 100644
--- a/drivers/char/drm/i915_mem.c
+++ b/drivers/char/drm/i915_mem.c
@@ -89,7 +89,7 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
- DRMFILE filp)
+ struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
@@ -99,7 +99,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -116,7 +116,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -126,20 +126,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
out:
/* Our block is in the middle */
- p->filp = filp;
+ p->file_priv = file_priv;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, DRMFILE filp)
+ int align2, struct drm_file *file_priv)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
for (p = heap->next; p != heap; p = p->next) {
int start = (p->start + mask) & ~mask;
- if (p->filp == NULL && start + size <= p->start + p->size)
- return split_block(p, start, size, filp);
+ if (p->file_priv == NULL && start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
}
return NULL;
@@ -158,12 +158,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
static void free_block(struct mem_block *p)
{
- p->filp = NULL;
+ p->file_priv = NULL;
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
- if (p->next->filp == NULL) {
+ if (p->next->file_priv == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -171,7 +171,7 @@ static void free_block(struct mem_block *p)
drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
}
- if (p->prev->filp == NULL) {
+ if (p->prev->file_priv == NULL) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
@@ -197,18 +197,19 @@ static int init_heap(struct mem_block **heap, int start, int size)
blocks->start = start;
blocks->size = size;
- blocks->filp = NULL;
+ blocks->file_priv = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
- (*heap)->filp = (DRMFILE) - 1;
+ (*heap)->file_priv = (struct drm_file *) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
-void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *heap)
+void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv,
+ struct mem_block *heap)
{
struct mem_block *p;
@@ -216,17 +217,17 @@ void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *h
return;
for (p = heap->next; p != heap; p = p->next) {
- if (p->filp == filp) {
- p->filp = NULL;
+ if (p->file_priv == file_priv) {
+ p->file_priv = NULL;
mark_block(dev, p, 0);
}
}
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
for (p = heap->next; p != heap; p = p->next) {
- while (p->filp == NULL && p->next->filp == NULL) {
+ while (p->file_priv == NULL && p->next->file_priv == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -267,129 +268,117 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
/* IOCTL HANDLERS */
-int i915_mem_alloc(DRM_IOCTL_ARGS)
+int i915_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_alloc_t alloc;
+ drm_i915_mem_alloc_t *alloc = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data,
- sizeof(alloc));
-
- heap = get_heap(dev_priv, alloc.region);
+ heap = get_heap(dev_priv, alloc->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
- if (alloc.alignment < 12)
- alloc.alignment = 12;
+ if (alloc->alignment < 12)
+ alloc->alignment = 12;
- block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+ block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
if (!block)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
mark_block(dev, block, 1);
- if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+ if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+ sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-int i915_mem_free(DRM_IOCTL_ARGS)
+int i915_mem_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_free_t memfree;
+ drm_i915_mem_free_t *memfree = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data,
- sizeof(memfree));
-
- heap = get_heap(dev_priv, memfree.region);
+ heap = get_heap(dev_priv, memfree->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- block = find_block(*heap, memfree.region_offset);
+ block = find_block(*heap, memfree->region_offset);
if (!block)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (block->filp != filp)
- return DRM_ERR(EPERM);
+ if (block->file_priv != file_priv)
+ return -EPERM;
mark_block(dev, block, 0);
free_block(block);
return 0;
}
-int i915_mem_init_heap(DRM_IOCTL_ARGS)
+int i915_mem_init_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_init_heap_t initheap;
+ drm_i915_mem_init_heap_t *initheap = data;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(initheap,
- (drm_i915_mem_init_heap_t __user *) data,
- sizeof(initheap));
-
- heap = get_heap(dev_priv, initheap.region);
+ heap = get_heap(dev_priv, initheap->region);
if (!heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (*heap) {
DRM_ERROR("heap already initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- return init_heap(heap, initheap.start, initheap.size);
+ return init_heap(heap, initheap->start, initheap->size);
}
-int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
+int i915_mem_destroy_heap( struct drm_device *dev, void *data,
+ struct drm_file *file_priv )
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_destroy_heap_t destroyheap;
+ drm_i915_mem_destroy_heap_t *destroyheap = data;
struct mem_block **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
- sizeof(destroyheap) );
-
- heap = get_heap( dev_priv, destroyheap.region );
+ heap = get_heap( dev_priv, destroyheap->region );
if (!heap) {
DRM_ERROR("get_heap failed");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (!*heap) {
DRM_ERROR("heap not initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
i915_mem_takedown( heap );
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
index 9c73a6e3861..c567c34cda7 100644
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -71,7 +71,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int mga_do_dma_reset(drm_mga_private_t * dev_priv)
@@ -256,7 +256,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
if (dev_priv->head == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0);
@@ -267,7 +267,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
if (entry == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(entry, 0, sizeof(drm_mga_freelist_t));
@@ -399,7 +399,7 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
if (!dev_priv)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
memset(dev_priv, 0, sizeof(drm_mga_private_t));
@@ -578,7 +578,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
dev_priv->warp->handle, dev_priv->primary->handle,
dev->agp_buffer_map->handle);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->dma_access = MGA_PAGPXFER;
@@ -622,7 +622,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
if (dev->dma == NULL) {
DRM_ERROR("dev->dma is NULL\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
/* Make drm_addbufs happy by not trying to create a mapping for less
@@ -656,7 +656,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
if (err != 0) {
DRM_ERROR("Unable to allocate primary DMA region: %d\n", err);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (dev_priv->primary->size != dma_bs->primary_size) {
@@ -759,36 +759,30 @@ static int mga_do_dma_bootstrap(struct drm_device * dev,
return err;
}
-int mga_dma_bootstrap(DRM_IOCTL_ARGS)
+int mga_dma_bootstrap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_mga_dma_bootstrap_t bootstrap;
+ drm_mga_dma_bootstrap_t *bootstrap = data;
int err;
static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
const drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private;
- DRM_COPY_FROM_USER_IOCTL(bootstrap,
- (drm_mga_dma_bootstrap_t __user *) data,
- sizeof(bootstrap));
-
- err = mga_do_dma_bootstrap(dev, &bootstrap);
+ err = mga_do_dma_bootstrap(dev, bootstrap);
if (err) {
mga_do_cleanup_dma(dev, FULL_CLEANUP);
return err;
}
if (dev_priv->agp_textures != NULL) {
- bootstrap.texture_handle = dev_priv->agp_textures->offset;
- bootstrap.texture_size = dev_priv->agp_textures->size;
+ bootstrap->texture_handle = dev_priv->agp_textures->offset;
+ bootstrap->texture_size = dev_priv->agp_textures->size;
} else {
- bootstrap.texture_handle = 0;
- bootstrap.texture_size = 0;
+ bootstrap->texture_handle = 0;
+ bootstrap->texture_size = 0;
}
- bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07];
- DRM_COPY_TO_USER_IOCTL((drm_mga_dma_bootstrap_t __user *)data,
- bootstrap, sizeof(bootstrap));
+ bootstrap->agp_mode = modes[bootstrap->agp_mode & 0x07];
return err;
}
@@ -826,7 +820,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("failed to find sarea!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->used_new_dma_init) {
@@ -837,29 +831,29 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
dev_priv->status = drm_core_findmap(dev, init->status_offset);
if (!dev_priv->status) {
DRM_ERROR("failed to find status page!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio) {
DRM_ERROR("failed to find mmio region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
if (!dev_priv->warp) {
DRM_ERROR("failed to find warp microcode region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
if (!dev_priv->primary) {
DRM_ERROR("failed to find primary dma region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map =
drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("failed to find dma buffer region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev_priv->warp, dev);
@@ -877,7 +871,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
((dev->agp_buffer_map == NULL) ||
(dev->agp_buffer_map->handle == NULL)))) {
DRM_ERROR("failed to ioremap agp regions!\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
ret = mga_warp_install_microcode(dev_priv);
@@ -927,7 +921,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
if (mga_freelist_init(dev, dev_priv) < 0) {
DRM_ERROR("could not initialize freelist\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
return 0;
@@ -1007,20 +1001,17 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
return 0;
}
-int mga_dma_init(DRM_IOCTL_ARGS)
+int mga_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_mga_init_t init;
+ drm_mga_init_t *init = data;
int err;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
- sizeof(init));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- switch (init.func) {
+ switch (init->func) {
case MGA_INIT_DMA:
- err = mga_do_init_dma(dev, &init);
+ err = mga_do_init_dma(dev, init);
if (err) {
(void)mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
@@ -1029,36 +1020,33 @@ int mga_dma_init(DRM_IOCTL_ARGS)
return mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* ================================================================
* Primary DMA stream management
*/
-int mga_dma_flush(DRM_IOCTL_ARGS)
+int mga_dma_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_lock lock;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ struct drm_lock *lock = data;
- DRM_COPY_FROM_USER_IOCTL(lock, (struct drm_lock __user *) data,
- sizeof(lock));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("%s%s%s\n",
- (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
- (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
- (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
+ (lock->flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
+ (lock->flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
+ (lock->flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
WRAP_WAIT_WITH_RETURN(dev_priv);
- if (lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
+ if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
mga_do_dma_flush(dev_priv);
}
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ if (lock->flags & _DRM_LOCK_QUIESCENT) {
#if MGA_DMA_DEBUG
int ret = mga_do_wait_for_idle(dev_priv);
if (ret < 0)
@@ -1072,12 +1060,12 @@ int mga_dma_flush(DRM_IOCTL_ARGS)
}
}
-int mga_dma_reset(DRM_IOCTL_ARGS)
+int mga_dma_reset(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return mga_do_dma_reset(dev_priv);
}
@@ -1086,7 +1074,8 @@ int mga_dma_reset(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int mga_dma_get_buffers(struct drm_device * dev,
+ struct drm_file *file_priv, struct drm_dma * d)
{
struct drm_buf *buf;
int i;
@@ -1094,61 +1083,56 @@ static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm
for (i = d->granted_count; i < d->request_count; i++) {
buf = mga_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i],
&buf->idx, sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i],
&buf->total, sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int mga_dma_buffers(DRM_IOCTL_ARGS)
+int mga_dma_buffers(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
int ret = 0;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = mga_dma_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = mga_dma_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 49253affa47..cd94c04e31c 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -148,15 +148,20 @@ typedef struct drm_mga_private {
unsigned int agp_size;
} drm_mga_private_t;
-extern drm_ioctl_desc_t mga_ioctls[];
+extern struct drm_ioctl_desc mga_ioctls[];
extern int mga_max_ioctl;
/* mga_dma.c */
-extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
-extern int mga_dma_init(DRM_IOCTL_ARGS);
-extern int mga_dma_flush(DRM_IOCTL_ARGS);
-extern int mga_dma_reset(DRM_IOCTL_ARGS);
-extern int mga_dma_buffers(DRM_IOCTL_ARGS);
+extern int mga_dma_bootstrap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_reset(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_buffers(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int mga_driver_load(struct drm_device *dev, unsigned long flags);
extern int mga_driver_unload(struct drm_device * dev);
extern void mga_driver_lastclose(struct drm_device * dev);
@@ -245,7 +250,7 @@ do { \
dev_priv->prim.high_mark ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
} \
} while (0)
@@ -256,7 +261,7 @@ do { \
if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
mga_do_dma_wrap_end( dev_priv ); \
} \
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
index d448b0aef33..5ec8b61c5d4 100644
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -392,7 +392,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv)
ctx->dstorg, dev_priv->front_offset,
dev_priv->back_offset);
ctx->dstorg = 0;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -411,7 +411,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
tex->texorg = 0;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -453,13 +453,13 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv,
dstorg + length > (dev_priv->texture_offset +
dev_priv->texture_size)) {
DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (length & MGA_ILOAD_MASK) {
DRM_ERROR("*** bad iload length: 0x%x\n",
length & MGA_ILOAD_MASK);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -471,7 +471,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv,
if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
(dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
@@ -828,24 +828,20 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit
*
*/
-static int mga_dma_clear(DRM_IOCTL_ARGS)
+static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_clear_t clear;
+ drm_mga_clear_t *clear = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_mga_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_clear(dev, &clear);
+ mga_dma_dispatch_clear(dev, clear);
/* Make sure we restore the 3D state next time.
*/
@@ -854,13 +850,12 @@ static int mga_dma_clear(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_swap(DRM_IOCTL_ARGS)
+static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
@@ -876,37 +871,32 @@ static int mga_dma_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_vertex(DRM_IOCTL_ARGS)
+static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_vertex_t vertex;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ drm_mga_vertex_t *vertex = data;
- DRM_COPY_FROM_USER_IOCTL(vertex,
- (drm_mga_vertex_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
- buf = dma->buflist[vertex.idx];
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
+ return -EINVAL;
+ buf = dma->buflist[vertex->idx];
buf_priv = buf->dev_private;
- buf->used = vertex.used;
- buf_priv->discard = vertex.discard;
+ buf->used = vertex->used;
+ buf_priv->discard = vertex->discard;
if (!mga_verify_state(dev_priv)) {
- if (vertex.discard) {
+ if (vertex->discard) {
if (buf_priv->dispatched == 1)
AGE_BUFFER(buf_priv);
buf_priv->dispatched = 0;
mga_freelist_put(dev, buf);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
@@ -916,82 +906,73 @@ static int mga_dma_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_indices(DRM_IOCTL_ARGS)
+static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_indices_t indices;
+ drm_mga_indices_t *indices = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(indices,
- (drm_mga_indices_t __user *) data,
- sizeof(indices));
+ if (indices->idx < 0 || indices->idx > dma->buf_count)
+ return -EINVAL;
- if (indices.idx < 0 || indices.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
-
- buf = dma->buflist[indices.idx];
+ buf = dma->buflist[indices->idx];
buf_priv = buf->dev_private;
- buf_priv->discard = indices.discard;
+ buf_priv->discard = indices->discard;
if (!mga_verify_state(dev_priv)) {
- if (indices.discard) {
+ if (indices->discard) {
if (buf_priv->dispatched == 1)
AGE_BUFFER(buf_priv);
buf_priv->dispatched = 0;
mga_freelist_put(dev, buf);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_indices(dev, buf, indices.start, indices.end);
+ mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
return 0;
}
-static int mga_dma_iload(DRM_IOCTL_ARGS)
+static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_iload_t iload;
+ drm_mga_iload_t *iload = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(iload, (drm_mga_iload_t __user *) data,
- sizeof(iload));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
#if 0
if (mga_do_wait_for_idle(dev_priv) < 0) {
if (MGA_DMA_DEBUG)
DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
#endif
- if (iload.idx < 0 || iload.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
+ if (iload->idx < 0 || iload->idx > dma->buf_count)
+ return -EINVAL;
- buf = dma->buflist[iload.idx];
+ buf = dma->buflist[iload->idx];
buf_priv = buf->dev_private;
- if (mga_verify_iload(dev_priv, iload.dstorg, iload.length)) {
+ if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
mga_freelist_put(dev, buf);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_iload(dev, buf, iload.dstorg, iload.length);
+ mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
/* Make sure we restore the 3D state next time.
*/
@@ -1000,28 +981,24 @@ static int mga_dma_iload(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_blit(DRM_IOCTL_ARGS)
+static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_blit_t blit;
+ drm_mga_blit_t *blit = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(blit, (drm_mga_blit_t __user *) data,
- sizeof(blit));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
- if (mga_verify_blit(dev_priv, blit.srcorg, blit.dstorg))
- return DRM_ERR(EINVAL);
+ if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
+ return -EINVAL;
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_blit(dev, &blit);
+ mga_dma_dispatch_blit(dev, blit);
/* Make sure we restore the 3D state next time.
*/
@@ -1030,24 +1007,20 @@ static int mga_dma_blit(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_getparam(DRM_IOCTL_ARGS)
+static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_getparam_t param;
+ drm_mga_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_mga_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case MGA_PARAM_IRQ_NR:
value = dev->irq;
break;
@@ -1055,36 +1028,35 @@ static int mga_getparam(DRM_IOCTL_ARGS)
value = dev_priv->chipset;
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int mga_set_fence(DRM_IOCTL_ARGS)
+static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- u32 temp;
+ u32 *fence = data;
DMA_LOCALS;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- /* I would normal do this assignment in the declaration of temp,
+ /* I would normal do this assignment in the declaration of fence,
* but dev_priv may be NULL.
*/
- temp = dev_priv->next_fence_to_post;
+ *fence = dev_priv->next_fence_to_post;
dev_priv->next_fence_to_post++;
BEGIN_DMA(1);
@@ -1093,53 +1065,40 @@ static int mga_set_fence(DRM_IOCTL_ARGS)
MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000);
ADVANCE_DMA();
- if (DRM_COPY_TO_USER((u32 __user *) data, &temp, sizeof(u32))) {
- DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
- }
-
return 0;
}
-static int mga_wait_fence(DRM_IOCTL_ARGS)
+static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *
+file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- u32 fence;
+ u32 *fence = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- mga_driver_fence_wait(dev, &fence);
-
- if (DRM_COPY_TO_USER((u32 __user *) data, &fence, sizeof(u32))) {
- DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
- }
-
+ mga_driver_fence_wait(dev, fence);
return 0;
}
-drm_ioctl_desc_t mga_ioctls[] = {
- [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+struct drm_ioctl_desc mga_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
};
int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
diff --git a/drivers/char/drm/mga_warp.c b/drivers/char/drm/mga_warp.c
index d67f4925fba..651b93c8ab5 100644
--- a/drivers/char/drm/mga_warp.c
+++ b/drivers/char/drm/mga_warp.c
@@ -141,7 +141,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
if (size > dev_priv->warp->size) {
DRM_ERROR("microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
switch (dev_priv->chipset) {
@@ -151,7 +151,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
case MGA_CARD_TYPE_G200:
return mga_warp_install_g200_microcode(dev_priv);
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -177,7 +177,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
MGA_WRITE(MGA_WVRTXSZ, 7);
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
@@ -186,7 +186,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
if (wmisc != WMISC_EXPECTED) {
DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
wmisc, WMISC_EXPECTED);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index b163ed09bd8..7d550aba165 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -129,7 +129,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
@@ -146,7 +146,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
@@ -168,7 +168,7 @@ static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* ================================================================
@@ -227,7 +227,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv)
DRM_ERROR("failed!\n");
r128_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* Start the Concurrent Command Engine.
@@ -355,7 +355,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_r128_private_t));
@@ -365,7 +365,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("PCI GART memory not allocated!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->usec_timeout = init->usec_timeout;
@@ -374,7 +374,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_DEBUG("TIMEOUT problem!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cce_mode = init->cce_mode;
@@ -394,7 +394,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_DEBUG("Bad cce_mode!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch (init->cce_mode) {
@@ -461,7 +461,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find sarea!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
@@ -469,21 +469,21 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find mmio region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
if (!dev_priv->cce_ring) {
DRM_ERROR("could not find cce ring region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
if (!dev_priv->ring_rptr) {
DRM_ERROR("could not find ring read pointer!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
@@ -491,7 +491,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find dma buffer region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->is_pci) {
@@ -501,7 +501,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find agp texture region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -520,7 +520,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("Could not ioremap agp regions!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
} else
#endif
@@ -567,7 +567,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("failed to init PCI GART!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
#if __OS_HAS_AGP
@@ -625,35 +625,30 @@ int r128_do_cleanup_cce(struct drm_device * dev)
return 0;
}
-int r128_cce_init(DRM_IOCTL_ARGS)
+int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_r128_init_t init;
+ drm_r128_init_t *init = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_r128_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case R128_INIT_CCE:
- return r128_do_init_cce(dev, &init);
+ return r128_do_init_cce(dev, init);
case R128_CLEANUP_CCE:
return r128_do_cleanup_cce(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-int r128_cce_start(DRM_IOCTL_ARGS)
+int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
DRM_DEBUG("%s while CCE running\n", __FUNCTION__);
@@ -668,30 +663,26 @@ int r128_cce_start(DRM_IOCTL_ARGS)
/* Stop the CCE. The engine must have been idled before calling this
* routine.
*/
-int r128_cce_stop(DRM_IOCTL_ARGS)
+int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_cce_stop_t stop;
+ drm_r128_cce_stop_t *stop = data;
int ret;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *) data,
- sizeof(stop));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Flush any pending CCE commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
- if (stop.flush) {
+ if (stop->flush) {
r128_do_cce_flush(dev_priv);
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
*/
- if (stop.idle) {
+ if (stop->idle) {
ret = r128_do_cce_idle(dev_priv);
if (ret)
return ret;
@@ -711,17 +702,16 @@ int r128_cce_stop(DRM_IOCTL_ARGS)
/* Just reset the CCE ring. Called as part of an X Server engine reset.
*/
-int r128_cce_reset(DRM_IOCTL_ARGS)
+int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_DEBUG("%s called before init done\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
r128_do_cce_reset(dev_priv);
@@ -732,13 +722,12 @@ int r128_cce_reset(DRM_IOCTL_ARGS)
return 0;
}
-int r128_cce_idle(DRM_IOCTL_ARGS)
+int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cce_running) {
r128_do_cce_flush(dev_priv);
@@ -747,19 +736,18 @@ int r128_cce_idle(DRM_IOCTL_ARGS)
return r128_do_cce_idle(dev_priv);
}
-int r128_engine_reset(DRM_IOCTL_ARGS)
+int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return r128_do_engine_reset(dev);
}
-int r128_fullscreen(DRM_IOCTL_ARGS)
+int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* ================================================================
@@ -780,7 +768,7 @@ static int r128_freelist_init(struct drm_device * dev)
dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (dev_priv->head == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
dev_priv->head->age = R128_BUFFER_USED;
@@ -791,7 +779,7 @@ static int r128_freelist_init(struct drm_device * dev)
entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (!entry)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
entry->age = R128_BUFFER_FREE;
entry->buf = buf;
@@ -828,7 +816,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev)
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0)
+ if (buf->file_priv == 0)
return buf;
}
@@ -883,10 +871,12 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
/* FIXME: This is being ignored... */
DRM_ERROR("failed!\n");
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
-static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int r128_cce_get_buffers(struct drm_device * dev,
+ struct drm_file *file_priv,
+ struct drm_dma * d)
{
int i;
struct drm_buf *buf;
@@ -894,57 +884,51 @@ static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct dr
for (i = d->granted_count; i < d->request_count; i++) {
buf = r128_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int r128_cce_buffers(DRM_IOCTL_ARGS)
+int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
int ret = 0;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = r128_cce_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = r128_cce_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index e94a39c6e32..8d8878b55f5 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -222,11 +222,7 @@ typedef struct drm_r128_init {
R128_INIT_CCE = 0x01,
R128_CLEANUP_CCE = 0x02
} func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int sarea_priv_offset;
-#else
unsigned long sarea_priv_offset;
-#endif
int is_pci;
int cce_mode;
int cce_secure;
@@ -240,21 +236,12 @@ typedef struct drm_r128_init {
unsigned int depth_offset, depth_pitch;
unsigned int span_offset;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- unsigned int fb_offset;
- unsigned int mmio_offset;
- unsigned int ring_offset;
- unsigned int ring_rptr_offset;
- unsigned int buffers_offset;
- unsigned int agp_textures_offset;
-#else
unsigned long fb_offset;
unsigned long mmio_offset;
unsigned long ring_offset;
unsigned long ring_rptr_offset;
unsigned long buffers_offset;
unsigned long agp_textures_offset;
-#endif
} drm_r128_init_t;
typedef struct drm_r128_cce_stop {
@@ -264,15 +251,10 @@ typedef struct drm_r128_cce_stop {
typedef struct drm_r128_clear {
unsigned int flags;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int x, y, w, h;
-#endif
unsigned int clear_color;
unsigned int clear_depth;
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
unsigned int color_mask;
unsigned int depth_mask;
-#endif
} drm_r128_clear_t;
typedef struct drm_r128_vertex {
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 72249fb2fd1..250d2aa4658 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -129,18 +129,18 @@ typedef struct drm_r128_buf_priv {
drm_r128_freelist_t *list_entry;
} drm_r128_buf_priv_t;
-extern drm_ioctl_desc_t r128_ioctls[];
+extern struct drm_ioctl_desc r128_ioctls[];
extern int r128_max_ioctl;
/* r128_cce.c */
-extern int r128_cce_init(DRM_IOCTL_ARGS);
-extern int r128_cce_start(DRM_IOCTL_ARGS);
-extern int r128_cce_stop(DRM_IOCTL_ARGS);
-extern int r128_cce_reset(DRM_IOCTL_ARGS);
-extern int r128_cce_idle(DRM_IOCTL_ARGS);
-extern int r128_engine_reset(DRM_IOCTL_ARGS);
-extern int r128_fullscreen(DRM_IOCTL_ARGS);
-extern int r128_cce_buffers(DRM_IOCTL_ARGS);
+extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void r128_freelist_reset(struct drm_device * dev);
@@ -156,7 +156,8 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev);
extern void r128_driver_irq_postinstall(struct drm_device * dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
-extern void r128_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void r128_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
@@ -428,7 +429,7 @@ do { \
DRM_UDELAY(1); \
} \
DRM_ERROR( "ring space check failed!\n" ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
__ring_space_done: \
; \
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 7b334fb7d64..b7f483cac6d 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -776,8 +776,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev,
sarea_priv->nbox = 0;
}
-static int r128_cce_dispatch_blit(DRMFILE filp,
- struct drm_device * dev, drm_r128_blit_t * blit)
+static int r128_cce_dispatch_blit(struct drm_device * dev,
+ struct drm_file *file_priv,
+ drm_r128_blit_t * blit)
{
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
@@ -809,7 +810,7 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
break;
default:
DRM_ERROR("invalid blit format %d\n", blit->format);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Flush the pixel cache, and mark the contents as Read Invalid.
@@ -829,14 +830,14 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
buf = dma->buflist[blit->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
DRM_ERROR("sending pending buffer %d\n", blit->idx);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
buf_priv->discard = 1;
@@ -900,22 +901,22 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
buffer_size = depth->n * sizeof(u32);
buffer = drm_alloc(buffer_size, DRM_MEM_BUFS);
if (buffer == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
mask_size = depth->n * sizeof(u8);
@@ -923,12 +924,12 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
mask = drm_alloc(mask_size, DRM_MEM_BUFS);
if (mask == NULL) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
drm_free(mask, mask_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++, x++) {
@@ -996,28 +997,28 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
xbuf_size = count * sizeof(*x);
ybuf_size = count * sizeof(*y);
x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
if (x == NULL) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
if (y == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
buffer_size = depth->n * sizeof(u32);
@@ -1025,13 +1026,13 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
if (buffer == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (depth->mask) {
@@ -1041,14 +1042,14 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
drm_free(mask, mask_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++) {
@@ -1115,13 +1116,13 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
BEGIN_RING(7);
@@ -1159,7 +1160,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (count > dev_priv->depth_pitch) {
count = dev_priv->depth_pitch;
@@ -1169,22 +1170,22 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
ybuf_size = count * sizeof(*y);
x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
if (x == NULL) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
if (y == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++) {
@@ -1241,25 +1242,21 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
* IOCTL functions
*/
-static int r128_cce_clear(DRM_IOCTL_ARGS)
+static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_clear_t clear;
+ drm_r128_clear_t *clear = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_r128_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
- r128_cce_dispatch_clear(dev, &clear);
+ r128_cce_dispatch_clear(dev, clear);
COMMIT_RING();
/* Make sure we restore the 3D state next time.
@@ -1309,13 +1306,12 @@ static int r128_do_cleanup_pageflip(struct drm_device * dev)
* They can & should be intermixed to support multiple 3d windows.
*/
-static int r128_cce_flip(DRM_IOCTL_ARGS)
+static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1328,14 +1324,13 @@ static int r128_cce_flip(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_swap(DRM_IOCTL_ARGS)
+static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1350,58 +1345,54 @@ static int r128_cce_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_vertex(DRM_IOCTL_ARGS)
+static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_vertex_t vertex;
+ drm_r128_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_r128_vertex_t __user *) data,
- sizeof(vertex));
-
DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (vertex.prim < 0 ||
- vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", vertex.prim);
- return DRM_ERR(EINVAL);
+ if (vertex->prim < 0 ||
+ vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+ DRM_ERROR("buffer prim %d\n", vertex->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
- buf->used = vertex.count;
- buf_priv->prim = vertex.prim;
- buf_priv->discard = vertex.discard;
+ buf->used = vertex->count;
+ buf_priv->prim = vertex->prim;
+ buf_priv->discard = vertex->discard;
r128_cce_dispatch_vertex(dev, buf);
@@ -1409,134 +1400,123 @@ static int r128_cce_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_indices(DRM_IOCTL_ARGS)
+static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_indices_t elts;
+ drm_r128_indices_t *elts = data;
int count;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(elts, (drm_r128_indices_t __user *) data,
- sizeof(elts));
-
DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID,
- elts.idx, elts.start, elts.end, elts.discard);
+ elts->idx, elts->start, elts->end, elts->discard);
- if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+ if (elts->idx < 0 || elts->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- elts.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ elts->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (elts.prim < 0 || elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", elts.prim);
- return DRM_ERR(EINVAL);
+ if (elts->prim < 0 ||
+ elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+ DRM_ERROR("buffer prim %d\n", elts->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[elts.idx];
+ buf = dma->buflist[elts->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", elts->idx);
+ return -EINVAL;
}
- count = (elts.end - elts.start) / sizeof(u16);
- elts.start -= R128_INDEX_PRIM_OFFSET;
+ count = (elts->end - elts->start) / sizeof(u16);
+ elts->start -= R128_INDEX_PRIM_OFFSET;
- if (elts.start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
- return DRM_ERR(EINVAL);
+ if (elts->start & 0x7) {
+ DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+ return -EINVAL;
}
- if (elts.start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
- return DRM_ERR(EINVAL);
+ if (elts->start < buf->used) {
+ DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+ return -EINVAL;
}
- buf->used = elts.end;
- buf_priv->prim = elts.prim;
- buf_priv->discard = elts.discard;
+ buf->used = elts->end;
+ buf_priv->prim = elts->prim;
+ buf_priv->discard = elts->discard;
- r128_cce_dispatch_indices(dev, buf, elts.start, elts.end, count);
+ r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
COMMIT_RING();
return 0;
}
-static int r128_cce_blit(DRM_IOCTL_ARGS)
+static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_blit_t blit;
+ drm_r128_blit_t *blit = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(blit, (drm_r128_blit_t __user *) data,
- sizeof(blit));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit.idx);
+ DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx);
- if (blit.idx < 0 || blit.idx >= dma->buf_count) {
+ if (blit->idx < 0 || blit->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- blit.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ blit->idx, dma->buf_count - 1);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- ret = r128_cce_dispatch_blit(filp, dev, &blit);
+ ret = r128_cce_dispatch_blit(dev, file_priv, blit);
COMMIT_RING();
return ret;
}
-static int r128_cce_depth(DRM_IOCTL_ARGS)
+static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_depth_t depth;
+ drm_r128_depth_t *depth = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(depth, (drm_r128_depth_t __user *) data,
- sizeof(depth));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
- ret = DRM_ERR(EINVAL);
- switch (depth.func) {
+ ret = -EINVAL;
+ switch (depth->func) {
case R128_WRITE_SPAN:
- ret = r128_cce_dispatch_write_span(dev, &depth);
+ ret = r128_cce_dispatch_write_span(dev, depth);
break;
case R128_WRITE_PIXELS:
- ret = r128_cce_dispatch_write_pixels(dev, &depth);
+ ret = r128_cce_dispatch_write_pixels(dev, depth);
break;
case R128_READ_SPAN:
- ret = r128_cce_dispatch_read_span(dev, &depth);
+ ret = r128_cce_dispatch_read_span(dev, depth);
break;
case R128_READ_PIXELS:
- ret = r128_cce_dispatch_read_pixels(dev, &depth);
+ ret = r128_cce_dispatch_read_pixels(dev, depth);
break;
}
@@ -1544,20 +1524,16 @@ static int r128_cce_depth(DRM_IOCTL_ARGS)
return ret;
}
-static int r128_cce_stipple(DRM_IOCTL_ARGS)
+static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_stipple_t stipple;
+ drm_r128_stipple_t *stipple = data;
u32 mask[32];
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stipple, (drm_r128_stipple_t __user *) data,
- sizeof(stipple));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1567,61 +1543,58 @@ static int r128_cce_stipple(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_indirect(DRM_IOCTL_ARGS)
+static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_indirect_t indirect;
+ drm_r128_indirect_t *indirect = data;
#if 0
RING_LOCALS;
#endif
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(indirect, (drm_r128_indirect_t __user *) data,
- sizeof(indirect));
-
DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
- indirect.idx, indirect.start, indirect.end, indirect.discard);
+ indirect->idx, indirect->start, indirect->end,
+ indirect->discard);
- if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+ if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- indirect.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ indirect->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- buf = dma->buflist[indirect.idx];
+ buf = dma->buflist[indirect->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+ return -EINVAL;
}
- if (indirect.start < buf->used) {
+ if (indirect->start < buf->used) {
DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect.start, buf->used);
- return DRM_ERR(EINVAL);
+ indirect->start, buf->used);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf->used = indirect.end;
- buf_priv->discard = indirect.discard;
+ buf->used = indirect->end;
+ buf_priv->discard = indirect->discard;
#if 0
/* Wait for the 3D stream to idle before the indirect buffer
@@ -1636,46 +1609,42 @@ static int r128_cce_indirect(DRM_IOCTL_ARGS)
* X server. This is insecure and is thus only available to
* privileged clients.
*/
- r128_cce_dispatch_indirect(dev, buf, indirect.start, indirect.end);
+ r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
COMMIT_RING();
return 0;
}
-static int r128_getparam(DRM_IOCTL_ARGS)
+static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_getparam_t param;
+ drm_r128_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_r128_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case R128_PARAM_IRQ_NR:
value = dev->irq;
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-void r128_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1690,24 +1659,24 @@ void r128_driver_lastclose(struct drm_device * dev)
r128_do_cleanup_cce(dev);
}
-drm_ioctl_desc_t r128_ioctls[] = {
- [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, DRM_AUTH},
+struct drm_ioctl_desc r128_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH),
};
int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index 4e5aca6ba59..59b2944811c 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -74,7 +74,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
if (DRM_COPY_FROM_USER_UNCHECKED
(&box, &cmdbuf->boxes[n + i], sizeof(box))) {
DRM_ERROR("copy cliprect faulted\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
box.x1 =
@@ -263,7 +263,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
DRM_ERROR
("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
reg, sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
for (i = 0; i < sz; i++) {
values[i] = ((int *)cmdbuf->buf)[i];
@@ -275,13 +275,13 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("Register %04x failed check as flag=%02x\n",
reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -317,12 +317,12 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
return 0;
if (sz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
if (reg + sz * 4 >= 0x10000) {
DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,
sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (r300_check_range(reg, sz)) {
@@ -362,7 +362,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
if (sz * 16 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(5 + sz * 4);
/* Wait for VAP to come to senses.. */
@@ -391,7 +391,7 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
RING_LOCALS;
if (8 * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(10);
OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
@@ -421,7 +421,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if ((count + 1) > MAX_ARRAY_PACKET) {
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
memset(payload, 0, MAX_ARRAY_PACKET * 4);
memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
@@ -437,7 +437,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -448,7 +448,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -458,7 +458,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* all clear, output packet */
@@ -492,7 +492,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -502,7 +502,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -530,12 +530,12 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(count+2);
@@ -557,7 +557,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
RING_LOCALS;
if (4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
/* Fixme !! This simply emits a packet without much checking.
We need to be smarter. */
@@ -568,7 +568,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
/* Is it packet 3 ? */
if ((header >> 30) != 0x3) {
DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
count = (header >> 16) & 0x3fff;
@@ -578,7 +578,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Expected packet3 of length %d but have only %d bytes left\n",
(count + 2) * 4, cmdbuf->bufsz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Is it a packet type we know about ? */
@@ -600,7 +600,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
break;
default:
DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(count + 2);
@@ -664,7 +664,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
DRM_ERROR("bad packet3 type %i at %p\n",
header.packet3.packet,
cmdbuf->buf - sizeof(header));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
n += R300_SIMULTANEOUS_CLIPRECTS;
@@ -726,11 +726,11 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
if (cmdbuf->bufsz <
(sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (header.scratch.reg >= 5) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->scratch_ages[header.scratch.reg]++;
@@ -745,21 +745,21 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
buf_idx *= 2; /* 8 bytes per buf */
if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (h_pending == 0) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
h_pending--;
if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmdbuf->buf += sizeof(buf_idx);
@@ -780,8 +780,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
* Called by the ioctl handler function radeon_cp_cmdbuf.
*/
int r300_do_cp_cmdbuf(struct drm_device *dev,
- DRMFILE filp,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -879,15 +878,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1);
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto cleanup;
}
buf = dma->buflist[idx];
- if (buf->filp != filp || buf->pending) {
+ if (buf->file_priv != file_priv || buf->pending) {
DRM_ERROR("bad buffer %p %p %d\n",
- buf->filp, filp, buf->pending);
- ret = DRM_ERR(EINVAL);
+ buf->file_priv, file_priv,
+ buf->pending);
+ ret = -EINVAL;
goto cleanup;
}
@@ -924,7 +924,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
DRM_ERROR("bad cmd_type %i at %p\n",
header.header.cmd_type,
cmdbuf->buf - sizeof(header));
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto cleanup;
}
}
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index af5790f8fd5..335423c5c18 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -889,7 +889,7 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
@@ -910,7 +910,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
@@ -936,7 +936,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* ================================================================
@@ -1394,7 +1394,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
@@ -1409,7 +1409,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
DRM_ERROR("PCI GART memory not allocated!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->usec_timeout = init->usec_timeout;
@@ -1417,7 +1417,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
DRM_DEBUG("TIMEOUT problem!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Enable vblank on CRTC1 for older X servers
@@ -1446,7 +1446,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
(init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch (init->fb_bpp) {
@@ -1515,27 +1515,27 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
if (!dev_priv->cp_ring) {
DRM_ERROR("could not find cp ring region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
if (!dev_priv->ring_rptr) {
DRM_ERROR("could not find ring read pointer!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("could not find dma buffer region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->gart_textures_offset) {
@@ -1544,7 +1544,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if (!dev_priv->gart_textures) {
DRM_ERROR("could not find GART texture region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -1562,7 +1562,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
!dev->agp_buffer_map->handle) {
DRM_ERROR("could not find ioremap agp regions!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else
#endif
@@ -1710,14 +1710,14 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
DRM_ERROR
("Cannot use PCI Express without GART in FB memory\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
DRM_ERROR("failed to init PCI GART!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
/* Turn on PCI GART */
@@ -1797,7 +1797,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
if (!dev_priv) {
DRM_ERROR("Called with no initialization\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("Starting radeon_do_resume_cp()\n");
@@ -1823,38 +1823,33 @@ static int radeon_do_resume_cp(struct drm_device * dev)
return 0;
}
-int radeon_cp_init(DRM_IOCTL_ARGS)
+int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_radeon_init_t init;
+ drm_radeon_init_t *init = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_radeon_init_t __user *) data,
- sizeof(init));
-
- if (init.func == RADEON_INIT_R300_CP)
+ if (init->func == RADEON_INIT_R300_CP)
r300_init_reg_flags();
- switch (init.func) {
+ switch (init->func) {
case RADEON_INIT_CP:
case RADEON_INIT_R200_CP:
case RADEON_INIT_R300_CP:
- return radeon_do_init_cp(dev, &init);
+ return radeon_do_init_cp(dev, init);
case RADEON_CLEANUP_CP:
return radeon_do_cleanup_cp(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-int radeon_cp_start(DRM_IOCTL_ARGS)
+int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cp_running) {
DRM_DEBUG("%s while CP running\n", __FUNCTION__);
@@ -1874,18 +1869,14 @@ int radeon_cp_start(DRM_IOCTL_ARGS)
/* Stop the CP. The engine must have been idled before calling this
* routine.
*/
-int radeon_cp_stop(DRM_IOCTL_ARGS)
+int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_cp_stop_t stop;
+ drm_radeon_cp_stop_t *stop = data;
int ret;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stop, (drm_radeon_cp_stop_t __user *) data,
- sizeof(stop));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->cp_running)
return 0;
@@ -1893,14 +1884,14 @@ int radeon_cp_stop(DRM_IOCTL_ARGS)
/* Flush any pending CP commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
- if (stop.flush) {
+ if (stop->flush) {
radeon_do_cp_flush(dev_priv);
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
*/
- if (stop.idle) {
+ if (stop->idle) {
ret = radeon_do_cp_idle(dev_priv);
if (ret)
return ret;
@@ -1963,17 +1954,16 @@ void radeon_do_release(struct drm_device * dev)
/* Just reset the CP ring. Called as part of an X Server engine reset.
*/
-int radeon_cp_reset(DRM_IOCTL_ARGS)
+int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_DEBUG("%s called before init done\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
radeon_do_cp_reset(dev_priv);
@@ -1984,32 +1974,29 @@ int radeon_cp_reset(DRM_IOCTL_ARGS)
return 0;
}
-int radeon_cp_idle(DRM_IOCTL_ARGS)
+int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_cp_idle(dev_priv);
}
/* Added by Charl P. Botha to call radeon_do_resume_cp().
*/
-int radeon_cp_resume(DRM_IOCTL_ARGS)
+int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
return radeon_do_resume_cp(dev);
}
-int radeon_engine_reset(DRM_IOCTL_ARGS)
+int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_engine_reset(dev);
}
@@ -2020,7 +2007,7 @@ int radeon_engine_reset(DRM_IOCTL_ARGS)
/* KW: Deprecated to say the least:
*/
-int radeon_fullscreen(DRM_IOCTL_ARGS)
+int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
return 0;
}
@@ -2066,8 +2053,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
for (i = start; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0 || (buf->pending &&
- buf_priv->age <= done_age)) {
+ if (buf->file_priv == NULL || (buf->pending &&
+ buf_priv->age <=
+ done_age)) {
dev_priv->stats.requested_bufs++;
buf->pending = 0;
return buf;
@@ -2106,8 +2094,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
for (i = start; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0 || (buf->pending &&
- buf_priv->age <= done_age)) {
+ if (buf->file_priv == 0 || (buf->pending &&
+ buf_priv->age <=
+ done_age)) {
dev_priv->stats.requested_bufs++;
buf->pending = 0;
return buf;
@@ -2167,10 +2156,11 @@ int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
radeon_status(dev_priv);
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
-static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
+static int radeon_cp_get_buffers(struct drm_device *dev,
+ struct drm_file *file_priv,
struct drm_dma * d)
{
int i;
@@ -2179,58 +2169,52 @@ static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
for (i = d->granted_count; i < d->request_count; i++) {
buf = radeon_freelist_get(dev);
if (!buf)
- return DRM_ERR(EBUSY); /* NOTE: broken client */
+ return -EBUSY; /* NOTE: broken client */
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int radeon_cp_buffers(DRM_IOCTL_ARGS)
+int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
int ret = 0;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = radeon_cp_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = radeon_cp_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
@@ -2241,7 +2225,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_radeon_private_t));
dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 3b3d9357201..e4077bc212b 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -188,7 +188,7 @@ struct mem_block {
struct mem_block *prev;
int start;
int size;
- DRMFILE filp; /* 0: free, -1: heap, other: real files */
+ struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};
struct radeon_surface {
@@ -203,7 +203,7 @@ struct radeon_virt_surface {
u32 lower;
u32 upper;
u32 flags;
- DRMFILE filp;
+ struct drm_file *file_priv;
};
typedef struct drm_radeon_private {
@@ -307,7 +307,7 @@ typedef struct drm_radeon_kcmd_buffer {
} drm_radeon_kcmd_buffer_t;
extern int radeon_no_wb;
-extern drm_ioctl_desc_t radeon_ioctls[];
+extern struct drm_ioctl_desc radeon_ioctls[];
extern int radeon_max_ioctl;
/* Check whether the given hardware address is inside the framebuffer or the
@@ -326,15 +326,15 @@ static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
}
/* radeon_cp.c */
-extern int radeon_cp_init(DRM_IOCTL_ARGS);
-extern int radeon_cp_start(DRM_IOCTL_ARGS);
-extern int radeon_cp_stop(DRM_IOCTL_ARGS);
-extern int radeon_cp_reset(DRM_IOCTL_ARGS);
-extern int radeon_cp_idle(DRM_IOCTL_ARGS);
-extern int radeon_cp_resume(DRM_IOCTL_ARGS);
-extern int radeon_engine_reset(DRM_IOCTL_ARGS);
-extern int radeon_fullscreen(DRM_IOCTL_ARGS);
-extern int radeon_cp_buffers(DRM_IOCTL_ARGS);
+extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_freelist_reset(struct drm_device * dev);
extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -347,15 +347,16 @@ extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
extern int radeon_presetup(struct drm_device *dev);
extern int radeon_driver_postcleanup(struct drm_device *dev);
-extern int radeon_mem_alloc(DRM_IOCTL_ARGS);
-extern int radeon_mem_free(DRM_IOCTL_ARGS);
-extern int radeon_mem_init_heap(DRM_IOCTL_ARGS);
+extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_mem_takedown(struct mem_block **heap);
-extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap);
+extern void radeon_mem_release(struct drm_file *file_priv,
+ struct mem_block *heap);
/* radeon_irq.c */
-extern int radeon_irq_emit(DRM_IOCTL_ARGS);
-extern int radeon_irq_wait(DRM_IOCTL_ARGS);
+extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev);
extern int radeon_driver_vblank_wait(struct drm_device * dev,
@@ -372,7 +373,7 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
extern int radeon_driver_unload(struct drm_device *dev);
extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
extern void radeon_driver_lastclose(struct drm_device * dev);
extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
@@ -382,8 +383,8 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
/* r300_cmdbuf.c */
extern void r300_init_reg_flags(void);
-extern int r300_do_cp_cmdbuf(struct drm_device * dev, DRMFILE filp,
- struct drm_file * filp_priv,
+extern int r300_do_cp_cmdbuf(struct drm_device * dev,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t * cmdbuf);
/* Flags for stats.boxes
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index ad8a0ac7182..f89e57665b6 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -155,7 +155,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
atomic_t *counter;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (crtc == DRM_RADEON_VBLANK_CRTC1) {
@@ -165,7 +165,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
counter = &dev->vbl_received2;
ack |= RADEON_CRTC2_VBLANK_STAT;
} else
- return DRM_ERR(EINVAL);
+ return -EINVAL;
radeon_acknowledge_irqs(dev_priv, ack);
@@ -196,28 +196,24 @@ int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
/* Needs the lock as it touches the ring.
*/
-int radeon_irq_emit(DRM_IOCTL_ARGS)
+int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_emit_t emit;
+ drm_radeon_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data,
- sizeof(emit));
-
result = radeon_emit_irq(dev);
- if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+ if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
@@ -225,21 +221,17 @@ int radeon_irq_emit(DRM_IOCTL_ARGS)
/* Doesn't need the hardware lock.
*/
-int radeon_irq_wait(DRM_IOCTL_ARGS)
+int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_wait_t irqwait;
+ drm_radeon_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data,
- sizeof(irqwait));
-
- return radeon_wait_irq(dev, irqwait.irq_seq);
+ return radeon_wait_irq(dev, irqwait->irq_seq);
}
static void radeon_enable_interrupt(struct drm_device *dev)
@@ -320,7 +312,7 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->vblank_crtc = (unsigned int)value;
radeon_enable_interrupt(dev);
diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c
index 517cad8b6e3..a29acfe2f97 100644
--- a/drivers/char/drm/radeon_mem.c
+++ b/drivers/char/drm/radeon_mem.c
@@ -39,7 +39,7 @@
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
- DRMFILE filp)
+ struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
@@ -49,7 +49,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -66,7 +66,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -76,20 +76,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
out:
/* Our block is in the middle */
- p->filp = filp;
+ p->file_priv = file_priv;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, DRMFILE filp)
+ int align2, struct drm_file *file_priv)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
list_for_each(p, heap) {
int start = (p->start + mask) & ~mask;
- if (p->filp == 0 && start + size <= p->start + p->size)
- return split_block(p, start, size, filp);
+ if (p->file_priv == 0 && start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
}
return NULL;
@@ -108,12 +108,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
static void free_block(struct mem_block *p)
{
- p->filp = NULL;
+ p->file_priv = NULL;
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
- if (p->next->filp == 0) {
+ if (p->next->file_priv == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -121,7 +121,7 @@ static void free_block(struct mem_block *p)
drm_free(q, sizeof(*q), DRM_MEM_BUFS);
}
- if (p->prev->filp == 0) {
+ if (p->prev->file_priv == 0) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
@@ -137,28 +137,28 @@ static int init_heap(struct mem_block **heap, int start, int size)
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
if (!blocks)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
*heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
if (!*heap) {
drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
blocks->start = start;
blocks->size = size;
- blocks->filp = NULL;
+ blocks->file_priv = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
- (*heap)->filp = (DRMFILE) - 1;
+ (*heap)->file_priv = (struct drm_file *) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
-void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
+void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap)
{
struct mem_block *p;
@@ -166,15 +166,15 @@ void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
return;
list_for_each(p, heap) {
- if (p->filp == filp)
- p->filp = NULL;
+ if (p->file_priv == file_priv)
+ p->file_priv = NULL;
}
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
list_for_each(p, heap) {
- while (p->filp == 0 && p->next->filp == 0) {
+ while (p->file_priv == 0 && p->next->file_priv == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -217,98 +217,86 @@ static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
}
}
-int radeon_mem_alloc(DRM_IOCTL_ARGS)
+int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_alloc_t alloc;
+ drm_radeon_mem_alloc_t *alloc = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data,
- sizeof(alloc));
-
- heap = get_heap(dev_priv, alloc.region);
+ heap = get_heap(dev_priv, alloc->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
- if (alloc.alignment < 12)
- alloc.alignment = 12;
+ if (alloc->alignment < 12)
+ alloc->alignment = 12;
- block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+ block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
if (!block)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
- if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+ if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+ sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-int radeon_mem_free(DRM_IOCTL_ARGS)
+int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_free_t memfree;
+ drm_radeon_mem_free_t *memfree = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
- sizeof(memfree));
-
- heap = get_heap(dev_priv, memfree.region);
+ heap = get_heap(dev_priv, memfree->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- block = find_block(*heap, memfree.region_offset);
+ block = find_block(*heap, memfree->region_offset);
if (!block)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (block->filp != filp)
- return DRM_ERR(EPERM);
+ if (block->file_priv != file_priv)
+ return -EPERM;
free_block(block);
return 0;
}
-int radeon_mem_init_heap(DRM_IOCTL_ARGS)
+int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_init_heap_t initheap;
+ drm_radeon_mem_init_heap_t *initheap = data;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(initheap,
- (drm_radeon_mem_init_heap_t __user *) data,
- sizeof(initheap));
-
- heap = get_heap(dev_priv, initheap.region);
+ heap = get_heap(dev_priv, initheap->region);
if (!heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (*heap) {
DRM_ERROR("heap already initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- return init_heap(heap, initheap.start, initheap.size);
+ return init_heap(heap, initheap->start, initheap->size);
}
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 3ddf86f2abf..69c9f2febf4 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -39,7 +39,7 @@
static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file * file_priv,
u32 *offset)
{
u64 off = *offset;
@@ -71,7 +71,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
* magic offset we get from SETPARAM or calculated from fb_location
*/
if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
- radeon_priv = filp_priv->driver_priv;
+ radeon_priv = file_priv->driver_priv;
off += radeon_priv->radeon_fb_delta;
}
@@ -85,29 +85,29 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
*offset = off;
return 0;
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
int id, u32 *data)
{
switch (id) {
case RADEON_EMIT_PP_MISC:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_EMIT_PP_CNTL:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
DRM_ERROR("Invalid colour buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -117,20 +117,20 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXOFFSET_3:
case R200_EMIT_PP_TXOFFSET_4:
case R200_EMIT_PP_TXOFFSET_5:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[0])) {
DRM_ERROR("Invalid R200 texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_EMIT_PP_TXFILTER_0:
case RADEON_EMIT_PP_TXFILTER_1:
case RADEON_EMIT_PP_TXFILTER_2:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
DRM_ERROR("Invalid R100 texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -143,11 +143,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
int i;
for (i = 0; i < 5; i++) {
if (radeon_check_and_fixup_offset(dev_priv,
- filp_priv,
+ file_priv,
&data[i])) {
DRM_ERROR
("Invalid R200 cubic texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
break;
@@ -159,11 +159,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
int i;
for (i = 0; i < 5; i++) {
if (radeon_check_and_fixup_offset(dev_priv,
- filp_priv,
+ file_priv,
&data[i])) {
DRM_ERROR
("Invalid R100 cubic texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
}
@@ -256,7 +256,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
default:
DRM_ERROR("Unknown state packet ID %d\n", id);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -264,7 +264,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
dev_priv,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *
cmdbuf,
unsigned int *cmdsz)
@@ -277,12 +277,12 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
DRM_ERROR("Not a type 3 packet\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (4 * *cmdsz > cmdbuf->bufsz) {
DRM_ERROR("Packet size larger than size of data provided\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch(cmd[0] & 0xff00) {
@@ -307,7 +307,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
/* safe but r200 only */
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -317,7 +317,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if (count > 18) { /* 12 arrays max */
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* carefully check packet contents */
@@ -326,22 +326,25 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
i = 2;
while ((k < narrays) && (i < (count + 2))) {
i++; /* skip attribute field */
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
+ &cmd[i])) {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
if (k == narrays)
break;
/* have one more to process, they come in pairs */
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+ if (radeon_check_and_fixup_offset(dev_priv,
+ file_priv, &cmd[i]))
+ {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -351,33 +354,33 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_3D_RNDR_GEN_INDX_PRIM:
if (dev_priv->microcode_version != UCODE_R100) {
DRM_ERROR("Invalid 3d packet for r200-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) {
DRM_ERROR("Invalid rndr_gen_indx offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_CP_INDX_BUFFER:
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -389,9 +392,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
if (radeon_check_and_fixup_offset
- (dev_priv, filp_priv, &offset)) {
+ (dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid first packet offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
}
@@ -400,9 +403,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
if (radeon_check_and_fixup_offset
- (dev_priv, filp_priv, &offset)) {
+ (dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid second packet offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
}
@@ -410,7 +413,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
default:
DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -439,7 +442,7 @@ static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
/* Emit 1.1 state
*/
static int radeon_emit_state(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_context_regs_t * ctx,
drm_radeon_texture_regs_t * tex,
unsigned int dirty)
@@ -448,16 +451,16 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
DRM_DEBUG("dirty=0x%08x\n", dirty);
if (dirty & RADEON_UPLOAD_CONTEXT) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&ctx->rb3d_depthoffset)) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&ctx->rb3d_coloroffset)) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(14);
@@ -543,10 +546,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX0) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[0].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 0\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -563,10 +566,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX1) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[1].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 1\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -583,10 +586,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX2) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[2].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 2\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -608,7 +611,7 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
/* Emit 1.2 state
*/
static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_state_t * state)
{
RING_LOCALS;
@@ -621,7 +624,7 @@ static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
ADVANCE_RING();
}
- return radeon_emit_state(dev_priv, filp_priv, &state->context,
+ return radeon_emit_state(dev_priv, file_priv, &state->context,
state->tex, state->dirty);
}
@@ -1646,13 +1649,12 @@ static void radeon_cp_dispatch_indices(struct drm_device * dev,
#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
-static int radeon_cp_dispatch_texture(DRMFILE filp,
- struct drm_device * dev,
+static int radeon_cp_dispatch_texture(struct drm_device * dev,
+ struct drm_file *file_priv,
drm_radeon_texture_t * tex,
drm_radeon_tex_image_t * image)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
struct drm_buf *buf;
u32 format;
u32 *buffer;
@@ -1664,11 +1666,9 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
u32 offset;
RING_LOCALS;
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
DRM_ERROR("Invalid destination offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
@@ -1711,11 +1711,11 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
break;
default:
DRM_ERROR("invalid texture format %d\n", tex->format);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
spitch = blit_width >> 6;
if (spitch == 0 && image->height > 1)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
texpitch = tex->pitch;
if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
@@ -1760,8 +1760,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
if (!buf) {
DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
- return DRM_ERR(EFAULT);
- return DRM_ERR(EAGAIN);
+ return -EFAULT;
+ return -EAGAIN;
}
/* Dispatch the indirect buffer.
@@ -1774,7 +1774,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
do { \
if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
- return DRM_ERR(EFAULT); \
+ return -EFAULT; \
} \
} while(0)
@@ -1841,7 +1841,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
}
#undef RADEON_COPY_MT
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf->used = size;
offset = dev_priv->gart_buffers_offset + buf->offset;
BEGIN_RING(9);
@@ -1861,6 +1861,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
OUT_RING((image->width << 16) | height);
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
+ COMMIT_RING();
radeon_cp_discard_buffer(dev, buf);
@@ -1878,6 +1879,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
RADEON_FLUSH_CACHE();
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
+ COMMIT_RING();
+
return 0;
}
@@ -1929,7 +1932,8 @@ static void radeon_apply_surface_regs(int surf_index,
* not always be available.
*/
static int alloc_surface(drm_radeon_surface_alloc_t *new,
- drm_radeon_private_t *dev_priv, DRMFILE filp)
+ drm_radeon_private_t *dev_priv,
+ struct drm_file *file_priv)
{
struct radeon_virt_surface *s;
int i;
@@ -1959,7 +1963,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
/* find a virtual surface */
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
- if (dev_priv->virt_surfaces[i].filp == 0)
+ if (dev_priv->virt_surfaces[i].file_priv == 0)
break;
if (i == 2 * RADEON_MAX_SURFACES) {
return -1;
@@ -1977,7 +1981,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount++;
dev_priv->surfaces[i].lower = s->lower;
radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -1993,7 +1997,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount++;
dev_priv->surfaces[i].upper = s->upper;
radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -2009,7 +2013,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount = 1;
dev_priv->surfaces[i].lower = s->lower;
dev_priv->surfaces[i].upper = s->upper;
@@ -2023,7 +2027,8 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
return -1;
}
-static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
+static int free_surface(struct drm_file *file_priv,
+ drm_radeon_private_t * dev_priv,
int lower)
{
struct radeon_virt_surface *s;
@@ -2031,8 +2036,9 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
/* find the virtual surface */
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
s = &(dev_priv->virt_surfaces[i]);
- if (s->filp) {
- if ((lower == s->lower) && (filp == s->filp)) {
+ if (s->file_priv) {
+ if ((lower == s->lower) && (file_priv == s->file_priv))
+ {
if (dev_priv->surfaces[s->surface_index].
lower == s->lower)
dev_priv->surfaces[s->surface_index].
@@ -2048,7 +2054,7 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
refcount == 0)
dev_priv->surfaces[s->surface_index].
flags = 0;
- s->filp = NULL;
+ s->file_priv = NULL;
radeon_apply_surface_regs(s->surface_index,
dev_priv);
return 0;
@@ -2058,13 +2064,13 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
return 1;
}
-static void radeon_surfaces_release(DRMFILE filp,
+static void radeon_surfaces_release(struct drm_file *file_priv,
drm_radeon_private_t * dev_priv)
{
int i;
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
- if (dev_priv->virt_surfaces[i].filp == filp)
- free_surface(filp, dev_priv,
+ if (dev_priv->virt_surfaces[i].file_priv == file_priv)
+ free_surface(file_priv, dev_priv,
dev_priv->virt_surfaces[i].lower);
}
}
@@ -2072,61 +2078,48 @@ static void radeon_surfaces_release(DRMFILE filp,
/* ================================================================
* IOCTL functions
*/
-static int radeon_surface_alloc(DRM_IOCTL_ARGS)
+static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_alloc_t alloc;
+ drm_radeon_surface_alloc_t *alloc = data;
- DRM_COPY_FROM_USER_IOCTL(alloc,
- (drm_radeon_surface_alloc_t __user *) data,
- sizeof(alloc));
-
- if (alloc_surface(&alloc, dev_priv, filp) == -1)
- return DRM_ERR(EINVAL);
+ if (alloc_surface(alloc, dev_priv, file_priv) == -1)
+ return -EINVAL;
else
return 0;
}
-static int radeon_surface_free(DRM_IOCTL_ARGS)
+static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_free_t memfree;
-
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
- sizeof(memfree));
+ drm_radeon_surface_free_t *memfree = data;
- if (free_surface(filp, dev_priv, memfree.address))
- return DRM_ERR(EINVAL);
+ if (free_surface(file_priv, dev_priv, memfree->address))
+ return -EINVAL;
else
return 0;
}
-static int radeon_cp_clear(DRM_IOCTL_ARGS)
+static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_clear_t clear;
+ drm_radeon_clear_t *clear = data;
drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
- if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
+ if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
sarea_priv->nbox * sizeof(depth_boxes[0])))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
+ radeon_cp_dispatch_clear(dev, clear, depth_boxes);
COMMIT_RING();
return 0;
@@ -2162,13 +2155,12 @@ static int radeon_do_init_pageflip(struct drm_device * dev)
/* Swapping and flipping are different operations, need different ioctls.
* They can & should be intermixed to support multiple 3d windows.
*/
-static int radeon_cp_flip(DRM_IOCTL_ARGS)
+static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2181,14 +2173,13 @@ static int radeon_cp_flip(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_swap(DRM_IOCTL_ARGS)
+static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2202,64 +2193,57 @@ static int radeon_cp_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_vertex(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_vertex_t vertex;
+ drm_radeon_vertex_t *vertex = data;
drm_radeon_tcl_prim_t prim;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", vertex.prim);
- return DRM_ERR(EINVAL);
+ if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+ DRM_ERROR("buffer prim %d\n", vertex->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
/* Build up a prim_t record:
*/
- if (vertex.count) {
- buf->used = vertex.count; /* not used? */
+ if (vertex->count) {
+ buf->used = vertex->count; /* not used? */
if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, filp_priv,
+ if (radeon_emit_state(dev_priv, file_priv,
&sarea_priv->context_state,
sarea_priv->tex_state,
sarea_priv->dirty)) {
DRM_ERROR("radeon_emit_state failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2269,15 +2253,15 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
}
prim.start = 0;
- prim.finish = vertex.count; /* unused */
- prim.prim = vertex.prim;
- prim.numverts = vertex.count;
+ prim.finish = vertex->count; /* unused */
+ prim.prim = vertex->prim;
+ prim.numverts = vertex->count;
prim.vc_format = dev_priv->sarea_priv->vc_format;
radeon_cp_dispatch_vertex(dev, buf, &prim);
}
- if (vertex.discard) {
+ if (vertex->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2285,74 +2269,68 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_indices(DRM_IOCTL_ARGS)
+static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_indices_t elts;
+ drm_radeon_indices_t *elts = data;
drm_radeon_tcl_prim_t prim;
int count;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
- sizeof(elts));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
- DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
+ DRM_CURRENTPID, elts->idx, elts->start, elts->end,
+ elts->discard);
- if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+ if (elts->idx < 0 || elts->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- elts.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ elts->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", elts.prim);
- return DRM_ERR(EINVAL);
+ if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+ DRM_ERROR("buffer prim %d\n", elts->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[elts.idx];
+ buf = dma->buflist[elts->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", elts->idx);
+ return -EINVAL;
}
- count = (elts.end - elts.start) / sizeof(u16);
- elts.start -= RADEON_INDEX_PRIM_OFFSET;
+ count = (elts->end - elts->start) / sizeof(u16);
+ elts->start -= RADEON_INDEX_PRIM_OFFSET;
- if (elts.start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
- return DRM_ERR(EINVAL);
+ if (elts->start & 0x7) {
+ DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+ return -EINVAL;
}
- if (elts.start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
- return DRM_ERR(EINVAL);
+ if (elts->start < buf->used) {
+ DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+ return -EINVAL;
}
- buf->used = elts.end;
+ buf->used = elts->end;
if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, filp_priv,
+ if (radeon_emit_state(dev_priv, file_priv,
&sarea_priv->context_state,
sarea_priv->tex_state,
sarea_priv->dirty)) {
DRM_ERROR("radeon_emit_state failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2363,15 +2341,15 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
/* Build up a prim_t record:
*/
- prim.start = elts.start;
- prim.finish = elts.end;
- prim.prim = elts.prim;
+ prim.start = elts->start;
+ prim.finish = elts->end;
+ prim.prim = elts->prim;
prim.offset = 0; /* offset from start of dma buffers */
prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
prim.vc_format = dev_priv->sarea_priv->vc_format;
radeon_cp_dispatch_indices(dev, buf, &prim);
- if (elts.discard) {
+ if (elts->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2379,52 +2357,43 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_texture(DRM_IOCTL_ARGS)
+static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_texture_t tex;
+ drm_radeon_texture_t *tex = data;
drm_radeon_tex_image_t image;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
- sizeof(tex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (tex.image == NULL) {
+ if (tex->image == NULL) {
DRM_ERROR("null texture image!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (DRM_COPY_FROM_USER(&image,
- (drm_radeon_tex_image_t __user *) tex.image,
+ (drm_radeon_tex_image_t __user *) tex->image,
sizeof(image)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
+ ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
- COMMIT_RING();
return ret;
}
-static int radeon_cp_stipple(DRM_IOCTL_ARGS)
+static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_stipple_t stipple;
+ drm_radeon_stipple_t *stipple = data;
u32 mask[32];
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
- sizeof(stipple));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2434,52 +2403,48 @@ static int radeon_cp_stipple(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_indirect(DRM_IOCTL_ARGS)
+static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_indirect_t indirect;
+ drm_radeon_indirect_t *indirect = data;
RING_LOCALS;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(indirect,
- (drm_radeon_indirect_t __user *) data,
- sizeof(indirect));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
- indirect.idx, indirect.start, indirect.end, indirect.discard);
+ indirect->idx, indirect->start, indirect->end,
+ indirect->discard);
- if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+ if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- indirect.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ indirect->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- buf = dma->buflist[indirect.idx];
+ buf = dma->buflist[indirect->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+ return -EINVAL;
}
- if (indirect.start < buf->used) {
+ if (indirect->start < buf->used) {
DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect.start, buf->used);
- return DRM_ERR(EINVAL);
+ indirect->start, buf->used);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf->used = indirect.end;
+ buf->used = indirect->end;
/* Wait for the 3D stream to idle before the indirect buffer
* containing 2D acceleration commands is processed.
@@ -2494,8 +2459,8 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
* X server. This is insecure and is thus only available to
* privileged clients.
*/
- radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
- if (indirect.discard) {
+ radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
+ if (indirect->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2503,71 +2468,64 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_vertex2_t vertex;
+ drm_radeon_vertex2_t *vertex = data;
int i;
unsigned char laststate;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
- for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
+ for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
drm_radeon_prim_t prim;
drm_radeon_tcl_prim_t tclprim;
- if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
+ return -EFAULT;
if (prim.stateidx != laststate) {
drm_radeon_state_t state;
if (DRM_COPY_FROM_USER(&state,
- &vertex.state[prim.stateidx],
+ &vertex->state[prim.stateidx],
sizeof(state)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
+ if (radeon_emit_state2(dev_priv, file_priv, &state)) {
DRM_ERROR("radeon_emit_state2 failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
laststate = prim.stateidx;
@@ -2594,7 +2552,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
sarea_priv->nbox = 0;
}
- if (vertex.discard) {
+ if (vertex->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2603,7 +2561,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
}
static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_cmd_header_t header,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
@@ -2613,19 +2571,19 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
RING_LOCALS;
if (id >= RADEON_MAX_STATE_PACKETS)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
sz = packet[id].len;
reg = packet[id].start;
if (sz * sizeof(int) > cmdbuf->bufsz) {
DRM_ERROR("Packet size provided larger than data provided\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
+ if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) {
DRM_ERROR("Packet verification failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(sz + 1);
@@ -2713,7 +2671,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
if (sz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(5 + sz);
OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
@@ -2729,7 +2687,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
}
static int radeon_emit_packet3(struct drm_device * dev,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2739,7 +2697,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
DRM_DEBUG("\n");
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+ if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
cmdbuf, &cmdsz))) {
DRM_ERROR("Packet verification failed\n");
return ret;
@@ -2755,7 +2713,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
}
static int radeon_emit_packet3_cliprect(struct drm_device *dev,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
int orig_nbox)
{
@@ -2769,7 +2727,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
DRM_DEBUG("\n");
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+ if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
cmdbuf, &cmdsz))) {
DRM_ERROR("Packet verification failed\n");
return ret;
@@ -2781,7 +2739,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
do {
if (i < cmdbuf->nbox) {
if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* FIXME The second and subsequent times round
* this loop, send a WAIT_UNTIL_3D_IDLE before
* calling emit_clip_rect(). This fixes a
@@ -2839,62 +2797,54 @@ static int radeon_emit_wait(struct drm_device * dev, int flags)
ADVANCE_RING();
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
-static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
+static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf = NULL;
int idx;
- drm_radeon_kcmd_buffer_t cmdbuf;
+ drm_radeon_kcmd_buffer_t *cmdbuf = data;
drm_radeon_cmd_header_t header;
int orig_nbox, orig_bufsz;
char *kbuf = NULL;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf,
- (drm_radeon_cmd_buffer_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
- return DRM_ERR(EINVAL);
+ if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
+ return -EINVAL;
}
/* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
* races between checking values and using those values in other code,
* and simply to avoid a lot of function calls to copy in data.
*/
- orig_bufsz = cmdbuf.bufsz;
+ orig_bufsz = cmdbuf->bufsz;
if (orig_bufsz != 0) {
- kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
+ kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER);
if (kbuf == NULL)
- return DRM_ERR(ENOMEM);
- if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
- cmdbuf.bufsz)) {
+ return -ENOMEM;
+ if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf,
+ cmdbuf->bufsz)) {
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- cmdbuf.buf = kbuf;
+ cmdbuf->buf = kbuf;
}
- orig_nbox = cmdbuf.nbox;
+ orig_nbox = cmdbuf->nbox;
if (dev_priv->microcode_version == UCODE_R300) {
int temp;
- temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
+ temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
if (orig_bufsz != 0)
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
@@ -2903,17 +2853,17 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
}
/* microcode_version != r300 */
- while (cmdbuf.bufsz >= sizeof(header)) {
+ while (cmdbuf->bufsz >= sizeof(header)) {
- header.i = *(int *)cmdbuf.buf;
- cmdbuf.buf += sizeof(header);
- cmdbuf.bufsz -= sizeof(header);
+ header.i = *(int *)cmdbuf->buf;
+ cmdbuf->buf += sizeof(header);
+ cmdbuf->bufsz -= sizeof(header);
switch (header.header.cmd_type) {
case RADEON_CMD_PACKET:
DRM_DEBUG("RADEON_CMD_PACKET\n");
if (radeon_emit_packets
- (dev_priv, filp_priv, header, &cmdbuf)) {
+ (dev_priv, file_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_packets failed\n");
goto err;
}
@@ -2921,7 +2871,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_SCALARS:
DRM_DEBUG("RADEON_CMD_SCALARS\n");
- if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_scalars(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars failed\n");
goto err;
}
@@ -2929,7 +2879,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_VECTORS:
DRM_DEBUG("RADEON_CMD_VECTORS\n");
- if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_vectors(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_vectors failed\n");
goto err;
}
@@ -2945,9 +2895,10 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
}
buf = dma->buflist[idx];
- if (buf->filp != filp || buf->pending) {
+ if (buf->file_priv != file_priv || buf->pending) {
DRM_ERROR("bad buffer %p %p %d\n",
- buf->filp, filp, buf->pending);
+ buf->file_priv, file_priv,
+ buf->pending);
goto err;
}
@@ -2956,7 +2907,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_PACKET3:
DRM_DEBUG("RADEON_CMD_PACKET3\n");
- if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
+ if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
DRM_ERROR("radeon_emit_packet3 failed\n");
goto err;
}
@@ -2965,7 +2916,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_PACKET3_CLIP:
DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
if (radeon_emit_packet3_cliprect
- (dev, filp_priv, &cmdbuf, orig_nbox)) {
+ (dev, file_priv, cmdbuf, orig_nbox)) {
DRM_ERROR("radeon_emit_packet3_clip failed\n");
goto err;
}
@@ -2973,7 +2924,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_SCALARS2:
DRM_DEBUG("RADEON_CMD_SCALARS2\n");
- if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars2 failed\n");
goto err;
}
@@ -2988,7 +2939,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
break;
case RADEON_CMD_VECLINEAR:
DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
- if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_veclinear failed\n");
goto err;
}
@@ -2997,7 +2948,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,
- cmdbuf.buf - sizeof(header));
+ cmdbuf->buf - sizeof(header));
goto err;
}
}
@@ -3012,22 +2963,18 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
err:
if (orig_bufsz != 0)
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-static int radeon_cp_getparam(DRM_IOCTL_ARGS)
+static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_getparam_t param;
+ drm_radeon_getparam_t *param = data;
int value;
- DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case RADEON_PARAM_GART_BUFFER_OFFSET:
value = dev_priv->gart_buffers_offset;
break;
@@ -3074,7 +3021,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
break;
case RADEON_PARAM_SCRATCH_OFFSET:
if (!dev_priv->writeback_works)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
value = RADEON_SCRATCH_REG_OFFSET;
break;
case RADEON_PARAM_CARD_TYPE:
@@ -3089,43 +3036,37 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
value = radeon_vblank_crtc_get(dev);
break;
default:
- DRM_DEBUG("Invalid parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid parameter %d\n", param->param);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int radeon_cp_setparam(DRM_IOCTL_ARGS)
+static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
- drm_radeon_setparam_t sp;
+ drm_radeon_setparam_t *sp = data;
struct drm_radeon_driver_file_fields *radeon_priv;
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
- sizeof(sp));
-
- switch (sp.param) {
+ switch (sp->param) {
case RADEON_SETPARAM_FB_LOCATION:
- radeon_priv = filp_priv->driver_priv;
- radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+ radeon_priv = file_priv->driver_priv;
+ radeon_priv->radeon_fb_delta = dev_priv->fb_location -
+ sp->value;
break;
case RADEON_SETPARAM_SWITCH_TILING:
- if (sp.value == 0) {
+ if (sp->value == 0) {
DRM_DEBUG("color tiling disabled\n");
dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
dev_priv->sarea_priv->tiling_enabled = 0;
- } else if (sp.value == 1) {
+ } else if (sp->value == 1) {
DRM_DEBUG("color tiling enabled\n");
dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
@@ -3133,23 +3074,23 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
}
break;
case RADEON_SETPARAM_PCIGART_LOCATION:
- dev_priv->pcigart_offset = sp.value;
+ dev_priv->pcigart_offset = sp->value;
dev_priv->pcigart_offset_set = 1;
break;
case RADEON_SETPARAM_NEW_MEMMAP:
- dev_priv->new_memmap = sp.value;
+ dev_priv->new_memmap = sp->value;
break;
case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
- dev_priv->gart_info.table_size = sp.value;
+ dev_priv->gart_info.table_size = sp->value;
if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
break;
case RADEON_SETPARAM_VBLANK_CRTC:
- return radeon_vblank_crtc_set(dev, sp.value);
+ return radeon_vblank_crtc_set(dev, sp->value);
break;
default:
- DRM_DEBUG("Invalid parameter %d\n", sp.param);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid parameter %d\n", sp->param);
+ return -EINVAL;
}
return 0;
@@ -3162,14 +3103,14 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
*
* DRM infrastructure takes care of reclaiming dma buffers.
*/
-void radeon_driver_preclose(struct drm_device *dev, DRMFILE filp)
+void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
dev_priv->page_flipping = 0;
- radeon_mem_release(filp, dev_priv->gart_heap);
- radeon_mem_release(filp, dev_priv->fb_heap);
- radeon_surfaces_release(filp, dev_priv);
+ radeon_mem_release(file_priv, dev_priv->gart_heap);
+ radeon_mem_release(file_priv, dev_priv->fb_heap);
+ radeon_surfaces_release(file_priv, dev_priv);
}
}
@@ -3186,7 +3127,7 @@ void radeon_driver_lastclose(struct drm_device *dev)
radeon_do_release(dev);
}
-int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
+int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_radeon_driver_file_fields *radeon_priv;
@@ -3199,7 +3140,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
if (!radeon_priv)
return -ENOMEM;
- filp_priv->driver_priv = radeon_priv;
+ file_priv->driver_priv = radeon_priv;
if (dev_priv)
radeon_priv->radeon_fb_delta = dev_priv->fb_location;
@@ -3208,42 +3149,42 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
return 0;
}
-void radeon_driver_postclose(struct drm_device *dev, struct drm_file *filp_priv)
+void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_radeon_driver_file_fields *radeon_priv =
- filp_priv->driver_priv;
+ file_priv->driver_priv;
drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
}
-drm_ioctl_desc_t radeon_ioctls[] = {
- [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
+struct drm_ioctl_desc radeon_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH)
};
int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index 18c7235f6b7..59484d56b33 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -60,7 +60,7 @@ savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x, threshold=0x%08x\n", status, threshold);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -81,7 +81,7 @@ savage_bci_wait_fifo_s3d(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -102,7 +102,7 @@ savage_bci_wait_fifo_s4(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/*
@@ -136,7 +136,7 @@ savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e)
DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -158,7 +158,7 @@ savage_bci_wait_event_reg(drm_savage_private_t * dev_priv, uint16_t e)
DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -301,7 +301,7 @@ static int savage_dma_init(drm_savage_private_t * dev_priv)
dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *
dev_priv->nr_dma_pages, DRM_MEM_DRIVER);
if (dev_priv->dma_pages == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
@@ -541,7 +541,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_savage_private_t));
dev->dev_private = (void *)dev_priv;
@@ -682,16 +682,16 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (init->fb_bpp != 16 && init->fb_bpp != 32) {
DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->depth_bpp != 16 && init->depth_bpp != 32) {
DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->dma_type != SAVAGE_DMA_AGP &&
init->dma_type != SAVAGE_DMA_PCI) {
DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cob_size = init->cob_size;
@@ -715,14 +715,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->status_offset != 0) {
dev_priv->status = drm_core_findmap(dev, init->status_offset);
if (!dev_priv->status) {
DRM_ERROR("could not find shadow status region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->status = NULL;
@@ -734,13 +734,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev->agp_buffer_map) {
DRM_ERROR("could not find DMA buffer region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev->agp_buffer_map, dev);
if (!dev->agp_buffer_map) {
DRM_ERROR("failed to ioremap DMA buffer region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
}
if (init->agp_textures_offset) {
@@ -749,7 +749,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->agp_textures) {
DRM_ERROR("could not find agp texture region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->agp_textures = NULL;
@@ -760,39 +760,39 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
DRM_ERROR("command DMA not supported on "
"Savage3D/MX/IX.\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev->dma && dev->dma->buflist) {
DRM_ERROR("command and vertex DMA not supported "
"at the same time.\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
if (!dev_priv->cmd_dma) {
DRM_ERROR("could not find command DMA region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
if (dev_priv->cmd_dma->type != _DRM_AGP) {
DRM_ERROR("AGP command DMA region is not a "
"_DRM_AGP map!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev_priv->cmd_dma, dev);
if (!dev_priv->cmd_dma->handle) {
DRM_ERROR("failed to ioremap command "
"DMA region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
} else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
DRM_ERROR("PCI command DMA region is not a "
"_DRM_CONSISTENT map!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->cmd_dma = NULL;
@@ -809,7 +809,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->fake_dma.handle) {
DRM_ERROR("could not allocate faked DMA buffer!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->cmd_dma = &dev_priv->fake_dma;
dev_priv->dma_flush = savage_fake_dma_flush;
@@ -886,13 +886,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (savage_freelist_init(dev) < 0) {
DRM_ERROR("could not initialize freelist\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (savage_dma_init(dev_priv) < 0) {
DRM_ERROR("could not initialize command DMA\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
return 0;
@@ -928,51 +928,41 @@ static int savage_do_cleanup_bci(struct drm_device * dev)
return 0;
}
-static int savage_bci_init(DRM_IOCTL_ARGS)
+static int savage_bci_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_savage_init_t init;
+ drm_savage_init_t *init = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case SAVAGE_INIT_BCI:
- return savage_do_init_bci(dev, &init);
+ return savage_do_init_bci(dev, init);
case SAVAGE_CLEANUP_BCI:
return savage_do_cleanup_bci(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-static int savage_bci_event_emit(DRM_IOCTL_ARGS)
+static int savage_bci_event_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_emit_t event;
+ drm_savage_event_emit_t *event = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *) data,
- sizeof(event));
+ event->count = savage_bci_emit_event(dev_priv, event->flags);
+ event->count |= dev_priv->event_wrap << 16;
- event.count = savage_bci_emit_event(dev_priv, event.flags);
- event.count |= dev_priv->event_wrap << 16;
- DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data,
- event, sizeof(event));
return 0;
}
-static int savage_bci_event_wait(DRM_IOCTL_ARGS)
+static int savage_bci_event_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_wait_t event;
+ drm_savage_event_wait_t *event = data;
unsigned int event_e, hw_e;
unsigned int event_w, hw_w;
@@ -990,8 +980,8 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
if (hw_e > dev_priv->event_counter)
hw_w--; /* hardware hasn't passed the last wrap yet */
- event_e = event.count & 0xffff;
- event_w = event.count >> 16;
+ event_e = event->count & 0xffff;
+ event_w = event->count >> 16;
/* Don't need to wait if
* - event counter wrapped since the event was emitted or
@@ -1007,7 +997,9 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct drm_dma *d)
+static int savage_bci_get_buffers(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct drm_dma *d)
{
struct drm_buf *buf;
int i;
@@ -1015,61 +1007,56 @@ static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct d
for (i = d->granted_count; i < d->request_count; i++) {
buf = savage_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i],
&buf->idx, sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i],
&buf->total, sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int savage_bci_buffers(DRM_IOCTL_ARGS)
+int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
- struct drm_dma d;
+ struct drm_dma *d = data;
int ret = 0;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, (struct drm_dma __user *) data, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = savage_bci_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = savage_bci_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL((struct drm_dma __user *) data, d, sizeof(d));
-
return ret;
}
-void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
+void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
drm_savage_private_t *dev_priv = dev->dev_private;
@@ -1088,7 +1075,7 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
struct drm_buf *buf = dma->buflist[i];
drm_savage_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv &&
+ if (buf->file_priv == file_priv && buf_priv &&
buf_priv->next == NULL && buf_priv->prev == NULL) {
uint16_t event;
DRM_DEBUG("reclaimed from client\n");
@@ -1098,14 +1085,14 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
}
}
- drm_core_reclaim_buffers(dev, filp);
+ drm_core_reclaim_buffers(dev, file_priv);
}
-drm_ioctl_desc_t savage_ioctls[] = {
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, DRM_AUTH},
+struct drm_ioctl_desc savage_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH),
};
int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls);
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
index 5fd54de4280..df2aac6636f 100644
--- a/drivers/char/drm/savage_drv.h
+++ b/drivers/char/drm/savage_drv.h
@@ -104,7 +104,7 @@ enum savage_family {
S3_LAST
};
-extern drm_ioctl_desc_t savage_ioctls[];
+extern struct drm_ioctl_desc savage_ioctls[];
extern int savage_max_ioctl;
#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
@@ -197,8 +197,8 @@ typedef struct drm_savage_private {
} drm_savage_private_t;
/* ioctls */
-extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
-extern int savage_bci_buffers(DRM_IOCTL_ARGS);
+extern int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
/* BCI functions */
extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -212,7 +212,8 @@ extern int savage_driver_load(struct drm_device *dev, unsigned long chipset);
extern int savage_driver_firstopen(struct drm_device *dev);
extern void savage_driver_lastclose(struct drm_device *dev);
extern int savage_driver_unload(struct drm_device *dev);
-extern void savage_reclaim_buffers(struct drm_device * dev, DRMFILE filp);
+extern void savage_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *file_priv);
/* state functions */
extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
index 77497841478..bf8e0e10fe2 100644
--- a/drivers/char/drm/savage_state.c
+++ b/drivers/char/drm/savage_state.c
@@ -83,7 +83,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
{
if ((addr & 6) != 2) { /* reserved bits */
DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!(addr & 1)) { /* local */
addr &= ~7;
@@ -92,13 +92,13 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
DRM_ERROR
("bad texAddr%d %08x (local addr out of range)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else { /* AGP */
if (!dev_priv->agp_textures) {
DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
addr &= ~7;
if (addr < dev_priv->agp_textures->offset ||
@@ -107,7 +107,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
DRM_ERROR
("bad texAddr%d %08x (AGP addr out of range)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
return 0;
@@ -133,7 +133,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,
start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
start, start + count - 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
@@ -165,7 +165,7 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv,
start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {
DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
start, start + count - 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
@@ -289,7 +289,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
if (!dmabuf) {
DRM_ERROR("called without dma buffers!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!n)
@@ -303,7 +303,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -312,18 +312,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
DRM_ERROR
("wrong number of vertices %u in TRIFAN/STRIP\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip != 0) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -331,18 +331,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (reorder) {
DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (start + n > dmabuf->total / 32) {
DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
start, start + n - 1, dmabuf->total / 32);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Vertex DMA doesn't work with command DMA at the same time,
@@ -440,7 +440,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -449,24 +449,24 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
DRM_ERROR
("wrong number of vertices %u in TRIFAN/STRIP\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip > SAVAGE_SKIP_ALL_S3D) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 8; /* full vertex */
} else {
if (skip > SAVAGE_SKIP_ALL_S4) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 10; /* full vertex */
}
@@ -478,13 +478,13 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
if (vtx_size > vb_stride) {
DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
vtx_size, vb_stride);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (start + n > vb_size / (vb_stride * 4)) {
DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
start, start + n - 1, vb_size / (vb_stride * 4));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
prim <<= 25;
@@ -547,7 +547,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (!dmabuf) {
DRM_ERROR("called without dma buffers!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!n)
@@ -560,7 +560,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -568,18 +568,18 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (n < 3) {
DRM_ERROR
("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip != 0) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -587,11 +587,11 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (reorder) {
DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -628,7 +628,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (idx[i] > dmabuf->total / 32) {
DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
i, idx[i], dmabuf->total / 32);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -698,7 +698,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -706,24 +706,24 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (n < 3) {
DRM_ERROR
("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip > SAVAGE_SKIP_ALL_S3D) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 8; /* full vertex */
} else {
if (skip > SAVAGE_SKIP_ALL_S4) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 10; /* full vertex */
}
@@ -735,7 +735,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (vtx_size > vb_stride) {
DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
vtx_size, vb_stride);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
prim <<= 25;
@@ -748,7 +748,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (idx[i] > vb_size / (vb_stride * 4)) {
DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
i, idx[i], vb_size / (vb_stride * 4));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -942,7 +942,7 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
DRM_ERROR("IMPLEMENTATION ERROR: "
"non-drawing-command %d\n",
cmd_header.cmd.cmd);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (ret != 0)
@@ -953,13 +953,12 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
return 0;
}
-int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *dmabuf;
- drm_savage_cmdbuf_t cmdbuf;
+ drm_savage_cmdbuf_t *cmdbuf = data;
drm_savage_cmd_header_t *kcmd_addr = NULL;
drm_savage_cmd_header_t *first_draw_cmd;
unsigned int *kvb_addr = NULL;
@@ -969,19 +968,16 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dma && dma->buflist) {
- if (cmdbuf.dma_idx > dma->buf_count) {
+ if (cmdbuf->dma_idx > dma->buf_count) {
DRM_ERROR
("vertex buffer index %u out of range (0-%u)\n",
- cmdbuf.dma_idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ cmdbuf->dma_idx, dma->buf_count - 1);
+ return -EINVAL;
}
- dmabuf = dma->buflist[cmdbuf.dma_idx];
+ dmabuf = dma->buflist[cmdbuf->dma_idx];
} else {
dmabuf = NULL;
}
@@ -991,47 +987,47 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
* COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
* for locking on FreeBSD.
*/
- if (cmdbuf.size) {
- kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
+ if (cmdbuf->size) {
+ kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER);
if (kcmd_addr == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
- if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
- cmdbuf.size * 8))
+ if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr,
+ cmdbuf->size * 8))
{
- drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
- return DRM_ERR(EFAULT);
+ drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+ return -EFAULT;
}
- cmdbuf.cmd_addr = kcmd_addr;
+ cmdbuf->cmd_addr = kcmd_addr;
}
- if (cmdbuf.vb_size) {
- kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER);
+ if (cmdbuf->vb_size) {
+ kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER);
if (kvb_addr == NULL) {
- ret = DRM_ERR(ENOMEM);
+ ret = -ENOMEM;
goto done;
}
- if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr,
- cmdbuf.vb_size)) {
- ret = DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr,
+ cmdbuf->vb_size)) {
+ ret = -EFAULT;
goto done;
}
- cmdbuf.vb_addr = kvb_addr;
+ cmdbuf->vb_addr = kvb_addr;
}
- if (cmdbuf.nbox) {
- kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(struct drm_clip_rect),
+ if (cmdbuf->nbox) {
+ kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
if (kbox_addr == NULL) {
- ret = DRM_ERR(ENOMEM);
+ ret = -ENOMEM;
goto done;
}
- if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,
- cmdbuf.nbox * sizeof(struct drm_clip_rect))) {
- ret = DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr,
+ cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
+ ret = -EFAULT;
goto done;
}
- cmdbuf.box_addr = kbox_addr;
+ cmdbuf->box_addr = kbox_addr;
}
/* Make sure writes to DMA buffers are finished before sending
@@ -1044,10 +1040,10 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
i = 0;
first_draw_cmd = NULL;
- while (i < cmdbuf.size) {
+ while (i < cmdbuf->size) {
drm_savage_cmd_header_t cmd_header;
- cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr;
- cmdbuf.cmd_addr++;
+ cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr;
+ cmdbuf->cmd_addr++;
i++;
/* Group drawing commands with same state to minimize
@@ -1057,28 +1053,28 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
case SAVAGE_CMD_DMA_IDX:
case SAVAGE_CMD_VB_IDX:
j = (cmd_header.idx.count + 3) / 4;
- if (i + j > cmdbuf.size) {
+ if (i + j > cmdbuf->size) {
DRM_ERROR("indexed drawing command extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* fall through */
case SAVAGE_CMD_DMA_PRIM:
case SAVAGE_CMD_VB_PRIM:
if (!first_draw_cmd)
- first_draw_cmd = cmdbuf.cmd_addr - 1;
- cmdbuf.cmd_addr += j;
+ first_draw_cmd = cmdbuf->cmd_addr - 1;
+ cmdbuf->cmd_addr += j;
i += j;
break;
default:
if (first_draw_cmd) {
ret = savage_dispatch_draw(
dev_priv, first_draw_cmd,
- cmdbuf.cmd_addr - 1,
- dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size,
- cmdbuf.vb_stride,
- cmdbuf.nbox, cmdbuf.box_addr);
+ cmdbuf->cmd_addr - 1,
+ dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size,
+ cmdbuf->vb_stride,
+ cmdbuf->nbox, cmdbuf->box_addr);
if (ret != 0)
return ret;
first_draw_cmd = NULL;
@@ -1090,40 +1086,42 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
switch (cmd_header.cmd.cmd) {
case SAVAGE_CMD_STATE:
j = (cmd_header.state.count + 1) / 2;
- if (i + j > cmdbuf.size) {
+ if (i + j > cmdbuf->size) {
DRM_ERROR("command SAVAGE_CMD_STATE extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
ret = savage_dispatch_state(dev_priv, &cmd_header,
- (const uint32_t *)cmdbuf.cmd_addr);
- cmdbuf.cmd_addr += j;
+ (const uint32_t *)cmdbuf->cmd_addr);
+ cmdbuf->cmd_addr += j;
i += j;
break;
case SAVAGE_CMD_CLEAR:
- if (i + 1 > cmdbuf.size) {
+ if (i + 1 > cmdbuf->size) {
DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
ret = savage_dispatch_clear(dev_priv, &cmd_header,
- cmdbuf.cmd_addr,
- cmdbuf.nbox, cmdbuf.box_addr);
- cmdbuf.cmd_addr++;
+ cmdbuf->cmd_addr,
+ cmdbuf->nbox,
+ cmdbuf->box_addr);
+ cmdbuf->cmd_addr++;
i++;
break;
case SAVAGE_CMD_SWAP:
- ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox,
- cmdbuf.box_addr);
+ ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox,
+ cmdbuf->box_addr);
break;
default:
- DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
+ DRM_ERROR("invalid command 0x%x\n",
+ cmd_header.cmd.cmd);
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
@@ -1135,9 +1133,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
if (first_draw_cmd) {
ret = savage_dispatch_draw (
- dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf,
- cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride,
- cmdbuf.nbox, cmdbuf.box_addr);
+ dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf,
+ cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride,
+ cmdbuf->nbox, cmdbuf->box_addr);
if (ret != 0) {
DMA_FLUSH();
goto done;
@@ -1146,7 +1144,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
DMA_FLUSH();
- if (dmabuf && cmdbuf.discard) {
+ if (dmabuf && cmdbuf->discard) {
drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
uint16_t event;
event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
@@ -1156,9 +1154,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
done:
/* If we didn't need to allocate them, these'll be NULL */
- drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
- drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);
- drm_free(kbox_addr, cmdbuf.nbox * sizeof(struct drm_clip_rect),
+ drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+ drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER);
+ drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
return ret;
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 1912f585705..7dacc64e9b5 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -42,7 +42,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
dev_priv->chipset = chipset;
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
index 5630df87435..ef940bad63f 100644
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -63,10 +63,11 @@ typedef struct drm_sis_private {
} drm_sis_private_t;
extern int sis_idle(struct drm_device *dev);
-extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void sis_reclaim_buffers_locked(struct drm_device *dev,
+ struct drm_file *file_priv);
extern void sis_lastclose(struct drm_device *dev);
-extern drm_ioctl_desc_t sis_ioctls[];
+extern struct drm_ioctl_desc sis_ioctls[];
extern int sis_max_ioctl;
#endif
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index 441bbdbf151..8c66838ff51 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -82,15 +82,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
#endif /* CONFIG_FB_SIS */
-static int sis_fb_init(DRM_IOCTL_ARGS)
+static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_fb_t fb;
+ drm_sis_fb_t *fb = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
-
mutex_lock(&dev->struct_mutex);
#if defined(CONFIG_FB_SIS)
{
@@ -105,7 +102,7 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
}
#else
ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
- fb.size >> SIS_MM_ALIGN_SHIFT);
+ fb->size >> SIS_MM_ALIGN_SHIFT);
#endif
if (ret) {
@@ -115,98 +112,87 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
}
dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb.offset;
+ dev_priv->vram_offset = fb->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+ DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
return 0;
}
-static int sis_drm_alloc(struct drm_device *dev, struct drm_file * priv,
- unsigned long data, int pool)
+static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv,
+ void *data, int pool)
{
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
- drm_sis_mem_t mem;
+ drm_sis_mem_t *mem = data;
int retval = 0;
struct drm_memblock_item *item;
- DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
if (0 == ((pool == 0) ? dev_priv->vram_initialized :
dev_priv->agp_initialized)) {
DRM_ERROR
("Attempt to allocate from uninitialized memory manager.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
- item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
- (unsigned long)priv);
+ mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0,
+ (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
if (item) {
- mem.offset = ((pool == 0) ?
+ mem->offset = ((pool == 0) ?
dev_priv->vram_offset : dev_priv->agp_offset) +
(item->mm->
offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
- mem.free = item->user_hash.key;
- mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
+ mem->free = item->user_hash.key;
+ mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
} else {
- mem.offset = 0;
- mem.size = 0;
- mem.free = 0;
- retval = DRM_ERR(ENOMEM);
+ mem->offset = 0;
+ mem->size = 0;
+ mem->free = 0;
+ retval = -ENOMEM;
}
- DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
-
- DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
- mem.offset);
+ DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size,
+ mem->offset);
return retval;
}
-static int sis_drm_free(DRM_IOCTL_ARGS)
+static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t mem;
+ drm_sis_mem_t *mem = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
- sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
- ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+ ret = drm_sman_free_key(&dev_priv->sman, mem->free);
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("free = 0x%lx\n", mem.free);
+ DRM_DEBUG("free = 0x%lx\n", mem->free);
return ret;
}
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static int sis_fb_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+ return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
}
-static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_agp_t agp;
+ drm_sis_agp_t *agp = data;
int ret;
dev_priv = dev->dev_private;
- DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
- sizeof(agp));
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
- agp.size >> SIS_MM_ALIGN_SHIFT);
+ agp->size >> SIS_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
@@ -215,18 +201,18 @@ static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
}
dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp.offset;
+ dev_priv->agp_offset = agp->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+ DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
return 0;
}
-static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+ return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
}
static drm_local_map_t *sis_reg_init(struct drm_device *dev)
@@ -314,13 +300,13 @@ void sis_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void sis_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
drm_sis_private_t *dev_priv = dev->dev_private;
- struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
- if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
mutex_unlock(&dev->struct_mutex);
return;
}
@@ -329,20 +315,18 @@ void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
dev->driver->dma_quiescent(dev);
}
- drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
return;
}
-drm_ioctl_desc_t sis_ioctls[] = {
- [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
- {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
- {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+struct drm_ioctl_desc sis_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
};
int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 7ff2b623c2d..75d6b748c2c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -175,24 +175,24 @@ static int via_initialize(struct drm_device * dev,
{
if (!dev_priv || !dev_priv->mmio) {
DRM_ERROR("via_dma_init called before via_map_init\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (dev_priv->ring.virtual_start != NULL) {
DRM_ERROR("%s called again without calling cleanup\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (!dev->agp || !dev->agp->base) {
DRM_ERROR("%s called with no agp memory available\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (dev_priv->chipset == VIA_DX9_0) {
DRM_ERROR("AGP DMA is not supported on this chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring.map.offset = dev->agp->base + init->offset;
@@ -207,7 +207,7 @@ static int via_initialize(struct drm_device * dev,
via_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -227,35 +227,31 @@ static int via_initialize(struct drm_device * dev,
return 0;
}
-static int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_dma_init_t init;
+ drm_via_dma_init_t *init = data;
int retcode = 0;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case VIA_INIT_DMA:
if (!DRM_SUSER(DRM_CURPROC))
- retcode = DRM_ERR(EPERM);
+ retcode = -EPERM;
else
- retcode = via_initialize(dev, dev_priv, &init);
+ retcode = via_initialize(dev, dev_priv, init);
break;
case VIA_CLEANUP_DMA:
if (!DRM_SUSER(DRM_CURPROC))
- retcode = DRM_ERR(EPERM);
+ retcode = -EPERM;
else
retcode = via_dma_cleanup(dev);
break;
case VIA_DMA_INITIALIZED:
retcode = (dev_priv->ring.virtual_start != NULL) ?
- 0 : DRM_ERR(EFAULT);
+ 0 : -EFAULT;
break;
default:
- retcode = DRM_ERR(EINVAL);
+ retcode = -EINVAL;
break;
}
@@ -273,15 +269,15 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
if (dev_priv->ring.virtual_start == NULL) {
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (cmd->size > VIA_PCI_BUF_SIZE) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/*
* Running this function on AGP memory is dead slow. Therefore
@@ -297,7 +293,7 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
if (vb == NULL) {
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
}
memcpy(vb, dev_priv->pci_buf, cmd->size);
@@ -321,34 +317,30 @@ int via_driver_dma_quiescent(struct drm_device * dev)
drm_via_private_t *dev_priv = dev->dev_private;
if (!via_wait_idle(dev_priv)) {
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
return 0;
}
-static int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return via_driver_dma_quiescent(dev);
}
-static int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+ DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+ cmdbuf->size);
- ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
@@ -363,10 +355,10 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
int ret;
if (cmd->size > VIA_PCI_BUF_SIZE) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if ((ret =
via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
@@ -380,21 +372,17 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
return ret;
}
-static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
+ DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+ cmdbuf->size);
- DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
- cmdbuf.size);
-
- ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
@@ -653,80 +641,74 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
* User interface to the space and lag functions.
*/
-static int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuf_size_t d_siz;
+ drm_via_cmdbuf_size_t *d_siz = data;
int ret = 0;
uint32_t tmp_size, count;
drm_via_private_t *dev_priv;
DRM_DEBUG("via cmdbuf_size\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
dev_priv = (drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start == NULL) {
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data,
- sizeof(d_siz));
-
count = 1000000;
- tmp_size = d_siz.size;
- switch (d_siz.func) {
+ tmp_size = d_siz->size;
+ switch (d_siz->func) {
case VIA_CMDBUF_SPACE:
- while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size)
+ while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
- ret = DRM_ERR(EAGAIN);
+ ret = -EAGAIN;
}
break;
case VIA_CMDBUF_LAG:
- while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size)
+ while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
- ret = DRM_ERR(EAGAIN);
+ ret = -EAGAIN;
}
break;
default:
- ret = DRM_ERR(EFAULT);
+ ret = -EFAULT;
}
- d_siz.size = tmp_size;
+ d_siz->size = tmp_size;
- DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz,
- sizeof(d_siz));
return ret;
}
-drm_ioctl_desc_t via_ioctls[] = {
- [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH}
+struct drm_ioctl_desc via_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
};
int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 3dd1ed3d1bf..c6fd16f3cb4 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -237,7 +237,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
first_pfn + 1;
if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
down_read(&current->mm->mmap_sem);
ret = get_user_pages(current, current->mm,
@@ -251,7 +251,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
if (ret < 0)
return ret;
vsg->state = dr_via_pages_locked;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vsg->state = dr_via_pages_locked;
DRM_DEBUG("DMA pages locked\n");
@@ -274,13 +274,13 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
vsg->descriptors_per_page;
if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
vsg->state = dr_via_desc_pages_alloc;
for (i=0; i<vsg->num_desc_pages; ++i) {
if (NULL == (vsg->desc_pages[i] =
(drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages,
vsg->num_desc);
@@ -593,7 +593,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->num_lines <= 0 || xfer->line_length <= 0) {
DRM_ERROR("Zero size bitblt.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -606,7 +606,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
DRM_ERROR("Too large system memory stride. Stride: %d, "
"Length: %d\n", xfer->mem_stride, xfer->line_length);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if ((xfer->mem_stride == xfer->line_length) &&
@@ -624,7 +624,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
DRM_ERROR("Too large PCI DMA bitblt.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -635,7 +635,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->mem_stride < xfer->line_length ||
abs(xfer->fb_stride) < xfer->line_length) {
DRM_ERROR("Invalid frame-buffer / memory stride.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -648,7 +648,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
#else
if ((((unsigned long)xfer->mem_addr & 15) ||
@@ -656,7 +656,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
((xfer->num_lines > 1) &&
((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
#endif
@@ -696,7 +696,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
if (ret) {
- return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret;
+ return (-EINTR == ret) ? -EAGAIN : ret;
}
spin_lock_irqsave(&blitq->blit_lock, irqsave);
@@ -740,7 +740,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
if (dev_priv == NULL) {
DRM_ERROR("Called without initialization.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
engine = (xfer->to_fb) ? 0 : 1;
@@ -750,7 +750,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
}
if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
via_dmablit_release_slot(blitq);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) {
via_dmablit_release_slot(blitq);
@@ -781,21 +781,18 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
*/
int
-via_dma_blit_sync( DRM_IOCTL_ARGS )
+via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv )
{
- drm_via_blitsync_t sync;
+ drm_via_blitsync_t *sync = data;
int err;
- DRM_DEVICE;
- DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync));
-
- if (sync.engine >= VIA_NUM_BLIT_ENGINES)
- return DRM_ERR(EINVAL);
+ if (sync->engine >= VIA_NUM_BLIT_ENGINES)
+ return -EINVAL;
- err = via_dmablit_sync(dev, sync.sync_handle, sync.engine);
+ err = via_dmablit_sync(dev, sync->sync_handle, sync->engine);
- if (DRM_ERR(EINTR) == err)
- err = DRM_ERR(EAGAIN);
+ if (-EINTR == err)
+ err = -EAGAIN;
return err;
}
@@ -808,17 +805,12 @@ via_dma_blit_sync( DRM_IOCTL_ARGS )
*/
int
-via_dma_blit( DRM_IOCTL_ARGS )
+via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv )
{
- drm_via_dmablit_t xfer;
+ drm_via_dmablit_t *xfer = data;
int err;
- DRM_DEVICE;
-
- DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer));
-
- err = via_dmablit(dev, &xfer);
- DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer));
+ err = via_dmablit(dev, xfer);
return err;
}
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 576711564a1..2daae81874c 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -110,18 +110,18 @@ enum via_family {
#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)
#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)
-extern drm_ioctl_desc_t via_ioctls[];
+extern struct drm_ioctl_desc via_ioctls[];
extern int via_max_ioctl;
-extern int via_fb_init(DRM_IOCTL_ARGS);
-extern int via_mem_alloc(DRM_IOCTL_ARGS);
-extern int via_mem_free(DRM_IOCTL_ARGS);
-extern int via_agp_init(DRM_IOCTL_ARGS);
-extern int via_map_init(DRM_IOCTL_ARGS);
-extern int via_decoder_futex(DRM_IOCTL_ARGS);
-extern int via_wait_irq(DRM_IOCTL_ARGS);
-extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
-extern int via_dma_blit( DRM_IOCTL_ARGS );
+extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv );
+extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv );
extern int via_driver_load(struct drm_device *dev, unsigned long chipset);
extern int via_driver_unload(struct drm_device *dev);
@@ -144,7 +144,7 @@ extern void via_init_futex(drm_via_private_t * dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
-extern void via_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
extern void via_lastclose(struct drm_device *dev);
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index 8dc99b5fbab..9c1d52bc92d 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -205,13 +205,13 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (irq >= drm_via_irq_num) {
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
irq);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
real_irq = dev_priv->irq_map[irq];
@@ -219,7 +219,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
if (real_irq < 0) {
DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
__FUNCTION__, irq);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
masks = dev_priv->irq_masks;
@@ -331,11 +331,9 @@ void via_driver_irq_uninstall(struct drm_device * dev)
}
}
-int via_wait_irq(DRM_IOCTL_ARGS)
+int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_irqwait_t __user *argp = (void __user *)data;
- drm_via_irqwait_t irqwait;
+ drm_via_irqwait_t *irqwait = data;
struct timeval now;
int ret = 0;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -343,42 +341,39 @@ int via_wait_irq(DRM_IOCTL_ARGS)
int force_sequence;
if (!dev->irq)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
- DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
- if (irqwait.request.irq >= dev_priv->num_irqs) {
+ if (irqwait->request.irq >= dev_priv->num_irqs) {
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
- irqwait.request.irq);
- return DRM_ERR(EINVAL);
+ irqwait->request.irq);
+ return -EINVAL;
}
- cur_irq += irqwait.request.irq;
+ cur_irq += irqwait->request.irq;
- switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+ switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
case VIA_IRQ_RELATIVE:
- irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
- irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case VIA_IRQ_ABSOLUTE:
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+ if (irqwait->request.type & VIA_IRQ_SIGNAL) {
DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
__FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+ force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
- ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
- &irqwait.request.sequence);
+ ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
+ &irqwait->request.sequence);
do_gettimeofday(&now);
- irqwait.reply.tval_sec = now.tv_sec;
- irqwait.reply.tval_usec = now.tv_usec;
-
- DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+ irqwait->reply.tval_sec = now.tv_sec;
+ irqwait->reply.tval_usec = now.tv_usec;
return ret;
}
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 7fb9d2a2cce..10091507a0d 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -75,19 +75,15 @@ int via_do_cleanup_map(struct drm_device * dev)
return 0;
}
-int via_map_init(DRM_IOCTL_ARGS)
+int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_init_t init;
+ drm_via_init_t *init = data;
DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case VIA_INIT_MAP:
- return via_do_init_map(dev, &init);
+ return via_do_init_map(dev, init);
case VIA_CLEANUP_MAP:
return via_do_cleanup_map(dev);
}
@@ -102,7 +98,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
index 85d56acd9d8..9afc1684348 100644
--- a/drivers/char/drm/via_mm.c
+++ b/drivers/char/drm/via_mm.c
@@ -33,18 +33,15 @@
#define VIA_MM_ALIGN_SHIFT 4
#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
-int via_agp_init(DRM_IOCTL_ARGS)
+int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_agp_t agp;
+ drm_via_agp_t *agp = data;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
int ret;
- DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
- sizeof(agp));
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
- agp.size >> VIA_MM_ALIGN_SHIFT);
+ agp->size >> VIA_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
@@ -53,25 +50,22 @@ int via_agp_init(DRM_IOCTL_ARGS)
}
dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp.offset;
+ dev_priv->agp_offset = agp->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+ DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
return 0;
}
-int via_fb_init(DRM_IOCTL_ARGS)
+int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_fb_t fb;
+ drm_via_fb_t *fb = data;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
int ret;
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
-
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
- fb.size >> VIA_MM_ALIGN_SHIFT);
+ fb->size >> VIA_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("VRAM memory manager initialisation error\n");
@@ -80,10 +74,10 @@ int via_fb_init(DRM_IOCTL_ARGS)
}
dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb.offset;
+ dev_priv->vram_offset = fb->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+ DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
return 0;
@@ -121,80 +115,71 @@ void via_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-int via_mem_alloc(DRM_IOCTL_ARGS)
+int via_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- drm_via_mem_t mem;
+ drm_via_mem_t *mem = data;
int retval = 0;
struct drm_memblock_item *item;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
unsigned long tmpSize;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
- sizeof(mem));
-
- if (mem.type > VIA_MEM_AGP) {
+ if (mem->type > VIA_MEM_AGP) {
DRM_ERROR("Unknown memory type allocation\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
mutex_lock(&dev->struct_mutex);
- if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+ if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
dev_priv->agp_initialized)) {
DRM_ERROR
("Attempt to allocate from uninitialized memory manager.\n");
mutex_unlock(&dev->struct_mutex);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
- item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
- (unsigned long)priv);
+ tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0,
+ (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
if (item) {
- mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+ mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
dev_priv->vram_offset : dev_priv->agp_offset) +
(item->mm->
offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
- mem.index = item->user_hash.key;
+ mem->index = item->user_hash.key;
} else {
- mem.offset = 0;
- mem.size = 0;
- mem.index = 0;
+ mem->offset = 0;
+ mem->size = 0;
+ mem->index = 0;
DRM_DEBUG("Video memory allocation failed\n");
- retval = DRM_ERR(ENOMEM);
+ retval = -ENOMEM;
}
- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
return retval;
}
-int via_mem_free(DRM_IOCTL_ARGS)
+int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_via_private_t *dev_priv = dev->dev_private;
- drm_via_mem_t mem;
+ drm_via_mem_t *mem = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
- sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
- ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+ ret = drm_sman_free_key(&dev_priv->sman, mem->index);
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("free = 0x%lx\n", mem.index);
+ DRM_DEBUG("free = 0x%lx\n", mem->index);
return ret;
}
-void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void via_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
drm_via_private_t *dev_priv = dev->dev_private;
- struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
- if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
mutex_unlock(&dev->struct_mutex);
return;
}
@@ -203,7 +188,7 @@ void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
dev->driver->dma_quiescent(dev);
}
- drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
return;
}
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 832d48356e9..46a57919874 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -1026,12 +1026,12 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
case state_error:
default:
*hc_state = saved_state;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (state == state_error) {
*hc_state = saved_state;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
@@ -1082,11 +1082,11 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
break;
case state_error:
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (state == state_error) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c
index 300ac61b09e..c15e75b54cb 100644
--- a/drivers/char/drm/via_video.c
+++ b/drivers/char/drm/via_video.c
@@ -65,10 +65,9 @@ void via_release_futex(drm_via_private_t * dev_priv, int context)
}
}
-int via_decoder_futex(DRM_IOCTL_ARGS)
+int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_futex_t fx;
+ drm_via_futex_t *fx = data;
volatile int *lock;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
@@ -76,21 +75,18 @@ int via_decoder_futex(DRM_IOCTL_ARGS)
DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t __user *) data,
- sizeof(fx));
-
- if (fx.lock > VIA_NR_XVMC_LOCKS)
+ if (fx->lock > VIA_NR_XVMC_LOCKS)
return -EFAULT;
- lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx.lock);
+ lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock);
- switch (fx.func) {
+ switch (fx->func) {
case VIA_FUTEX_WAIT:
- DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
- (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
+ DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
+ (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val);
return ret;
case VIA_FUTEX_WAKE:
- DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
+ DRM_WAKEUP(&(dev_priv->decoder_queue[fx->lock]));
return 0;
}
return 0;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b8278e1f4f..a69c6528326 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -136,7 +136,7 @@ static int sizeof_bootstrap = 375;
static struct dsp56k_device {
- long in_use;
+ unsigned long in_use;
long maxio, timeout;
int tx_wsize, rx_wsize;
} dsp56k;
@@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void)
err = PTR_ERR(dsp56k_class);
goto out_chrdev;
}
- class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+ device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
printk(banner);
goto out;
@@ -527,7 +527,7 @@ module_init(dsp56k_init_driver);
static void __exit dsp56k_cleanup_driver(void)
{
- class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+ device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
class_destroy(dsp56k_class);
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
}
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
deleted file mode 100644
index 020011495d9..00000000000
--- a/drivers/char/ec3104_keyb.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * linux/drivers/char/ec3104_keyb.c
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- * based on linux/drivers/char/pc_keyb.c, which had the following comments:
- *
- * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
- * See keyboard.c for the whole history.
- *
- * Major cleanup by Martin Mares, May 1997
- *
- * Combined the keyboard and PS/2 mouse handling into one file,
- * because they share the same hardware.
- * Johan Myreen <jem@iki.fi> 1998-10-08.
- *
- * Code fixes to handle mouse ACKs properly.
- * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
- */
-/* EC3104 note:
- * This code was written without any documentation about the EC3104 chip. While
- * I hope I got most of the basic functionality right, the register names I use
- * are most likely completely different from those in the chip documentation.
- *
- * If you have any further information about the EC3104, please tell me
- * (prumpf@tux.org).
- */
-
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/bitops.h>
-
-#include <asm/keyboard.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/ec3104.h>
-
-#include <asm/io.h>
-
-/* Some configuration switches are present in the include file... */
-
-#include <linux/pc_keyb.h>
-
-#define MSR_CTS 0x10
-#define MCR_RTS 0x02
-#define LSR_DR 0x01
-#define LSR_BOTH_EMPTY 0x60
-
-static struct e5_struct {
- u8 packet[8];
- int pos;
- int length;
-
- u8 cached_mcr;
- u8 last_msr;
-} ec3104_keyb;
-
-/* Simple translation table for the SysRq keys */
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char ec3104_kbd_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
- "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
- "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\r\000/"; /* 0x60 - 0x6f */
-#endif
-
-static void kbd_write_command_w(int data);
-static void kbd_write_output_w(int data);
-#ifdef CONFIG_PSMOUSE
-static void aux_write_ack(int val);
-static void __aux_write_ack(int val);
-#endif
-
-static DEFINE_SPINLOCK(kbd_controller_lock);
-static unsigned char handle_kbd_event(void);
-
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected;
-static volatile unsigned char acknowledge;
-static volatile unsigned char resend;
-
-
-int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
- return 0;
-}
-
-int ec3104_kbd_getkeycode(unsigned int scancode)
-{
- return 0;
-}
-
-
-/* yes, it probably would be faster to use an array. I don't care. */
-
-static inline unsigned char ec3104_scan2key(unsigned char scancode)
-{
- switch (scancode) {
- case 1: /* '`' */
- return 41;
-
- case 2 ... 27:
- return scancode;
-
- case 28: /* '\\' */
- return 43;
-
- case 29 ... 39:
- return scancode + 1;
-
- case 40: /* '\r' */
- return 28;
-
- case 41 ... 50:
- return scancode + 3;
-
- case 51: /* ' ' */
- return 57;
-
- case 52: /* escape */
- return 1;
-
- case 54: /* insert/delete (labelled delete) */
- /* this should arguably be 110, but I'd like to have ctrl-alt-del
- * working with a standard keymap */
- return 111;
-
- case 55: /* left */
- return 105;
- case 56: /* home */
- return 102;
- case 57: /* end */
- return 107;
- case 58: /* up */
- return 103;
- case 59: /* down */
- return 108;
- case 60: /* pgup */
- return 104;
- case 61: /* pgdown */
- return 109;
- case 62: /* right */
- return 106;
-
- case 79 ... 88: /* f1 - f10 */
- return scancode - 20;
-
- case 89 ... 90: /* f11 - f12 */
- return scancode - 2;
-
- case 91: /* left shift */
- return 42;
-
- case 92: /* right shift */
- return 54;
-
- case 93: /* left alt */
- return 56;
- case 94: /* right alt */
- return 100;
- case 95: /* left ctrl */
- return 29;
- case 96: /* right ctrl */
- return 97;
-
- case 97: /* caps lock */
- return 58;
- case 102: /* left windows */
- return 125;
- case 103: /* right windows */
- return 126;
-
- case 106: /* Fn */
- /* this is wrong. */
- return 84;
-
- default:
- return 0;
- }
-}
-
-int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
- scancode &= 0x7f;
-
- *keycode = ec3104_scan2key(scancode);
-
- return 1;
-}
-
-char ec3104_kbd_unexpected_up(unsigned char keycode)
-{
- return 0200;
-}
-
-static inline void handle_keyboard_event(unsigned char scancode)
-{
-#ifdef CONFIG_VT
- handle_scancode(scancode, !(scancode & 0x80));
-#endif
- tasklet_schedule(&keyboard_tasklet);
-}
-
-void ec3104_kbd_leds(unsigned char leds)
-{
-}
-
-static u8 e5_checksum(u8 *packet, int count)
-{
- int i;
- u8 sum = 0;
-
- for (i=0; i<count; i++)
- sum ^= packet[i];
-
- if (sum & 0x80)
- sum ^= 0xc0;
-
- return sum;
-}
-
-static void e5_wait_for_cts(struct e5_struct *k)
-{
- u8 msr;
-
- do {
- msr = ctrl_inb(EC3104_SER4_MSR);
- } while (!(msr & MSR_CTS));
-}
-
-
-static void e5_send_byte(u8 byte, struct e5_struct *k)
-{
- u8 status;
-
- do {
- status = ctrl_inb(EC3104_SER4_LSR);
- } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
-
- printk("<%02x>", byte);
-
- ctrl_outb(byte, EC3104_SER4_DATA);
-
- do {
- status = ctrl_inb(EC3104_SER4_LSR);
- } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
-
-}
-
-static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
-{
- int i;
-
- disable_irq(EC3104_IRQ_SER4);
-
- if (k->cached_mcr & MCR_RTS) {
- printk("e5_send_packet: too slow\n");
- enable_irq(EC3104_IRQ_SER4);
- return -EAGAIN;
- }
-
- k->cached_mcr |= MCR_RTS;
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
-
- e5_wait_for_cts(k);
-
- printk("p: ");
-
- for(i=0; i<count; i++)
- e5_send_byte(packet[i], k);
-
- e5_send_byte(e5_checksum(packet, count), k);
-
- printk("\n");
-
- udelay(1500);
-
- k->cached_mcr &= ~MCR_RTS;
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
-
- set_current_state(TASK_UNINTERRUPTIBLE);
-
-
-
- enable_irq(EC3104_IRQ_SER4);
-
-
-
- return 0;
-}
-
-/*
- * E5 packets we know about:
- * E5->host 0x80 0x05 <checksum> - resend packet
- * host->E5 0x83 0x43 <contrast> - set LCD contrast
- * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
- * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2
- * E5->host 0x88 <scancode> <checksum> - key press
- */
-
-static void e5_receive(struct e5_struct *k)
-{
- k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
-
- if (k->pos == 1) {
- switch(k->packet[0]) {
- case 0x80:
- k->length = 3;
- break;
-
- case 0x87: /* PS2 ext */
- k->length = 6;
- break;
-
- case 0x88: /* keyboard */
- k->length = 3;
- break;
-
- default:
- k->length = 1;
- printk(KERN_WARNING "unknown E5 packet %02x\n",
- k->packet[0]);
- }
- }
-
- if (k->pos == k->length) {
- int i;
-
- if (e5_checksum(k->packet, k->length) != 0)
- printk(KERN_WARNING "E5: wrong checksum\n");
-
-#if 0
- printk("E5 packet [");
- for(i=0; i<k->length; i++) {
- printk("%02x ", k->packet[i]);
- }
-
- printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
-#endif
-
- switch(k->packet[0]) {
- case 0x80:
- case 0x88:
- handle_keyboard_event(k->packet[1]);
- break;
- }
-
- k->pos = k->length = 0;
- }
-}
-
-static void ec3104_keyb_interrupt(int irq, void *data)
-{
- struct e5_struct *k = &ec3104_keyb;
- u8 msr, lsr;
-
- msr = ctrl_inb(EC3104_SER4_MSR);
-
- if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
- if (k->cached_mcr & MCR_RTS)
- printk("confused: RTS already high\n");
- /* CTS went high. Send RTS. */
- k->cached_mcr |= MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
- /* CTS went low. */
- if (!(k->cached_mcr & MCR_RTS))
- printk("confused: RTS already low\n");
-
- k->cached_mcr &= ~MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- }
-
- k->last_msr = msr;
-
- lsr = ctrl_inb(EC3104_SER4_LSR);
-
- if (lsr & LSR_DR)
- e5_receive(k);
-}
-
-static void ec3104_keyb_clear_state(void)
-{
- struct e5_struct *k = &ec3104_keyb;
- u8 msr, lsr;
-
- /* we want CTS to be low */
- k->last_msr = 0;
-
- for (;;) {
- msleep(100);
-
- msr = ctrl_inb(EC3104_SER4_MSR);
-
- lsr = ctrl_inb(EC3104_SER4_LSR);
-
- if (lsr & LSR_DR) {
- e5_receive(k);
- continue;
- }
-
- if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
- if (k->cached_mcr & MCR_RTS)
- printk("confused: RTS already high\n");
- /* CTS went high. Send RTS. */
- k->cached_mcr |= MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
- /* CTS went low. */
- if (!(k->cached_mcr & MCR_RTS))
- printk("confused: RTS already low\n");
-
- k->cached_mcr &= ~MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else
- break;
-
- k->last_msr = msr;
-
- continue;
- }
-}
-
-void __init ec3104_kbd_init_hw(void)
-{
- ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
- ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
-
- ec3104_keyb_clear_state();
-
- /* Ok, finally allocate the IRQ, and off we go.. */
- request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
-}
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 8d74b8745e6..bd94d5f9e62 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -411,8 +411,8 @@ cleanup_module(void)
iiResetDelay( i2BoardPtrTable[i] );
/* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 );
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
}
/* Disable and remove interrupt handler. */
if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
@@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
}
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- class_device_create(ip2_class, NULL,
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i),
- NULL, "ipl%d", i);
- class_device_create(ip2_class, NULL,
+ "ipl%d", i);
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- NULL, "stat%d", i);
+ "stat%d", i);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c2aa44ee6eb..0246a2b8ce4 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
entry->dev = dev;
mutex_lock(&reg_list_mutex);
- class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+ device_create(ipmi_class, device, dev, "ipmi%d", if_num);
list_add(&entry->link, &reg_list);
mutex_unlock(&reg_list_mutex);
}
@@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num)
break;
}
}
- class_device_destroy(ipmi_class, dev);
+ device_destroy(ipmi_class, dev);
mutex_unlock(&reg_list_mutex);
}
@@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void)
mutex_lock(&reg_list_mutex);
list_for_each_entry_safe(entry, entry2, &reg_list, link) {
list_del(&entry->link);
- class_device_destroy(ipmi_class, entry->dev);
+ device_destroy(ipmi_class, entry->dev);
kfree(entry);
}
mutex_unlock(&reg_list_mutex);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index a2894d42515..c1222e98525 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1072,19 +1072,19 @@ static char *si_type[SI_MAX_PARMS];
#define MAX_SI_TYPE_STR 30
static char si_type_str[MAX_SI_TYPE_STR];
static unsigned long addrs[SI_MAX_PARMS];
-static int num_addrs;
+static unsigned int num_addrs;
static unsigned int ports[SI_MAX_PARMS];
-static int num_ports;
+static unsigned int num_ports;
static int irqs[SI_MAX_PARMS];
-static int num_irqs;
+static unsigned int num_irqs;
static int regspacings[SI_MAX_PARMS];
-static int num_regspacings;
+static unsigned int num_regspacings;
static int regsizes[SI_MAX_PARMS];
-static int num_regsizes;
+static unsigned int num_regsizes;
static int regshifts[SI_MAX_PARMS];
-static int num_regshifts;
+static unsigned int num_regshifts;
static int slave_addrs[SI_MAX_PARMS];
-static int num_slave_addrs;
+static unsigned int num_slave_addrs;
#define IPMI_IO_ADDR_SPACE 0
#define IPMI_MEM_ADDR_SPACE 1
@@ -1106,12 +1106,12 @@ MODULE_PARM_DESC(type, "Defines the type of each interface, each"
" interface separated by commas. The types are 'kcs',"
" 'smic', and 'bt'. For example si_type=kcs,bt will set"
" the first interface to kcs and the second to bt");
-module_param_array(addrs, long, &num_addrs, 0);
+module_param_array(addrs, ulong, &num_addrs, 0);
MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"
" addresses separated by commas. Only use if an interface"
" is in memory. Otherwise, set it to zero or leave"
" it blank.");
-module_param_array(ports, int, &num_ports, 0);
+module_param_array(ports, uint, &num_ports, 0);
MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"
" addresses separated by commas. Only use if an interface"
" is a port. Otherwise, set it to zero or leave"
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 3c66f402f9d..1f27be1ec3d 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void)
istallion_class = class_create(THIS_MODULE, "staliomem");
for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_deinit:
@@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void)
unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
for (j = 0; j < 4; j++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
- j));
+ device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
class_destroy(istallion_class);
pci_unregister_driver(&stli_pcidriver);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 62051f8b091..c59e2a0996c 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
- "lp%d", nr);
+ device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -971,7 +970,7 @@ static void lp_cleanup_module (void)
if (lp_table[offset].dev == NULL)
continue;
parport_unregister_device(lp_table[offset].dev);
- class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+ device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
}
class_destroy(lp_class);
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 4177f6db83e..cc5d77797de 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
- "cmm%d", i);
+ device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
return 0;
}
@@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmm_class, MKDEV(major, devno));
+ device_destroy(cmm_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index b24a3e7bbb9..a0b9c8728d5 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
- "cmx%d", i);
+ device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
return 0;
}
@@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmx_class, MKDEV(major, devno));
+ device_destroy(cmx_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index de14aea34e1..73de77105fe 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
static void __init legacy_pty_init(void)
{
+ if (legacy_count <= 0)
+ return;
- pty_driver = alloc_tty_driver(NR_PTYS);
+ pty_driver = alloc_tty_driver(legacy_count);
if (!pty_driver)
panic("Couldn't allocate pty driver");
- pty_slave_driver = alloc_tty_driver(NR_PTYS);
+ pty_slave_driver = alloc_tty_driver(legacy_count);
if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver");
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 1f0d7c60c94..bbfa0e241cb 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = {
.owner = THIS_MODULE,
};
-static struct cdev raw_cdev = {
- .kobj = {.name = "raw", },
- .owner = THIS_MODULE,
-};
+static struct cdev raw_cdev;
static int __init raw_init(void)
{
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
index 23d0681fe49..78f24540c22 100644
--- a/drivers/char/rio/host.h
+++ b/drivers/char/rio/host.h
@@ -99,7 +99,7 @@ struct Host {
struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT];
int timeout_id; /* For calling 100 ms delays */
int timeout_sem; /* For calling 100 ms delays */
- long locks; /* long req'd for set_bit --RR */
+ unsigned long locks; /* long req'd for set_bit --RR */
char ____end_marker____;
};
#define Control CardP->DpControl
diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h
index 6317aade201..9cc1313d5e6 100644
--- a/drivers/char/riscom8.h
+++ b/drivers/char/riscom8.h
@@ -71,7 +71,7 @@ struct riscom_port {
struct tty_struct * tty;
int count;
int blocked_open;
- long event; /* long req'd for set_bit --RR */
+ unsigned long event; /* long req'd for set_bit --RR */
int timeout;
int close_delay;
unsigned char * xmit_buf;
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 52753e723ea..b9c1dba6bd0 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -441,8 +441,7 @@ scdrv_init(void)
continue;
}
- class_device_create(snsc_class, NULL, dev, NULL,
- "%s", devname);
+ device_create(snsc_class, NULL, dev, "%s", devname);
ia64_sn_irtr_intr_enable(scd->scd_nasid,
0 /*ignored */ ,
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 4a80b2f864e..45758d5b56e 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void)
if (IS_ERR(stallion_class))
printk("STALLION: failed to create class\n");
for (i = 0; i < 4; i++)
- class_device_create(stallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i), NULL,
- "staliomem%d", i);
+ device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_unrtty:
@@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void)
}
for (i = 0; i < 4; i++)
- class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
class_destroy(stallion_class);
diff --git a/drivers/char/sx.h b/drivers/char/sx.h
index 432aad0a2dd..70d9783c732 100644
--- a/drivers/char/sx.h
+++ b/drivers/char/sx.h
@@ -27,7 +27,7 @@ struct sx_port {
int c_dcd;
struct sx_board *board;
int line;
- long locks;
+ unsigned long locks;
};
struct sx_board {
@@ -45,7 +45,7 @@ struct sx_board {
int poll;
int ta_type;
struct timer_list timer;
- long locks;
+ unsigned long locks;
};
struct vpd_prom {
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2f97d2f8f91..64e835f6243 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -206,10 +206,10 @@ static void flush_cond_wait(struct cond_wait **head);
*/
struct slgt_desc
{
- unsigned short count;
- unsigned short status;
- unsigned int pbuf; /* physical address of data buffer */
- unsigned int next; /* physical address of next descriptor */
+ __le16 count;
+ __le16 status;
+ __le32 pbuf; /* physical address of data buffer */
+ __le32 next; /* physical address of next descriptor */
/* driver book keeping */
char *buf; /* virtual address of data buffer */
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 35b40b99653..cef55c40654 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port)
goto out;
}
- class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
- TIPAR_MINOR + nr), port->dev, "par%d", nr);
+ device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+ TIPAR_MINOR + nr), "par%d", nr);
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@ tipar_cleanup_module(void)
if (table[i].dev == NULL)
continue;
parport_unregister_device(table[i].dev);
- class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+ device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
}
class_destroy(tipar_class);
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index f1d60f0cef8..db7a731e236 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
state[i].cur_part = 0;
for (j = 0; j < MAX_PARTITIONS; ++j)
state[i].part_stat_rwi[j] = VIOT_IDLE;
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
"iseries!vt%d", i);
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
- NULL, "iseries!nvt%d", i);
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+ "iseries!nvt%d", i);
printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
"resource %10.10s type %4.4s, model %3.3s\n",
i, viotape_unitinfo[i].rsrcname,
@@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev)
{
int i = vdev->unit_address;
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
return 0;
}
diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c
index 564143d4061..9cfb9757662 100644
--- a/drivers/char/watchdog/mpc5200_wdt.c
+++ b/drivers/char/watchdog/mpc5200_wdt.c
@@ -81,7 +81,7 @@ static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
/* file operations */
-static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
struct mpc5200_wdt *wdt = file->private_data;
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 993fa7b8925..721f86f4f00 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS
If in doubt, say N.
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+ bool "ondemand"
+ select CPU_FREQ_GOV_ONDEMAND
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'ondemand' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the ondemand
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+ bool "conservative"
+ select CPU_FREQ_GOV_CONSERVATIVE
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'conservative' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the conservative
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
endchoice
config CPU_FREQ_GOV_PERFORMANCE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2f6a73c01b7..5e626b12b97 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
+ /* Set governor before ->init, so that driver could check it */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* prepare interface data */
policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq;
- strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+ kobject_set_name(&policy->kobj, "cpufreq");
ret = kobject_register(&policy->kobj);
if (ret) {
@@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (policy) {
- if (unlikely(lock_policy_rwsem_read(cpu)))
- return ret_freq;
-
ret_freq = policy->cur;
-
- unlock_policy_rwsem_read(cpu);
cpufreq_cpu_put(policy);
}
@@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
{
int ret;
+ /* Only must be defined when default governor is known to have latency
+ restrictions, like e.g. conservative or ondemand.
+ That this is the case is already ensured in Kconfig
+ */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+ struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+ struct cpufreq_governor *gov = NULL;
+#endif
+
+ if (policy->governor->max_transition_latency &&
+ policy->cpuinfo.transition_latency >
+ policy->governor->max_transition_latency) {
+ if (!gov)
+ return -EINVAL;
+ else {
+ printk(KERN_WARNING "%s governor failed, too long"
+ " transition latency of HW, fallback"
+ " to %s governor\n",
+ policy->governor->name,
+ gov->name);
+ policy->governor = gov;
+ }
+ }
+
if (!try_module_get(policy->governor->owner))
return -EINVAL;
@@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_update_policy);
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 26f440ccc3f..4bd33ce8a6f 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -58,7 +58,7 @@ static unsigned int def_sampling_rate;
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
(!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000))
- return -EINVAL;
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "conservative",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_conservative);
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_conservative);
}
static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
/* Make sure that the scheduled work is indeed not running */
flush_scheduled_work();
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_conservative);
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e794527e492..369f4459515 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000)) {
- printk(KERN_WARNING "ondemand governor failed to load "
- "due to too long transition latency\n");
- return -EINVAL;
- }
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
static int __init cpufreq_gov_dbs_init(void)
{
@@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void)
printk(KERN_ERR "Creation of kondemand failed\n");
return -EFAULT;
}
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_ondemand);
destroy_workqueue(kondemand_wq);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 917b9bab9cc..8a45d0f93e2 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1;
}
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
return 0;
}
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
{
.notifier_call = cpufreq_stat_cpu_callback,
};
@@ -356,8 +356,7 @@ __init cpufreq_stats_init(void)
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_ONLINE, (void *)(long)cpu);
+ cpufreq_update_policy(cpu);
}
return 0;
}
@@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void)
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_DEAD, (void *)(long)cpu);
+ cpufreq_stats_free_table(cpu);
}
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
"through sysfs filesystem");
MODULE_LICENSE ("GPL");
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 4a0576bd06f..3706b2bc098 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = {
* /sys/devices/system/edac/mc
*/
static struct kset mc_kset = {
- .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+ .kobj = {.ktype = &ktype_mc_set_attribs },
.ktype = &ktype_mci,
};
@@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void)
}
/* Init the MC's kobject */
+ kobject_set_name(&mc_kset.kobj, "mc");
mc_kset.kobj.parent = &edac_class->kset.kobj;
/* register the mc_kset */
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d944647c82c..65dcf043265 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -35,9 +35,9 @@ static struct eisa_device_info __initdata eisa_table[] = {
#define EISA_MAX_FORCED_DEV 16
static int enable_dev[EISA_MAX_FORCED_DEV];
-static int enable_dev_count;
+static unsigned int enable_dev_count;
static int disable_dev[EISA_MAX_FORCED_DEV];
-static int disable_dev_count;
+static unsigned int disable_dev_count;
static int is_forced_dev (int *forced_tab,
int forced_count,
@@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
return 0;
}
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct eisa_device *edev = to_eisa_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
return 0;
}
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 22b62b3cd14..82de9e1adb1 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -427,15 +427,10 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len);
}
- if (fcmd->data) {
- if (SCpnt->use_sg)
- dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- else
- dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
+ if (fcmd->data)
+ dma_unmap_sg(fc->dev, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt),
+ SCpnt->sc_data_direction);
break;
default:
host_status=DID_ERROR; /* FIXME */
@@ -793,10 +788,14 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
fcp_cntl = FCP_CNTL_QTYPE_SIMPLE;
} else
fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED;
- if (!SCpnt->request_bufflen && !SCpnt->use_sg) {
+
+ if (!scsi_bufflen(SCpnt)) {
cmd->fcp_cntl = fcp_cntl;
fcmd->data = (dma_addr_t)NULL;
} else {
+ struct scatterlist *sg;
+ int nents;
+
switch (SCpnt->cmnd[0]) {
case WRITE_6:
case WRITE_10:
@@ -805,22 +804,12 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
default:
cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break;
}
- if (!SCpnt->use_sg) {
- cmd->fcp_data_len = SCpnt->request_bufflen;
- fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- } else {
- struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
- int nents;
-
- FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
- nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg);
- fcmd->data = sg_dma_address(sg);
- cmd->fcp_data_len = sg_dma_len(sg);
- }
+
+ sg = scsi_sglist(SCpnt);
+ nents = dma_map_sg(fc->dev, sg, scsi_sg_count(SCpnt),
+ SCpnt->sc_data_direction);
+ fcmd->data = sg_dma_address(sg);
+ cmd->fcp_data_len = sg_dma_len(sg);
}
memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len);
memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len);
diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h
index 1ac61330592..506338a461b 100644
--- a/drivers/fc4/fcp_impl.h
+++ b/drivers/fc4/fcp_impl.h
@@ -91,7 +91,7 @@ typedef struct _fc_channel {
fcp_cmd *scsi_cmd_pool;
char *scsi_rsp_pool;
dma_addr_t dma_scsi_cmd, dma_scsi_rsp;
- long *scsi_bitmap;
+ unsigned long *scsi_bitmap;
long scsi_bitmap_end;
int scsi_free;
int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *);
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 75388641a7d..06471302200 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -722,10 +722,11 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
buffer_end = 0;
}
- if (!access_ok(VERIFY_READ, request->packets, request->size))
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+
+ if (!access_ok(VERIFY_READ, p, request->size))
return -EFAULT;
- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
end = (void __user *)p + request->size;
count = 0;
while (p < end) {
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 2b658634163..56681b3b297 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
}
static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct fw_unit *unit = fw_unit(dev);
char modalias[64];
- int length = 0;
- int i = 0;
get_modalias(unit, modalias, sizeof(modalias));
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=%s", modalias))
+ if (add_uevent_var(env, "MODALIAS=%s", modalias))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 59c3b5aa89f..b6e1eb77d14 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -13,21 +13,31 @@
#include <linux/device.h>
#include <linux/autoconf.h>
-#define DEFINE_DMI_ATTR(_name, _mode, _show) \
-static struct device_attribute sys_dmi_##_name##_attr = \
- __ATTR(_name, _mode, _show, NULL);
-
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
-static ssize_t sys_dmi_##_name##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *page) \
-{ \
- ssize_t len; \
- len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
- page[len-1] = '\n'; \
- return len; \
-} \
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+struct dmi_device_attribute{
+ struct device_attribute dev_attr;
+ int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+ container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
+
+static ssize_t sys_dmi_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ int field = to_dmi_dev_attr(attr)->field;
+ ssize_t len;
+ len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+ page[len-1] = '\n';
+ return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field) \
+ { .dev_attr = __ATTR(_name, _mode, _show, NULL), \
+ .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
+static struct dmi_device_attribute sys_dmi_##_name##_attr = \
+ DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev,
return r+1;
}
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+ __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
@@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = {
NULL
};
-static int dmi_dev_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- strcpy(buffer, "MODALIAS=");
- get_modalias(buffer+9, buffer_size-9);
- envp[0] = buffer;
- envp[1] = NULL;
-
+ ssize_t len;
+
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = get_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
@@ -157,7 +171,7 @@ static struct device *dmi_dev;
#define ADD_DMI_ATTR(_name, _field) \
if (dmi_get_system_info(_field)) \
- sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+ sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
extern int dmi_available;
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 0fb730ee1da..6942e065e60 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj)
kfree(dev);
}
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
.release = edd_release,
.sysfs_ops = &edd_attr_ops,
.default_attrs = def_attrs,
};
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
/**
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index bfd2d67df68..858a7b95933 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = {
NULL,
};
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
.release = efivar_release,
.sysfs_ops = &efivar_attr_ops,
.default_attrs = def_attrs,
@@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = {
NULL, /* maybe more in the future? */
};
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
static decl_subsys(efi, NULL, NULL);
/*
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 19667fcc722..cacf89e65af 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -46,6 +46,25 @@ config HID_DEBUG
If unsure, say N
+config HIDRAW
+ bool "/dev/hidraw raw HID device support"
+ depends on HID
+ ---help---
+ Say Y here if you want to support HID devices (from the USB
+ specification standpoint) that aren't strictly user interface
+ devices, like monitor controls and Uninterruptable Power Supplies.
+
+ This module supports these devices separately using a separate
+ event interface on /dev/hidraw.
+
+ There is also a /dev/hiddev configuration option in the USB HID
+ configuration menu. In comparison to hiddev, this device does not process
+ the hid events at all (no parsing, no lookups). This lets applications
+ to work on raw hid events when they want to, and avoid using transport-specific
+ userspace libhid/libusb libraries.
+
+ If unsure, say Y.
+
source "drivers/hid/usbhid/Kconfig"
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 68d1376a53f..1ac5103f7c9 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -4,7 +4,9 @@
hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
+
hid-$(CONFIG_HID_DEBUG) += hid-debug.o
+hid-$(CONFIG_HIDRAW) += hidraw.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 317cf8a7b63..2884b036495 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -30,6 +30,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
+#include <linux/hidraw.h>
/*
* Version Information
@@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ hidraw_report_event(hid, data, size);
for (n = 0; n < report->maxfield; n++)
hid_input_field(hid, report->field[n], data, interrupt);
@@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
}
EXPORT_SYMBOL_GPL(hid_input_report);
+static int __init hid_init(void)
+{
+ return hidraw_init();
+}
+
+static void __exit hid_exit(void)
+{
+ hidraw_exit();
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index a13757b7898..5c24fe46d8e 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -34,7 +34,7 @@
struct hid_usage_entry {
unsigned page;
unsigned usage;
- char *description;
+ const char *description;
};
static const struct hid_usage_entry hid_usage_table[] = {
@@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) {
}
EXPORT_SYMBOL_GPL(hid_resolv_usage);
-__inline__ static void tab(int n) {
- while (n--) printk(" ");
+static void tab(int n) {
+ printk(KERN_DEBUG "%*s", n, "");
}
void hid_dump_field(struct hid_field *field, int n) {
@@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) {
tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
}
if (field->unit) {
- char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
- char *units[5][8] = {
+ static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+ static const char *units[5][8] = {
{ "None", "None", "None", "None", "None", "None", "None", "None" },
{ "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
{ "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
@@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) {
printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
- printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+ printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
@@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) {
struct hid_report *report;
struct list_head *list;
unsigned i,k;
- static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+ static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
if (!hid_debug)
return;
@@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) {
if (!hid_debug)
return;
- printk("hid-debug: input ");
+ printk(KERN_DEBUG "hid-debug: input ");
hid_resolv_usage(usage->hid);
printk(" = %d\n", value);
}
EXPORT_SYMBOL_GPL(hid_dump_input);
-static char *events[EV_MAX + 1] = {
+static const char *events[EV_MAX + 1] = {
[EV_SYN] = "Sync", [EV_KEY] = "Key",
[EV_REL] = "Relative", [EV_ABS] = "Absolute",
[EV_MSC] = "Misc", [EV_LED] = "LED",
@@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = {
[EV_FF_STATUS] = "ForceFeedbackStatus",
};
-static char *syncs[2] = {
+static const char *syncs[2] = {
[SYN_REPORT] = "Report", [SYN_CONFIG] = "Config",
};
-static char *keys[KEY_MAX + 1] = {
+static const char *keys[KEY_MAX + 1] = {
[KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc",
[KEY_1] = "1", [KEY_2] = "2",
[KEY_3] = "3", [KEY_4] = "4",
@@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = {
[KEY_DEL_LINE] = "DeleteLine",
[KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
[KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
- [KEY_DOCUMENTS] = "Documents",
+ [KEY_DOCUMENTS] = "Documents", [KEY_SPELLCHECK] = "SpellCheck",
+ [KEY_LOGOFF] = "Logoff",
[KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC",
[KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2",
[KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D",
@@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = {
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
};
-static char *relatives[REL_MAX + 1] = {
+static const char *relatives[REL_MAX + 1] = {
[REL_X] = "X", [REL_Y] = "Y",
[REL_Z] = "Z", [REL_RX] = "Rx",
[REL_RY] = "Ry", [REL_RZ] = "Rz",
@@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = {
[REL_WHEEL] = "Wheel", [REL_MISC] = "Misc",
};
-static char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_MAX + 1] = {
[ABS_X] = "X", [ABS_Y] = "Y",
[ABS_Z] = "Z", [ABS_RX] = "Rx",
[ABS_RY] = "Ry", [ABS_RZ] = "Rz",
@@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = {
[ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc",
};
-static char *misc[MSC_MAX + 1] = {
+static const char *misc[MSC_MAX + 1] = {
[MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled",
[MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData"
};
-static char *leds[LED_MAX + 1] = {
+static const char *leds[LED_MAX + 1] = {
[LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
[LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
[LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
@@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = {
[LED_MISC] = "Misc",
};
-static char *repeats[REP_MAX + 1] = {
+static const char *repeats[REP_MAX + 1] = {
[REP_DELAY] = "Delay", [REP_PERIOD] = "Period"
};
-static char *sounds[SND_MAX + 1] = {
+static const char *sounds[SND_MAX + 1] = {
[SND_CLICK] = "Click", [SND_BELL] = "Bell",
[SND_TONE] = "Tone"
};
-static char **names[EV_MAX + 1] = {
+static const char **names[EV_MAX + 1] = {
[EV_SYN] = syncs, [EV_KEY] = keys,
[EV_REL] = relatives, [EV_ABS] = absolutes,
[EV_MSC] = misc, [EV_LED] = leds,
@@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) {
names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
}
EXPORT_SYMBOL_GPL(hid_resolv_event);
-
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 8edbd30cf79..dd332f28e08 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = {
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+ unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
@@ -86,6 +86,10 @@ static const struct {
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
+/* hardware needing special handling due to colliding MSVENDOR page usages */
+#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
+#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
+
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
struct hidinput_key_translation {
@@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode,
{
struct hid_device *hid = dev->private;
struct hid_usage *usage;
-
+
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
*keycode = usage->code;
@@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
struct hid_device *hid = dev->private;
struct hid_usage *usage;
int old_keycode;
-
+
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
-
+
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
old_keycode = usage->code;
usage->code = keycode;
-
+
clear_bit(old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
* by another key */
if (hidinput_find_key (hid, 0, old_keycode))
set_bit(old_keycode, dev->keybit);
-
+
return 0;
}
-
+
return -EINVAL;
}
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore;
+ /* only LED usages are supported in output fields */
+ if (field->report_type == HID_OUTPUT_REPORT &&
+ (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
+ dbg_hid_line(" [non-LED output field] ");
+ goto ignore;
+ }
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_UNDEFINED:
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0f6: map_key_clear(KEY_NEXT); break;
case 0x0fa: map_key_clear(KEY_BACK); break;
+ case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x185: map_key_clear(KEY_EDITOR); break;
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x192: map_key_clear(KEY_CALC); break;
case 0x194: map_key_clear(KEY_FILE); break;
case 0x196: map_key_clear(KEY_WWW); break;
+ case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
+ case 0x1b6: map_key_clear(KEY_MEDIA); break;
+ case 0x1b7: map_key_clear(KEY_SOUND); break;
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x201: map_key_clear(KEY_NEW); break;
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_MSVENDOR:
- /* special case - Chicony Chicony KU-0418 tactical pad */
- if (device->vendor == 0x04f2 && device->product == 0x0418) {
+ /* Unfortunately, there are multiple devices which
+ * emit usages from MSVENDOR page that require different
+ * handling. If this list grows too much in the future,
+ * more general handling will have to be introduced here
+ * (i.e. another blacklist).
+ */
+
+ /* Chicony Chicony KU-0418 tactical pad */
+ if (IS_CHICONY_TACTICAL_PAD(device)) {
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
case 0xff01: map_key_clear(BTN_1); break;
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0xff0b: map_key_clear(BTN_B); break;
default: goto ignore;
}
+
+ /* Microsoft Natural Ergonomic Keyboard 4000 */
+ } else if (IS_MS_KB(device)) {
+ switch(usage->hid & HID_USAGE) {
+ case 0xfd06:
+ map_key_clear(KEY_CHAT);
+ break;
+ case 0xfd07:
+ map_key_clear(KEY_PHONE);
+ break;
+ case 0xff05:
+ set_bit(EV_REP, input->evbit);
+ map_key_clear(KEY_F13);
+ set_bit(KEY_F14, input->keybit);
+ set_bit(KEY_F15, input->keybit);
+ set_bit(KEY_F16, input->keybit);
+ set_bit(KEY_F17, input->keybit);
+ set_bit(KEY_F18, input->keybit);
+ default: goto ignore;
+ }
} else {
goto ignore;
}
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(KEY_VOLUMEDOWN, input->keybit);
}
+ if (usage->type == EV_KEY) {
+ set_bit(EV_MSC, input->evbit);
+ set_bit(MSC_SCAN, input->mscbit);
+ }
+
hid_resolv_event(usage->type, usage->code);
dbg_hid_line("\n");
@@ -902,7 +950,7 @@ ignore:
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
- int *quirks = &hid->quirks;
+ unsigned *quirks = &hid->quirks;
if (!field->hidinput)
return;
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
+ /* Handling MS keyboards special buttons */
+ if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+ int key = 0;
+ static int last_key = 0;
+ switch (value) {
+ case 0x01: key = KEY_F14; break;
+ case 0x02: key = KEY_F15; break;
+ case 0x04: key = KEY_F16; break;
+ case 0x08: key = KEY_F17; break;
+ case 0x10: key = KEY_F18; break;
+ default: break;
+ }
+ if (key) {
+ input_event(input, usage->type, key, 1);
+ last_key = key;
+ } else {
+ input_event(input, usage->type, last_key, 0);
+ }
+ }
+ /* report the usage code as scancode if the key status has changed */
+ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
+ input_event(input, EV_MSC, MSC_SCAN, usage->hid);
+
input_event(input, usage->type, usage->code, value);
if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid)
int i, j, k;
int max_report_type = HID_OUTPUT_REPORT;
+ if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
+ return -1;
+
INIT_LIST_HEAD(&hid->inputs);
for (i = 0; i < hid->maxcollection; i++)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
new file mode 100644
index 00000000000..a702e2f6da7
--- /dev/null
+++ b/drivers/hid/hidraw.c
@@ -0,0 +1,407 @@
+/*
+ * HID raw devices, giving access to raw HID events.
+ *
+ * In comparison to hiddev, this device does not process the
+ * hid events at all (no parsing, no lookups). This lets applications
+ * to work on raw hid events as they want to, and avoids a need to
+ * use a transport-specific userspace libhid/libusb libraries.
+ *
+ * Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/major.h>
+#include <linux/hid.h>
+#include <linux/mutex.h>
+
+#include <linux/hidraw.h>
+
+static int hidraw_major;
+static struct cdev hidraw_cdev;
+static struct class *hidraw_class;
+static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
+static DEFINE_SPINLOCK(minors_lock);
+
+static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct hidraw_list *list = file->private_data;
+ int ret = 0, len;
+ char *report;
+ DECLARE_WAITQUEUE(wait, current);
+
+ while (ret == 0) {
+
+ mutex_lock(&list->read_mutex);
+
+ if (list->head == list->tail) {
+ add_wait_queue(&list->hidraw->wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (list->head == list->tail) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ if (!list->hidraw->exist) {
+ ret = -EIO;
+ break;
+ }
+
+ /* allow O_NONBLOCK to work well from other threads */
+ mutex_unlock(&list->read_mutex);
+ schedule();
+ mutex_lock(&list->read_mutex);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&list->hidraw->wait, &wait);
+ }
+
+ if (ret)
+ goto out;
+
+ report = list->buffer[list->tail].value;
+ len = list->buffer[list->tail].len > count ?
+ count : list->buffer[list->tail].len;
+
+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret += len;
+
+ kfree(list->buffer[list->tail].value);
+ list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
+ }
+out:
+ mutex_unlock(&list->read_mutex);
+ return ret;
+}
+
+/* the first byte is expected to be a report number */
+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ struct hid_device *dev = hidraw_table[minor]->hid;
+ __u8 *buf;
+ int ret = 0;
+
+ if (!dev->hid_output_raw_report)
+ return -ENODEV;
+
+ if (count > HID_MIN_BUFFER_SIZE) {
+ printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
+ current->pid);
+ return -EINVAL;
+ }
+
+ if (count < 2) {
+ printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
+ current->pid);
+ return -EINVAL;
+ }
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, buffer, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = dev->hid_output_raw_report(dev, buf, count);
+out:
+ kfree(buf);
+ return ret;
+}
+
+static unsigned int hidraw_poll(struct file *file, poll_table *wait)
+{
+ struct hidraw_list *list = file->private_data;
+
+ poll_wait(file, &list->hidraw->wait, wait);
+ if (list->head != list->tail)
+ return POLLIN | POLLRDNORM;
+ if (!list->hidraw->exist)
+ return POLLERR | POLLHUP;
+ return 0;
+}
+
+static int hidraw_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev;
+ struct hidraw_list *list;
+ int err = 0;
+
+ if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+ minor);
+ kfree(list);
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ list->hidraw = hidraw_table[minor];
+ mutex_init(&list->read_mutex);
+ list_add_tail(&list->node, &hidraw_table[minor]->list);
+ file->private_data = list;
+
+ dev = hidraw_table[minor];
+ if (!dev->open++)
+ dev->hid->hid_open(dev->hid);
+
+out_unlock:
+ spin_unlock(&minors_lock);
+out:
+ return err;
+
+}
+
+static int hidraw_release(struct inode * inode, struct file * file)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev;
+ struct hidraw_list *list = file->private_data;
+
+ if (!hidraw_table[minor]) {
+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+ minor);
+ return -ENODEV;
+ }
+
+ list_del(&list->node);
+ dev = hidraw_table[minor];
+ if (!dev->open--) {
+ if (list->hidraw->exist)
+ dev->hid->hid_close(dev->hid);
+ else
+ kfree(list->hidraw);
+ }
+
+ return 0;
+}
+
+static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev = hidraw_table[minor];
+ void __user *user_arg = (void __user*) arg;
+
+ switch (cmd) {
+ case HIDIOCGRDESCSIZE:
+ if (put_user(dev->hid->rsize, (int __user *)arg))
+ return -EFAULT;
+ return 0;
+
+ case HIDIOCGRDESC:
+ {
+ __u32 len;
+
+ if (get_user(len, (int __user *)arg))
+ return -EFAULT;
+
+ if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
+ return -EINVAL;
+
+ if (copy_to_user(user_arg + offsetof(
+ struct hidraw_report_descriptor,
+ value[0]),
+ dev->hid->rdesc,
+ min(dev->hid->rsize, len)))
+ return -EFAULT;
+ return 0;
+ }
+ case HIDIOCGRAWINFO:
+ {
+ struct hidraw_devinfo dinfo;
+
+ dinfo.bustype = dev->hid->bus;
+ dinfo.vendor = dev->hid->vendor;
+ dinfo.product = dev->hid->product;
+ if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
+ default:
+ printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n",
+ cmd);
+ }
+ return -EINVAL;
+}
+
+static const struct file_operations hidraw_ops = {
+ .owner = THIS_MODULE,
+ .read = hidraw_read,
+ .write = hidraw_write,
+ .poll = hidraw_poll,
+ .open = hidraw_open,
+ .release = hidraw_release,
+ .ioctl = hidraw_ioctl,
+};
+
+void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+{
+ struct hidraw *dev = hid->hidraw;
+ struct hidraw_list *list;
+
+ list_for_each_entry(list, &dev->list, node) {
+ list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+ list->buffer[list->head].len = len;
+ list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ }
+
+ wake_up_interruptible(&dev->wait);
+}
+EXPORT_SYMBOL_GPL(hidraw_report_event);
+
+int hidraw_connect(struct hid_device *hid)
+{
+ int minor, result;
+ struct hidraw *dev;
+
+ /* TODO currently we accept any HID device. This should later
+ * probably be fixed to accept only those devices which provide
+ * non-input applications
+ */
+
+ dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ result = -EINVAL;
+
+ spin_lock(&minors_lock);
+
+ for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
+ if (hidraw_table[minor])
+ continue;
+ hidraw_table[minor] = dev;
+ result = 0;
+ break;
+ }
+
+ spin_unlock(&minors_lock);
+
+ if (result) {
+ kfree(dev);
+ goto out;
+ }
+
+ dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor),
+ "%s%d", "hidraw", minor);
+
+ if (IS_ERR(dev->dev)) {
+ spin_lock(&minors_lock);
+ hidraw_table[minor] = NULL;
+ spin_unlock(&minors_lock);
+ result = PTR_ERR(dev->dev);
+ kfree(dev);
+ goto out;
+ }
+
+ init_waitqueue_head(&dev->wait);
+ INIT_LIST_HEAD(&dev->list);
+
+ dev->hid = hid;
+ dev->minor = minor;
+
+ dev->exist = 1;
+ hid->hidraw = dev;
+
+out:
+ return result;
+
+}
+EXPORT_SYMBOL_GPL(hidraw_connect);
+
+void hidraw_disconnect(struct hid_device *hid)
+{
+ struct hidraw *hidraw = hid->hidraw;
+
+ hidraw->exist = 0;
+
+ spin_lock(&minors_lock);
+ hidraw_table[hidraw->minor] = NULL;
+ spin_unlock(&minors_lock);
+
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
+ if (hidraw->open) {
+ hid->hid_close(hid);
+ wake_up_interruptible(&hidraw->wait);
+ } else {
+ kfree(hidraw);
+ }
+}
+EXPORT_SYMBOL_GPL(hidraw_disconnect);
+
+int __init hidraw_init(void)
+{
+ int result;
+ dev_t dev_id;
+
+ result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
+ HIDRAW_MAX_DEVICES, "hidraw");
+
+ hidraw_major = MAJOR(dev_id);
+
+ if (result < 0) {
+ printk(KERN_WARNING "hidraw: can't get major number\n");
+ result = 0;
+ goto out;
+ }
+
+ hidraw_class = class_create(THIS_MODULE, "hidraw");
+ if (IS_ERR(hidraw_class)) {
+ result = PTR_ERR(hidraw_class);
+ unregister_chrdev(hidraw_major, "hidraw");
+ goto out;
+ }
+
+ cdev_init(&hidraw_cdev, &hidraw_ops);
+ cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+out:
+ return result;
+}
+
+void __exit hidraw_exit(void)
+{
+ dev_t dev_id = MKDEV(hidraw_major, 0);
+
+ cdev_del(&hidraw_cdev);
+ class_destroy(hidraw_class);
+ unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+
+}
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 1b4b572f899..c557d7040a6 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -71,19 +71,20 @@ config LOGITECH_FF
force feedback.
config PANTHERLORD_FF
- bool "PantherLord USB/PS2 2in1 Adapter support"
+ bool "PantherLord/GreenAsia based device support"
depends on HID_FF
select INPUT_FF_MEMLESS if USB_HID
help
- Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
- to enable force feedback support for it.
+ Say Y here if you have a PantherLord/GreenAsia based game controller
+ or adapter and want to enable force feedback support for it.
config THRUSTMASTER_FF
- bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+ bool "ThrustMaster devices support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
select INPUT_FF_MEMLESS if USB_HID
help
- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+ a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
and want to enable force feedback support for it.
Note: if you say N here, this device will still be supported, but without
force feedback.
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 0a1f2b52a12..b38e559b7a4 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -32,6 +32,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
+#include <linux/hidraw.h>
#include "usbhid.h"
/*
@@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
int usbhid_open(struct hid_device *hid)
{
- ++hid->open;
+ struct usbhid_device *usbhid = hid->driver_data;
+ int res;
+
+ if (!hid->open++) {
+ res = usb_autopm_get_interface(usbhid->intf);
+ if (res < 0) {
+ hid->open--;
+ return -EIO;
+ }
+ }
if (hid_start_in(hid))
hid_io_error(hid);
return 0;
@@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- if (!--hid->open)
+ if (!--hid->open) {
usb_kill_urb(usbhid->urbin);
+ usb_autopm_put_interface(usbhid->intf);
+ }
}
/*
@@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = usbhid->intf;
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ HID_REQ_SET_REPORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),
+ interface->desc.bInterfaceNumber, buf + 1, count - 1,
+ USB_CTRL_SET_TIMEOUT);
+
+ /* count also the report id */
+ if (ret > 0)
+ ret++;
+
+ return ret;
+}
+
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
#endif
+ hid->hid_output_raw_report = usbhid_output_raw_report;
return hid;
fail:
@@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf)
hidinput_disconnect(hid);
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ hidraw_disconnect(hid);
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbctrl);
@@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
hid->claimed |= HID_CLAIMED_INPUT;
if (!hiddev_connect(hid))
hid->claimed |= HID_CLAIMED_HIDDEV;
+ if (!hidraw_connect(hid))
+ hid->claimed |= HID_CLAIMED_HIDRAW;
usb_set_intfdata(intf, hid);
if (!hid->claimed) {
- printk ("HID device not claimed by input or hiddev\n");
+ printk ("HID device claimed by neither input, hiddev nor hidraw\n");
hid_disconnect(intf);
return -ENODEV;
}
@@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (hid->claimed & HID_CLAIMED_INPUT)
printk("input");
- if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+ if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
+ hid->claimed & HID_CLAIMED_HIDRAW))
printk(",");
if (hid->claimed & HID_CLAIMED_HIDDEV)
printk("hiddev%d", hid->minor);
+ if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
+ (hid->claimed & HID_CLAIMED_HIDRAW))
+ printk(",");
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
c = "Device";
for (i = 0; i < hid->maxcollection; i++) {
@@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = {
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,
+ .supports_autosuspend = 1,
};
static int __init hid_init(void)
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
index 23431fbbc3d..22329feb3b5 100644
--- a/drivers/hid/usbhid/hid-ff.c
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -62,11 +62,14 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
#endif
#ifdef CONFIG_PANTHERLORD_FF
- { 0x810, 0x0001, hid_plff_init },
+ { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
+ { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
#endif
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb300, hid_tmff_init },
{ 0x44f, 0xb304, hid_tmff_init },
+ { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
+ { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
#endif
#ifdef CONFIG_ZEROPLUS_FF
{ 0xc12, 0x0005, hid_zpff_init },
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
index d6a8f2b49bd..9eb83cf9d22 100644
--- a/drivers/hid/usbhid/hid-plff.c
+++ b/drivers/hid/usbhid/hid-plff.c
@@ -1,5 +1,15 @@
/*
- * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ * Force feedback support for PantherLord/GreenAsia based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in both adapters and actual game controllers.
+ *
+ * 0810:0001 "Twin USB Joystick"
+ * - tested with PantherLord USB/PS2 2in1 Adapter
+ * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
+ *
+ * 0e8f:0003 "GreenAsia Inc. USB Joystick "
+ * - tested with Köng Gaming gamepad
*
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid)
struct input_dev *dev;
int error;
- /* The device contains 2 output reports (one for each
- HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
- contains 4 ff00.0002 usages and 4 16bit absolute values.
+ /* The device contains one output report per physical device, all
+ containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
+ absolute values.
- The 2 input reports also contain a field which contains
+ The input reports also contain a field which contains
8 ff00.0001 usages and 8 boolean values. Their meaning is
currently unknown. */
@@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid)
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
}
- printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
- "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+ "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 6b21a214f41..41a59a80e7e 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -61,6 +61,7 @@
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
#define USB_VENDOR_ID_ASUS 0x0b05
#define USB_DEVICE_ID_ASUS_LCM 0x1726
@@ -86,6 +87,9 @@
#define USB_VENDOR_ID_CIDC 0x1677
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CM109 0x000e
+
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
@@ -104,12 +108,17 @@
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
+#define USB_VENDOR_ID_ELO 0x04E7
+#define USB_DEVICE_ID_ELO_TS2700 0x0020
+
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
#define USB_VENDOR_ID_GAMERON 0x0810
#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
@@ -373,6 +382,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
@@ -387,11 +397,16 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
@@ -507,6 +522,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
@@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
+
{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
@@ -927,6 +945,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
printk(KERN_INFO "Fixing up Cypress report descriptor\n");
}
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
+{
+ if (rsize >= 60 && rdesc[53] == 0x65
+ && rdesc[59] == 0x65) {
+ printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
+ rdesc[53] = rdesc[59] = 0xe7;
+ }
+}
+
static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
{
@@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
if (quirks & HID_QUIRK_RDESC_PETALYNX)
usbhid_fixup_petalynx_descriptor(rdesc, rsize);
+
+ if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
+ usbhid_fixup_macbook_descriptor(rdesc, rsize);
}
/**
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index 555bb48b429..69882a726e9 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -36,16 +36,39 @@
#include "usbhid.h"
/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
+#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
+struct dev_type {
+ u16 idVendor;
+ u16 idProduct;
+ const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+ FF_RUMBLE,
+ -1
+};
+
+static const signed short ff_joystick[] = {
+ FF_CONSTANT,
+ -1
+};
+
+static const struct dev_type devices[] = {
+ { 0x44f, 0xb300, ff_rumble },
+ { 0x44f, 0xb304, ff_rumble },
+ { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */
+ { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
+};
struct tmff_device {
struct hid_report *report;
- struct hid_field *rumble;
+ struct hid_field *ff_field;
};
/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+static inline int hid_tmff_scale_u16(unsigned int in,
+ int minimum, int maximum)
{
int ret;
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
return ret;
}
+/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
+static inline int hid_tmff_scale_s8(int in,
+ int minimum, int maximum)
+{
+ int ret;
+
+ ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+ if (ret < minimum)
+ return minimum;
+ if (ret > maximum)
+ return maximum;
+ return ret;
+}
+
static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
+ struct hid_field *ff_field = tmff->ff_field;
+ int x, y;
int left, right; /* Rumbling */
- left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
- tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
- right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
- tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
- tmff->rumble->value[0] = left;
- tmff->rumble->value[1] = right;
- dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
- usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
+ switch (effect->type) {
+ case FF_CONSTANT:
+ x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+ y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+
+ dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+ ff_field->value[0] = x;
+ ff_field->value[1] = y;
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ break;
+
+ case FF_RUMBLE:
+ left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+ right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+
+ dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
+ ff_field->value[0] = left;
+ ff_field->value[1] = right;
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ break;
+ }
return 0;
}
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
struct list_head *pos;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
+ const signed short *ff_bits = ff_joystick;
int error;
+ int i;
tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
if (!tmff)
return -ENOMEM;
/* Find the report to use */
- __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+ list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
struct hid_report *report = (struct hid_report *)pos;
int fieldnum;
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
continue;
switch (field->usage[0].hid) {
- case THRUSTMASTER_USAGE_RUMBLE_LR:
- if (field->report_count < 2) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
- continue;
- }
+ case THRUSTMASTER_USAGE_FF:
+ if (field->report_count < 2) {
+ warn("ignoring FF field with report_count < 2");
+ continue;
+ }
- if (field->logical_maximum == field->logical_minimum) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
- continue;
- }
+ if (field->logical_maximum == field->logical_minimum) {
+ warn("ignoring FF field with logical_maximum == logical_minimum");
+ continue;
+ }
- if (tmff->report && tmff->report != report) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
- continue;
- }
+ if (tmff->report && tmff->report != report) {
+ warn("ignoring FF field in other report");
+ continue;
+ }
- if (tmff->rumble && tmff->rumble != field) {
- warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
- continue;
+ if (tmff->ff_field && tmff->ff_field != field) {
+ warn("ignoring duplicate FF field");
+ continue;
+ }
+
+ tmff->report = report;
+ tmff->ff_field = field;
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ if (input_dev->id.vendor == devices[i].idVendor &&
+ input_dev->id.product == devices[i].idProduct) {
+ ff_bits = devices[i].ff;
+ break;
}
+ }
- tmff->report = report;
- tmff->rumble = field;
+ for (i = 0; ff_bits[i] >= 0; i++)
+ set_bit(ff_bits[i], input_dev->ffbit);
- set_bit(FF_RUMBLE, input_dev->ffbit);
- break;
+ break;
- default:
- warn("ignoring unknown output usage %08x", field->usage[0].hid);
- continue;
+ default:
+ warn("ignoring unknown output usage %08x", field->usage[0].hid);
+ continue;
}
}
}
- error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
- if (error) {
- kfree(tmff);
- return error;
+ if (!tmff->report) {
+ err("cant find FF field in output reports\n");
+ error = -ENODEV;
+ goto fail;
}
- info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+ error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+ if (error)
+ goto fail;
+ info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
return 0;
+
+ fail:
+ kfree(tmff);
+ return error;
}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index e793127f971..9837adcb17e 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/compat.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -738,6 +739,14 @@ inval:
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ return hiddev_ioctl(inode, file, cmd, compat_ptr(arg));
+}
+#endif
+
static const struct file_operations hiddev_fops = {
.owner = THIS_MODULE,
.read = hiddev_read,
@@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = {
.release = hiddev_release,
.ioctl = hiddev_ioctl,
.fasync = hiddev_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hiddev_compat_ioctl,
+#endif
};
static struct usb_class_driver hiddev_class = {
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 192953b29b2..700a1657554 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -30,7 +30,7 @@ config HWMON_VID
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
- depends on EXPERIMENTAL
+ depends on X86 && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
@@ -45,7 +45,7 @@ config SENSORS_ABITUGURU
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
- depends on HWMON && EXPERIMENTAL
+ depends on X86 && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
@@ -133,6 +133,16 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_ADT7470
+ tristate "Analog Devices ADT7470"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7470 temperature monitoring chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7470.
+
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
@@ -148,6 +158,7 @@ config SENSORS_K8TEMP
config SENSORS_AMS
tristate "Apple Motion Sensor driver"
depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+ select INPUT_POLLDEV
help
Support for the motion sensor included in PowerBooks. Includes
implementations for PMU and I2C.
@@ -172,7 +183,7 @@ config SENSORS_AMS_I2C
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
- depends on I2C && EXPERIMENTAL
+ depends on X86 && I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
@@ -206,19 +217,39 @@ config SENSORS_DS1621
will be called ds1621.
config SENSORS_F71805F
- tristate "Fintek F71805F/FG and F71872F/FG"
+ tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
depends on EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
- features of the Fintek F71805F/FG and F71872F/FG Super-I/O
- chips.
+ features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
+ Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called f71805f.
+config SENSORS_F71882FG
+ tristate "Fintek F71882FG and F71883FG"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for hardware monitoring
+ features of the Fintek F71882FG and F71883FG Super-I/O chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called f71882fg.
+
+config SENSORS_F75375S
+ tristate "Fintek F75375S/SP and F75373";
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for hardware monitoring
+ features of the Fintek F75375S/SP and F75373
+
+ This driver can also be built as a module. If so, the module
+ will be called f75375s.
+
config SENSORS_FSCHER
tristate "FSC Hermes"
- depends on I2C
+ depends on X86 && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -228,7 +259,7 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
- depends on I2C
+ depends on X86 && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -236,6 +267,20 @@ config SENSORS_FSCPOS
This driver can also be built as a module. If so, the module
will be called fscpos.
+config SENSORS_FSCHMD
+ tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
+ depends on X86 && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for various Fujitsu Siemens
+ Computers sensor chips.
+
+ This is a new merged driver for FSC sensor chips which is intended
+ as a replacment for the fscpos, fscscy and fscher drivers and adds
+ support for several other FCS sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called fschmd.
+
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on I2C
@@ -265,6 +310,19 @@ config SENSORS_CORETEMP
sensor inside your CPU. Supported all are all known variants
of Intel Core family.
+config SENSORS_IBMPEX
+ tristate "IBM PowerExecutive temperature/power sensors"
+ select IPMI_SI
+ depends on IPMI_HANDLER
+ help
+ If you say yes here you get support for the temperature and
+ power sensors in various IBM System X servers that support
+ PowerExecutive. So far this includes the x3550, x3650, x3655,
+ x3755, and certain HS20 blades.
+
+ This driver can also be built as a module. If so, the module
+ will be called ibmpex.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
select HWMON_VID
@@ -401,7 +459,7 @@ config SENSORS_LM92
config SENSORS_LM93
tristate "National Semiconductor LM93 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM93
@@ -466,13 +524,13 @@ config SENSORS_SIS5595
will be called sis5595.
config SENSORS_DME1737
- tristate "SMSC DME1737 and compatibles"
+ tristate "SMSC DME1737, SCH311x and compatibles"
depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles
- like the Asus A8000) Super-I/O chip.
+ like the Asus A8000) and SCH311x Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called dme1737.
@@ -644,6 +702,7 @@ config SENSORS_W83627EHF
config SENSORS_HDAPS
tristate "IBM Hard Drive Active Protection System (hdaps)"
depends on INPUT && X86
+ select INPUT_POLLDEV
default n
help
This driver provides support for the IBM Hard Drive Active Protection
@@ -665,6 +724,7 @@ config SENSORS_APPLESMC
depends on INPUT && X86
select NEW_LEDS
select LEDS_CLASS
+ select INPUT_POLLDEV
default n
help
This driver provides support for the Apple System Management
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d04f90031eb..6da3eef9430 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
@@ -29,11 +30,15 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
+obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
+obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
+obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
+obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 2317f4bb9c9..4dbdb81ea3b 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
The structure is dynamically allocated, at the same time when a new
abituguru device is allocated. */
struct abituguru_data {
- struct class_device *class_dev; /* hwmon registered device */
+ struct device *hwmon_dev; /* hwmon registered device */
struct mutex update_lock; /* protect access to data and uGuru */
unsigned long last_updated; /* In jiffies */
unsigned short addr; /* uguru base address */
@@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
&abituguru_sysfs_attr[i].dev_attr))
goto abituguru_probe_error;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (!IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (!IS_ERR(data->hwmon_dev))
return 0; /* success */
- res = PTR_ERR(data->class_dev);
+ res = PTR_ERR(data->hwmon_dev);
abituguru_probe_error:
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
@@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index cdd8b6dea16..cb2331bfd9d 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -124,7 +124,7 @@ struct abituguru3_motherboard_info {
The structure is dynamically allocated, at the same time when a new
abituguru3 device is allocated. */
struct abituguru3_data {
- struct class_device *class_dev; /* hwmon registered device */
+ struct device *hwmon_dev; /* hwmon registered device */
struct mutex update_lock; /* protect access to data and uGuru */
unsigned short addr; /* uguru base address */
char valid; /* !=0 if following fields are valid */
@@ -933,9 +933,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
&abituguru3_sysfs_attr[i].dev_attr))
goto abituguru3_probe_error;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- res = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ res = PTR_ERR(data->hwmon_dev);
goto abituguru3_probe_error;
}
@@ -957,7 +957,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
struct abituguru3_data *data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index cc8b624a1e5..fcd7fe78f3f 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
struct ad7418_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct attribute_group attrs;
enum chips type;
struct mutex lock;
@@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct ad7418_data *data = i2c_get_clientdata(client);
- int temp = simple_strtol(buf, NULL, 10);
+ long temp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->lock);
data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
@@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -347,7 +347,7 @@ exit:
static int ad7418_detach_client(struct i2c_client *client)
{
struct ad7418_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index c466329b2ef..ebdc6d7db23 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -1,6 +1,6 @@
/*
adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
+ monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
@@ -25,6 +25,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -32,93 +33,77 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
+ 0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
/* Insmod parameters */
-I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm,
+ mc1066);
/* adm1021 constants specified below */
/* The adm1021 registers */
/* Read-only */
-#define ADM1021_REG_TEMP 0x00
-#define ADM1021_REG_REMOTE_TEMP 0x01
+/* For nr in 0-1 */
+#define ADM1021_REG_TEMP(nr) (nr)
#define ADM1021_REG_STATUS 0x02
-#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/
-#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */
-#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */
+/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
+#define ADM1021_REG_MAN_ID 0xFE
+/* ADM1021 = 0x0X, ADM1023 = 0x3X */
+#define ADM1021_REG_DEV_ID 0xFF
/* These use different addresses for reading/writing */
#define ADM1021_REG_CONFIG_R 0x03
#define ADM1021_REG_CONFIG_W 0x09
#define ADM1021_REG_CONV_RATE_R 0x04
#define ADM1021_REG_CONV_RATE_W 0x0A
/* These are for the ADM1023's additional precision on the remote temp sensor */
-#define ADM1021_REG_REM_TEMP_PREC 0x010
-#define ADM1021_REG_REM_OFFSET 0x011
-#define ADM1021_REG_REM_OFFSET_PREC 0x012
-#define ADM1021_REG_REM_TOS_PREC 0x013
-#define ADM1021_REG_REM_THYST_PREC 0x014
+#define ADM1023_REG_REM_TEMP_PREC 0x10
+#define ADM1023_REG_REM_OFFSET 0x11
+#define ADM1023_REG_REM_OFFSET_PREC 0x12
+#define ADM1023_REG_REM_TOS_PREC 0x13
+#define ADM1023_REG_REM_THYST_PREC 0x14
/* limits */
-#define ADM1021_REG_TOS_R 0x05
-#define ADM1021_REG_TOS_W 0x0B
-#define ADM1021_REG_REMOTE_TOS_R 0x07
-#define ADM1021_REG_REMOTE_TOS_W 0x0D
-#define ADM1021_REG_THYST_R 0x06
-#define ADM1021_REG_THYST_W 0x0C
-#define ADM1021_REG_REMOTE_THYST_R 0x08
-#define ADM1021_REG_REMOTE_THYST_W 0x0E
+/* For nr in 0-1 */
+#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr))
+#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr))
+#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr))
+#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr))
/* write-only */
#define ADM1021_REG_ONESHOT 0x0F
-
-/* Conversions. Rounding and limit checking is only done on the TO_REG
- variants. Note that you should be a bit careful with which arguments
- these macros are called: arguments may be evaluated more than once.
- Fixing this is just not worth it. */
-/* Conversions note: 1021 uses normal integer signed-byte format*/
-#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000)
-#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255))
-
/* Initial values */
-/* Note: Even though I left the low and high limits named os and hyst,
-they don't quite work like a thermostat the way the LM75 does. I.e.,
-a lower temp than THYST actually triggers an alarm instead of
+/* Note: Even though I left the low and high limits named os and hyst,
+they don't quite work like a thermostat the way the LM75 does. I.e.,
+a lower temp than THYST actually triggers an alarm instead of
clearing it. Weird, ey? --Phil */
/* Each client has this additional data */
struct adm1021_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u8 temp_max; /* Register values */
- u8 temp_hyst;
- u8 temp_input;
- u8 remote_temp_max;
- u8 remote_temp_hyst;
- u8 remote_temp_input;
- u8 alarms;
- /* Special values for ADM1023 only */
- u8 remote_temp_prec;
- u8 remote_temp_os_prec;
- u8 remote_temp_hyst_prec;
- u8 remote_temp_offset;
- u8 remote_temp_offset_prec;
+ s8 temp_max[2]; /* Register values */
+ s8 temp_min[2];
+ s8 temp[2];
+ u8 alarms;
+ /* Special values for ADM1023 only */
+ u8 remote_temp_prec;
+ u8 remote_temp_os_prec;
+ u8 remote_temp_hyst_prec;
+ u8 remote_temp_offset;
+ u8 remote_temp_offset_prec;
};
static int adm1021_attach_adapter(struct i2c_adapter *adapter);
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
static void adm1021_init_client(struct i2c_client *client);
static int adm1021_detach_client(struct i2c_client *client);
-static int adm1021_read_value(struct i2c_client *client, u8 reg);
-static int adm1021_write_value(struct i2c_client *client, u8 reg,
- u16 value);
static struct adm1021_data *adm1021_update_device(struct device *dev);
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
@@ -135,53 +120,104 @@ static struct i2c_driver adm1021_driver = {
.detach_client = adm1021_detach_client,
};
-#define show(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1021_data *data = adm1021_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp[index]);
}
-show(temp_max);
-show(temp_hyst);
-show(temp_input);
-show(remote_temp_max);
-show(remote_temp_hyst);
-show(remote_temp_input);
-
-#define show2(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1021_data *data = adm1021_update_device(dev); \
- return sprintf(buf, "%d\n", data->value); \
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp_max[index]);
}
-show2(alarms);
-
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1021_data *data = i2c_get_clientdata(client); \
- int temp = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->value = TEMP_TO_REG(temp); \
- adm1021_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp_min[index]);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adm1021_data *data = adm1021_update_device(dev);
+ return sprintf(buf, "%u\n", data->alarms);
}
-set(temp_max, ADM1021_REG_TOS_W);
-set(temp_hyst, ADM1021_REG_THYST_W);
-set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W);
-set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W);
-
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1021_data *data = i2c_get_clientdata(client);
+ long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->update_lock);
+ data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+ if (!read_only)
+ i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
+ data->temp_max[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1021_data *data = i2c_get_clientdata(client);
+ long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->update_lock);
+ data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+ if (!read_only)
+ i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
+ data->temp_min[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
{
@@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *adm1021_attributes[] = {
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp2_input.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&dev_attr_alarms.attr,
NULL
};
@@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = {
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct adm1021_data *data;
int err = 0;
const char *type_name = "";
+ int conv_rate, status, config;
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_debug("adm1021: detect failed, "
+ "smbus byte data not supported!\n");
goto error0;
+ }
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
- But it allows us to access adm1021_{read,write}_value. */
+ But it allows us to access adm1021 register values. */
if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
+ pr_debug("adm1021: detect failed, kzalloc failed!\n");
err = -ENOMEM;
goto error0;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm1021_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1021_driver;
+ status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
+ conv_rate = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_CONV_RATE_R);
+ config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
/* Now, we do the remaining detection. */
if (kind < 0) {
- if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00
- || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00
- || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) {
+ if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00
+ || (conv_rate & 0xF8) != 0x00) {
+ pr_debug("adm1021: detect failed, "
+ "chip not detected!\n");
err = -ENODEV;
goto error1;
}
@@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
/* Determine the chip type. */
if (kind <= 0) {
- i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID);
+ i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
if (i == 0x41)
- if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030)
+ if ((i2c_smbus_read_byte_data(client,
+ ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
kind = adm1023;
else
kind = adm1021;
@@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
else if (i == 0x23)
kind = gl523sm;
else if ((i == 0x4d) &&
- (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01))
+ (i2c_smbus_read_byte_data(client,
+ ADM1021_REG_DEV_ID) == 0x01))
kind = max1617a;
else if (i == 0x54)
kind = mc1066;
/* LM84 Mfr ID in a different place, and it has more unused bits */
- else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00
- && (kind == 0 /* skip extra detection */
- || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00
- && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00)))
+ else if (conv_rate == 0x00
+ && (kind == 0 /* skip extra detection */
+ || ((config & 0x7F) == 0x00
+ && (status & 0xAB) == 0x00)))
kind = lm84;
else
kind = max1617;
@@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
} else if (kind == mc1066) {
type_name = "mc1066";
}
+ pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
+ type_name, i2c_adapter_id(adapter), address);
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+ /* Fill in the remaining client fields */
+ strlcpy(client->name, type_name, I2C_NAME_SIZE);
data->type = kind;
- data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto error1;
/* Initialize the ADM1021 chip */
- if (kind != lm84)
- adm1021_init_client(new_client);
+ if (kind != lm84 && !read_only)
+ adm1021_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
goto error2;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error3;
}
return 0;
error3:
- sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1021_group);
error2:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
error1:
kfree(data);
error0:
@@ -326,10 +379,10 @@ error0:
static void adm1021_init_client(struct i2c_client *client)
{
/* Enable ADC and disable suspend mode */
- adm1021_write_value(client, ADM1021_REG_CONFIG_W,
- adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF);
+ i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
+ i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
/* Set Conversion rate to 1/sec (this can be tinkered with) */
- adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04);
+ i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
}
static int adm1021_detach_client(struct i2c_client *client)
@@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client)
struct adm1021_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
if ((err = i2c_detach_client(client)))
@@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client)
return 0;
}
-/* All registers are byte-sized */
-static int adm1021_read_value(struct i2c_client *client, u8 reg)
-{
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
- if (!read_only)
- return i2c_smbus_write_byte_data(client, reg, value);
- return 0;
-}
-
static struct adm1021_data *adm1021_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
+ int i;
+
dev_dbg(&client->dev, "Starting adm1021 update\n");
- data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP);
- data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R);
- data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R);
- data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
- data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
- data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
- data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
+ for (i = 0; i < 2; i++) {
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_TEMP(i));
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_TOS_R(i));
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_THYST_R(i));
+ }
+ data->alarms = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_STATUS) & 0x7c;
if (data->type == adm1023) {
- data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
- data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
- data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC);
- data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET);
- data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC);
+ data->remote_temp_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_TEMP_PREC);
+ data->remote_temp_os_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_TOS_PREC);
+ data->remote_temp_hyst_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_THYST_PREC);
+ data->remote_temp_offset =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_OFFSET);
+ data->remote_temp_offset_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_OFFSET_PREC);
}
data->last_updated = jiffies;
data->valid = 1;
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 8c562885b54..041ecb0bdf4 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = {
struct adm1025_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -292,7 +292,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct adm1025_data *data = adm1025_update_device(dev);
+ struct adm1025_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client)
struct adm1025_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index ba80cd3258c..aa875ca50d9 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -260,7 +260,7 @@ struct pwm_data {
struct adm1026_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -1221,7 +1221,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct adm1026_data *data = adm1026_update_device(dev);
+ struct adm1026_data *data = dev_get_drvdata(dev);
return sprintf(buf,"%d\n", data->vrm);
}
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
goto exitdetach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exitremove;
}
@@ -1698,7 +1698,7 @@ exit:
static int adm1026_detach_client(struct i2c_client *client)
{
struct adm1026_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 73ce31b3151..0bc897dffa2 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = {
struct adm1029_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client)
struct adm1029_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 122683fc91d..37cfc101da5 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2];
/* Each client has this additional data */
struct adm1031_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
int chip_type;
char valid; /* !=0 if following fields are valid */
@@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client)
struct adm1031_data *data = i2c_get_clientdata(client);
int ret;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
if ((ret = i2c_detach_client(client)) != 0) {
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index aad594adf0c..c17d0b6b328 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = {
struct adm9240_data {
enum chips type;
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid;
unsigned long last_updated_measure;
@@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client)
struct adm9240_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
new file mode 100644
index 00000000000..9810aaa0489
--- /dev/null
+++ b/drivers/hwmon/adt7470.c
@@ -0,0 +1,1050 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7470
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(adt7470);
+
+/* ADT7470 registers */
+#define ADT7470_REG_BASE_ADDR 0x20
+#define ADT7470_REG_TEMP_BASE_ADDR 0x20
+#define ADT7470_REG_TEMP_MAX_ADDR 0x29
+#define ADT7470_REG_FAN_BASE_ADDR 0x2A
+#define ADT7470_REG_FAN_MAX_ADDR 0x31
+#define ADT7470_REG_PWM_BASE_ADDR 0x32
+#define ADT7470_REG_PWM_MAX_ADDR 0x35
+#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38
+#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B
+#define ADT7470_REG_CFG 0x40
+#define ADT7470_FSPD_MASK 0x04
+#define ADT7470_REG_ALARM1 0x41
+#define ADT7470_REG_ALARM2 0x42
+#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44
+#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57
+#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58
+#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F
+#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60
+#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67
+#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68
+#define ADT7470_REG_PWM12_CFG 0x68
+#define ADT7470_PWM2_AUTO_MASK 0x40
+#define ADT7470_PWM1_AUTO_MASK 0x80
+#define ADT7470_REG_PWM34_CFG 0x69
+#define ADT7470_PWM3_AUTO_MASK 0x40
+#define ADT7470_PWM4_AUTO_MASK 0x80
+#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A
+#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D
+#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
+#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71
+#define ADT7470_REG_ACOUSTICS12 0x75
+#define ADT7470_REG_ACOUSTICS34 0x76
+#define ADT7470_REG_DEVICE 0x3D
+#define ADT7470_REG_VENDOR 0x3E
+#define ADT7470_REG_REVISION 0x3F
+#define ADT7470_REG_ALARM1_MASK 0x72
+#define ADT7470_REG_ALARM2_MASK 0x73
+#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C
+#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D
+#define ADT7470_REG_MAX_ADDR 0x81
+
+#define ADT7470_TEMP_COUNT 10
+#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x))
+#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
+#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
+ ((x) * 2) + 1)
+
+#define ADT7470_FAN_COUNT 4
+#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
+
+#define ADT7470_PWM_COUNT 4
+#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
+#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
+ ((x) / 2))
+
+#define ADT7470_VENDOR 0x41
+#define ADT7470_DEVICE 0x70
+/* datasheet only mentions a revision 2 */
+#define ADT7470_REVISION 0x02
+
+/* "all temps" according to hwmon sysfs interface spec */
+#define ADT7470_PWM_ALL_TEMPS 0x3FF
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL (5 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+/* sleep 1s while gathering temperature data */
+#define TEMP_COLLECTION_TIME 1000
+
+#define power_of_2(x) (((x) & ((x) - 1)) == 0)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID 65535
+#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
+
+struct adt7470_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct attribute_group attrs;
+ struct mutex lock;
+ char sensors_valid;
+ char limits_valid;
+ unsigned long sensors_last_updated; /* In jiffies */
+ unsigned long limits_last_updated; /* In jiffies */
+
+ s8 temp[ADT7470_TEMP_COUNT];
+ s8 temp_min[ADT7470_TEMP_COUNT];
+ s8 temp_max[ADT7470_TEMP_COUNT];
+ u16 fan[ADT7470_FAN_COUNT];
+ u16 fan_min[ADT7470_FAN_COUNT];
+ u16 fan_max[ADT7470_FAN_COUNT];
+ u16 alarms, alarms_mask;
+ u8 force_pwm_max;
+ u8 pwm[ADT7470_PWM_COUNT];
+ u8 pwm_max[ADT7470_PWM_COUNT];
+ u8 pwm_automatic[ADT7470_PWM_COUNT];
+ u8 pwm_min[ADT7470_PWM_COUNT];
+ s8 pwm_tmin[ADT7470_PWM_COUNT];
+ u8 pwm_auto_temp[ADT7470_PWM_COUNT];
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter);
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adt7470_detach_client(struct i2c_client *client);
+
+static struct i2c_driver adt7470_driver = {
+ .driver = {
+ .name = "adt7470",
+ },
+ .attach_adapter = adt7470_attach_adapter,
+ .detach_client = adt7470_detach_client,
+};
+
+/*
+ * 16-bit registers on the ADT7470 are low-byte first. The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg)
+{
+ u16 foo;
+ foo = i2c_smbus_read_byte_data(client, reg);
+ foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+ return foo;
+}
+
+static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
+ u16 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
+ && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+}
+
+static void adt7470_init_client(struct i2c_client *client)
+{
+ int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+
+ if (reg < 0) {
+ dev_err(&client->dev, "cannot read configuration register\n");
+ } else {
+ /* start monitoring (and do a self-test) */
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
+ }
+}
+
+static struct adt7470_data *adt7470_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ unsigned long local_jiffies = jiffies;
+ u8 cfg;
+ int i;
+
+ mutex_lock(&data->lock);
+ if (time_before(local_jiffies, data->sensors_last_updated +
+ SENSOR_REFRESH_INTERVAL)
+ && data->sensors_valid)
+ goto no_sensor_update;
+
+ /* start reading temperature sensors */
+ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ cfg |= 0x80;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+ /*
+ * Delay is 200ms * number of tmp05 sensors. Too bad
+ * there's no way to figure out how many are connected.
+ * For now, assume 1s will work.
+ */
+ msleep(TEMP_COLLECTION_TIME);
+
+ /* done reading temperature sensors */
+ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ cfg &= ~0x80;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+ for (i = 0; i < ADT7470_TEMP_COUNT; i++)
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_REG(i));
+
+ for (i = 0; i < ADT7470_FAN_COUNT; i++)
+ data->fan[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN(i));
+
+ for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+ int reg;
+ int reg_mask;
+
+ data->pwm[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM(i));
+
+ if (i % 2)
+ reg_mask = ADT7470_PWM2_AUTO_MASK;
+ else
+ reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+ reg = ADT7470_REG_PWM_CFG(i);
+ if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
+ data->pwm_automatic[i] = 1;
+ else
+ data->pwm_automatic[i] = 0;
+
+ reg = ADT7470_REG_PWM_AUTO_TEMP(i);
+ cfg = i2c_smbus_read_byte_data(client, reg);
+ if (!(i % 2))
+ data->pwm_auto_temp[i] = cfg >> 4;
+ else
+ data->pwm_auto_temp[i] = cfg & 0xF;
+ }
+
+ if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) &
+ ADT7470_FSPD_MASK)
+ data->force_pwm_max = 1;
+ else
+ data->force_pwm_max = 0;
+
+ data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1);
+ data->alarms_mask = adt7470_read_word_data(client,
+ ADT7470_REG_ALARM1_MASK);
+
+ data->sensors_last_updated = local_jiffies;
+ data->sensors_valid = 1;
+
+no_sensor_update:
+ if (time_before(local_jiffies, data->limits_last_updated +
+ LIMIT_REFRESH_INTERVAL)
+ && data->limits_valid)
+ goto out;
+
+ for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_MIN_REG(i));
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_MAX_REG(i));
+ }
+
+ for (i = 0; i < ADT7470_FAN_COUNT; i++) {
+ data->fan_min[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN_MIN(i));
+ data->fan_max[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN_MAX(i));
+ }
+
+ for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+ data->pwm_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_MAX(i));
+ data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_MIN(i));
+ data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_TMIN(i));
+ }
+
+ data->limits_last_updated = local_jiffies;
+ data->limits_valid = 1;
+
+out:
+ mutex_unlock(&data->lock);
+ return data;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
+}
+
+static ssize_t set_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->temp_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->temp_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (attr->index)
+ return sprintf(buf, "%x\n", data->alarms);
+ else
+ return sprintf(buf, "%x\n", data->alarms_mask);
+}
+
+static ssize_t show_fan_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan_max[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ if (!temp)
+ return -EINVAL;
+ temp = FAN_RPM_TO_PERIOD(temp);
+
+ mutex_lock(&data->lock);
+ data->fan_max[attr->index] = temp;
+ adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan_min[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ if (!temp)
+ return -EINVAL;
+ temp = FAN_RPM_TO_PERIOD(temp);
+
+ mutex_lock(&data->lock);
+ data->fan_min[attr->index] = temp;
+ adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->force_pwm_max);
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+ u8 reg;
+
+ mutex_lock(&data->lock);
+ data->force_pwm_max = temp;
+ reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ if (temp)
+ reg |= ADT7470_FSPD_MASK;
+ else
+ reg &= ~ADT7470_FSPD_MASK;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ /* the datasheet says that tmax = tmin + 20C */
+ return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->pwm_tmin[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+ int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
+ int pwm_auto_reg_mask;
+ u8 reg;
+
+ if (attr->index % 2)
+ pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
+ else
+ pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+ if (temp != 2 && temp != 1)
+ return -EINVAL;
+ temp--;
+
+ mutex_lock(&data->lock);
+ data->pwm_automatic[attr->index] = temp;
+ reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+ if (temp)
+ reg |= pwm_auto_reg_mask;
+ else
+ reg &= ~pwm_auto_reg_mask;
+ i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ u8 ctrl = data->pwm_auto_temp[attr->index];
+
+ if (ctrl)
+ return sprintf(buf, "%d\n", 1 << (ctrl - 1));
+ else
+ return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
+}
+
+static int cvt_auto_temp(int input)
+{
+ if (input == ADT7470_PWM_ALL_TEMPS)
+ return 0;
+ if (input < 1 || !power_of_2(input))
+ return -EINVAL;
+ return ilog2(input) + 1;
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
+ int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+ u8 reg;
+
+ if (temp < 0)
+ return temp;
+
+ mutex_lock(&data->lock);
+ data->pwm_automatic[attr->index] = temp;
+ reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+
+ if (!(attr->index % 2)) {
+ reg &= 0xF;
+ reg |= (temp << 4) & 0xF0;
+ } else {
+ reg &= 0xF0;
+ reg |= temp & 0xF;
+ }
+
+ i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0);
+static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 7);
+static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 8);
+static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 4);
+static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 5);
+static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 6);
+static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 7);
+static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 8);
+static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
+
+static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 0);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 1);
+static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 2);
+static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+ show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7470_attr[] =
+{
+ &sensor_dev_attr_alarms.dev_attr.attr,
+ &sensor_dev_attr_alarm_mask.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp7_max.dev_attr.attr,
+ &sensor_dev_attr_temp8_max.dev_attr.attr,
+ &sensor_dev_attr_temp9_max.dev_attr.attr,
+ &sensor_dev_attr_temp10_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp5_min.dev_attr.attr,
+ &sensor_dev_attr_temp6_min.dev_attr.attr,
+ &sensor_dev_attr_temp7_min.dev_attr.attr,
+ &sensor_dev_attr_temp8_min.dev_attr.attr,
+ &sensor_dev_attr_temp9_min.dev_attr.attr,
+ &sensor_dev_attr_temp10_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp7_input.dev_attr.attr,
+ &sensor_dev_attr_temp8_input.dev_attr.attr,
+ &sensor_dev_attr_temp9_input.dev_attr.attr,
+ &sensor_dev_attr_temp10_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_max.dev_attr.attr,
+ &sensor_dev_attr_fan2_max.dev_attr.attr,
+ &sensor_dev_attr_fan3_max.dev_attr.attr,
+ &sensor_dev_attr_fan4_max.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_force_pwm_max.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+ NULL
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, adt7470_detect);
+}
+
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct adt7470_data *data;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adt7470_driver;
+
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ if (kind <= 0) {
+ int vendor, device, revision;
+
+ vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
+ if (vendor != ADT7470_VENDOR) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
+ if (device != ADT7470_DEVICE) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ revision = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_REVISION);
+ if (revision != ADT7470_REVISION) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+ } else
+ dev_dbg(&adapter->dev, "detection forced\n");
+
+ strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
+
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ dev_info(&client->dev, "%s chip found\n", client->name);
+
+ /* Initialize the ADT7470 chip */
+ adt7470_init_client(client);
+
+ /* Register sysfs hooks */
+ data->attrs.attrs = adt7470_attr;
+ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
+ goto exit_detach;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int adt7470_detach_client(struct i2c_client *client)
+{
+ struct adt7470_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
+static int __init adt7470_init(void)
+{
+ return i2c_add_driver(&adt7470_driver);
+}
+
+static void __exit adt7470_exit(void)
+{
+ i2c_del_driver(&adt7470_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ADT7470 driver");
+MODULE_LICENSE("GPL");
+
+module_init(adt7470_init);
+module_exit(adt7470_exit);
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index ca7095d96ad..7b81e0c2c2d 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -27,47 +27,32 @@ static unsigned int invert;
module_param(invert, bool, 0644);
MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
-static int ams_input_kthread(void *data)
+static void ams_idev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *idev = dev->input;
s8 x, y, z;
- while (!kthread_should_stop()) {
- mutex_lock(&ams_info.lock);
-
- ams_sensors(&x, &y, &z);
-
- x -= ams_info.xcalib;
- y -= ams_info.ycalib;
- z -= ams_info.zcalib;
-
- input_report_abs(ams_info.idev, ABS_X, invert ? -x : x);
- input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y);
- input_report_abs(ams_info.idev, ABS_Z, z);
+ mutex_lock(&ams_info.lock);
- input_sync(ams_info.idev);
+ ams_sensors(&x, &y, &z);
- mutex_unlock(&ams_info.lock);
+ x -= ams_info.xcalib;
+ y -= ams_info.ycalib;
+ z -= ams_info.zcalib;
- msleep(25);
- }
+ input_report_abs(idev, ABS_X, invert ? -x : x);
+ input_report_abs(idev, ABS_Y, invert ? -y : y);
+ input_report_abs(idev, ABS_Z, z);
- return 0;
-}
+ input_sync(idev);
-static int ams_input_open(struct input_dev *dev)
-{
- ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams");
- return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0;
-}
-
-static void ams_input_close(struct input_dev *dev)
-{
- kthread_stop(ams_info.kthread);
+ mutex_unlock(&ams_info.lock);
}
/* Call with ams_info.lock held! */
static void ams_input_enable(void)
{
+ struct input_dev *input;
s8 x, y, z;
if (ams_info.idev)
@@ -78,27 +63,29 @@ static void ams_input_enable(void)
ams_info.ycalib = y;
ams_info.zcalib = z;
- ams_info.idev = input_allocate_device();
+ ams_info.idev = input_allocate_polled_device();
if (!ams_info.idev)
return;
- ams_info.idev->name = "Apple Motion Sensor";
- ams_info.idev->id.bustype = ams_info.bustype;
- ams_info.idev->id.vendor = 0;
- ams_info.idev->open = ams_input_open;
- ams_info.idev->close = ams_input_close;
- ams_info.idev->dev.parent = &ams_info.of_dev->dev;
+ ams_info.idev->poll = ams_idev_poll;
+ ams_info.idev->poll_interval = 25;
+
+ input = ams_info.idev->input;
+ input->name = "Apple Motion Sensor";
+ input->id.bustype = ams_info.bustype;
+ input->id.vendor = 0;
+ input->dev.parent = &ams_info.of_dev->dev;
- input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
- input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
- input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
- set_bit(EV_ABS, ams_info.idev->evbit);
- set_bit(EV_KEY, ams_info.idev->evbit);
- set_bit(BTN_TOUCH, ams_info.idev->keybit);
+ set_bit(EV_ABS, input->evbit);
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
- if (input_register_device(ams_info.idev)) {
- input_free_device(ams_info.idev);
+ if (input_register_polled_device(ams_info.idev)) {
+ input_free_polled_device(ams_info.idev);
ams_info.idev = NULL;
return;
}
@@ -108,7 +95,8 @@ static void ams_input_enable(void)
static void ams_input_disable(void)
{
if (ams_info.idev) {
- input_unregister_device(ams_info.idev);
+ input_unregister_polled_device(ams_info.idev);
+ input_free_polled_device(ams_info.idev);
ams_info.idev = NULL;
}
}
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
index 240730e6bcd..a6221e5dd98 100644
--- a/drivers/hwmon/ams/ams.h
+++ b/drivers/hwmon/ams/ams.h
@@ -1,5 +1,5 @@
#include <linux/i2c.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
@@ -52,8 +52,7 @@ struct ams {
#endif
/* Joystick emulation */
- struct task_struct *kthread;
- struct input_dev *idev;
+ struct input_polled_dev *idev;
__u16 bustype;
/* calibrated null values */
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 56213b7f818..4879125b4cd 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -28,7 +28,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
@@ -59,9 +59,9 @@
#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
-#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
+#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
-#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
+#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
@@ -103,7 +103,7 @@ static const char* fan_speed_keys[] = {
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
-#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define APPLESMC_POLL_INTERVAL 50 /* msecs */
#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
#define APPLESMC_INPUT_FLAT 4
@@ -125,9 +125,8 @@ static const int debug;
static struct platform_device *pdev;
static s16 rest_x;
static s16 rest_y;
-static struct timer_list applesmc_timer;
-static struct input_dev *applesmc_idev;
-static struct class_device *hwmon_class_dev;
+static struct device *hwmon_dev;
+static struct input_polled_dev *applesmc_idev;
/* Indicates whether this computer has an accelerometer. */
static unsigned int applesmc_accelerometer;
@@ -138,7 +137,7 @@ static unsigned int applesmc_light;
/* Indicates which temperature sensors set to use. */
static unsigned int applesmc_temperature_set;
-static struct mutex applesmc_lock;
+static DEFINE_MUTEX(applesmc_lock);
/*
* Last index written to key_at_index sysfs file, and value to use for all other
@@ -455,27 +454,12 @@ static void applesmc_calibrate(void)
rest_x = -rest_x;
}
-static int applesmc_idev_open(struct input_dev *dev)
-{
- add_timer(&applesmc_timer);
-
- return 0;
-}
-
-static void applesmc_idev_close(struct input_dev *dev)
-{
- del_timer_sync(&applesmc_timer);
-}
-
-static void applesmc_idev_poll(unsigned long unused)
+static void applesmc_idev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *idev = dev->input;
s16 x, y;
- /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (!mutex_trylock(&applesmc_lock)) {
- mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
- return;
- }
+ mutex_lock(&applesmc_lock);
if (applesmc_read_motion_sensor(SENSOR_X, &x))
goto out;
@@ -483,13 +467,11 @@ static void applesmc_idev_poll(unsigned long unused)
goto out;
x = -x;
- input_report_abs(applesmc_idev, ABS_X, x - rest_x);
- input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
- input_sync(applesmc_idev);
+ input_report_abs(idev, ABS_X, x - rest_x);
+ input_report_abs(idev, ABS_Y, y - rest_y);
+ input_sync(idev);
out:
- mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
-
mutex_unlock(&applesmc_lock);
}
@@ -821,8 +803,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
if (!ret) {
return info[0];
- }
- else {
+ } else {
return ret;
}
}
@@ -1093,6 +1074,7 @@ static int applesmc_dmi_match(const struct dmi_system_id *id)
/* Create accelerometer ressources */
static int applesmc_create_accelerometer(void)
{
+ struct input_dev *idev;
int ret;
ret = sysfs_create_group(&pdev->dev.kobj,
@@ -1100,40 +1082,37 @@ static int applesmc_create_accelerometer(void)
if (ret)
goto out;
- applesmc_idev = input_allocate_device();
+ applesmc_idev = input_allocate_polled_device();
if (!applesmc_idev) {
ret = -ENOMEM;
goto out_sysfs;
}
+ applesmc_idev->poll = applesmc_idev_poll;
+ applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
+
/* initial calibrate for the input device */
applesmc_calibrate();
- /* initialize the input class */
- applesmc_idev->name = "applesmc";
- applesmc_idev->id.bustype = BUS_HOST;
- applesmc_idev->dev.parent = &pdev->dev;
- applesmc_idev->evbit[0] = BIT(EV_ABS);
- applesmc_idev->open = applesmc_idev_open;
- applesmc_idev->close = applesmc_idev_close;
- input_set_abs_params(applesmc_idev, ABS_X,
+ /* initialize the input device */
+ idev = applesmc_idev->input;
+ idev->name = "applesmc";
+ idev->id.bustype = BUS_HOST;
+ idev->dev.parent = &pdev->dev;
+ idev->evbit[0] = BIT(EV_ABS);
+ input_set_abs_params(idev, ABS_X,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
- input_set_abs_params(applesmc_idev, ABS_Y,
+ input_set_abs_params(idev, ABS_Y,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
- ret = input_register_device(applesmc_idev);
+ ret = input_register_polled_device(applesmc_idev);
if (ret)
goto out_idev;
- /* start up our timer for the input device */
- init_timer(&applesmc_timer);
- applesmc_timer.function = applesmc_idev_poll;
- applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
-
return 0;
out_idev:
- input_free_device(applesmc_idev);
+ input_free_polled_device(applesmc_idev);
out_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
@@ -1146,8 +1125,8 @@ out:
/* Release all ressources used by the accelerometer */
static void applesmc_release_accelerometer(void)
{
- del_timer_sync(&applesmc_timer);
- input_unregister_device(applesmc_idev);
+ input_unregister_polled_device(applesmc_idev);
+ input_free_polled_device(applesmc_idev);
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
}
@@ -1184,8 +1163,6 @@ static int __init applesmc_init(void)
int count;
int i;
- mutex_init(&applesmc_lock);
-
if (!dmi_check_system(applesmc_whitelist)) {
printk(KERN_WARNING "applesmc: supported laptop not found!\n");
ret = -ENODEV;
@@ -1287,9 +1264,9 @@ static int __init applesmc_init(void)
goto out_light_wq;
}
- hwmon_class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(hwmon_class_dev)) {
- ret = PTR_ERR(hwmon_class_dev);
+ hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon_dev)) {
+ ret = PTR_ERR(hwmon_dev);
goto out_light_ledclass;
}
@@ -1331,7 +1308,7 @@ out:
static void __exit applesmc_exit(void)
{
- hwmon_device_unregister(hwmon_class_dev);
+ hwmon_device_unregister(hwmon_dev);
if (applesmc_light) {
led_classdev_unregister(&applesmc_backlight);
destroy_workqueue(applesmc_led_wq);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 57b1c7b7ac3..9460dba4cf7 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div)
/* TEMP: 0.001C/bit (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val)
dynamically allocated, at the same time the client itself is allocated. */
struct asb100_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct asb100_data *data = i2c_get_clientdata(client); \
- unsigned long val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
switch (nr) { \
@@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
/* VRM */
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct asb100_data *data = asb100_update_device(dev);
+ struct asb100_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &asb100_group);
}
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 0ccdd0750c4..cce3350e539 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = {
struct atxp1_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated;
u8 valid;
@@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client)
struct atxp1_data * data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 7c1795225b0..6f66551d9e5 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
static struct coretemp_data *coretemp_update_device(struct device *dev);
struct coretemp_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
const char *name;
u32 id;
@@ -58,8 +58,6 @@ struct coretemp_data {
u8 alarm;
};
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
/*
* Sysfs stuff
*/
@@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
goto exit_free;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n",
err);
goto exit_class;
@@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
{
struct coretemp_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
+static struct notifier_block coretemp_cpu_notifier = {
.notifier_call = coretemp_cpu_callback,
};
#endif /* !CONFIG_HOTPLUG_CPU */
@@ -371,9 +369,10 @@ static int __init coretemp_init(void)
for_each_online_cpu(i) {
struct cpuinfo_x86 *c = &(cpu_data)[i];
- /* check if family 6, models e, f */
+ /* check if family 6, models e, f, 16 */
if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
- !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
+ !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
+ (c->x86_model == 0x16))) {
/* supported CPU not found, but report the unknown
family 6 CPU */
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index e9cbc727664..a878c98e252 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -1,12 +1,12 @@
/*
- * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
- * integrated hardware monitoring features.
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
+ * Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
*
- * This driver is based on the LM85 driver. The hardware monitoring
- * capabilities of the DME1737 are very similar to the LM85 with some
- * additional features. Even though the DME1737 is a Super-I/O chip, the
- * hardware monitoring registers are only accessible via SMBus.
+ * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
+ * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
+ * SCH311x chip is found. Both types of chips have very similar hardware
+ * monitoring capabilities but differ in the way they can be accessed.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -35,6 +36,9 @@
#include <linux/mutex.h>
#include <asm/io.h>
+/* ISA device, if found */
+static struct platform_device *pdev;
+
/* Module load parameters */
static int force_start;
module_param(force_start, bool, 0);
@@ -133,6 +137,7 @@ static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
/* Miscellaneous registers */
+#define DME1737_REG_DEVICE 0x3d
#define DME1737_REG_COMPANY 0x3e
#define DME1737_REG_VERSTEP 0x3f
#define DME1737_REG_CONFIG 0x40
@@ -148,14 +153,20 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define DME1737_COMPANY_SMSC 0x5c
#define DME1737_VERSTEP 0x88
#define DME1737_VERSTEP_MASK 0xf8
+#define SCH311X_DEVICE 0x8c
+
+/* Length of ISA address segment */
+#define DME1737_EXTENT 2
/* ---------------------------------------------------------------------
* Data structures and manipulation thereof
* --------------------------------------------------------------------- */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+ the driver field to differentiate between I2C and ISA chips. */
struct dme1737_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
@@ -465,27 +476,48 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
/* ---------------------------------------------------------------------
* Device I/O access
+ *
+ * ISA access is performed through an index/data register pair and needs to
+ * be protected by a mutex during runtime (not required for initialization).
+ * We use data->update_lock for this and need to ensure that we acquire it
+ * before calling dme1737_read or dme1737_write.
* --------------------------------------------------------------------- */
static u8 dme1737_read(struct i2c_client *client, u8 reg)
{
- s32 val = i2c_smbus_read_byte_data(client, reg);
+ s32 val;
+
+ if (client->driver) { /* I2C device */
+ val = i2c_smbus_read_byte_data(client, reg);
- if (val < 0) {
- dev_warn(&client->dev, "Read from register 0x%02x failed! "
- "Please report to the driver maintainer.\n", reg);
+ if (val < 0) {
+ dev_warn(&client->dev, "Read from register "
+ "0x%02x failed! Please report to the driver "
+ "maintainer.\n", reg);
+ }
+ } else { /* ISA device */
+ outb(reg, client->addr);
+ val = inb(client->addr + 1);
}
return val;
}
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
{
- s32 res = i2c_smbus_write_byte_data(client, reg, value);
+ s32 res = 0;
+
+ if (client->driver) { /* I2C device */
+ res = i2c_smbus_write_byte_data(client, reg, val);
- if (res < 0) {
- dev_warn(&client->dev, "Write to register 0x%02x failed! "
- "Please report to the driver maintainer.\n", reg);
+ if (res < 0) {
+ dev_warn(&client->dev, "Write to register "
+ "0x%02x failed! Please report to the driver "
+ "maintainer.\n", reg);
+ }
+ } else { /* ISA device */
+ outb(reg, client->addr);
+ outb(val, client->addr + 1);
}
return res;
@@ -493,8 +525,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
static struct dme1737_data *dme1737_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
int ix;
u8 lsb[5];
@@ -630,6 +662,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
DME1737_REG_ALARM3) << 16;
}
+ /* The ISA chips require explicit clearing of alarm bits.
+ * Don't worry, an alarm will come back if the condition
+ * that causes it still exists */
+ if (!client->driver) {
+ if (data->alarms & 0xff0000) {
+ dme1737_write(client, DME1737_REG_ALARM3,
+ 0xff);
+ }
+ if (data->alarms & 0xff00) {
+ dme1737_write(client, DME1737_REG_ALARM2,
+ 0xff);
+ }
+ if (data->alarms & 0xff) {
+ dme1737_write(client, DME1737_REG_ALARM1,
+ 0xff);
+ }
+ }
+
data->last_update = jiffies;
data->valid = 1;
}
@@ -674,7 +724,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -683,8 +733,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
static ssize_t set_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -704,7 +754,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
data->in_max[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -754,7 +804,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -763,8 +813,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -789,7 +839,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
data->temp_offset[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -843,7 +893,7 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -852,8 +902,8 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -898,7 +948,7 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
data->zone_abs[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -950,7 +1000,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -959,8 +1009,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -995,7 +1045,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
/* Only valid for fan[1-4] */
if (!(val == 1 || val == 2 || val == 4)) {
count = -EINVAL;
- dev_warn(&client->dev, "Fan type value %ld not "
+ dev_warn(dev, "Fan type value %ld not "
"supported. Choose one of 1, 2, or 4.\n",
val);
goto exit;
@@ -1006,7 +1056,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
data->fan_opt[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
exit:
mutex_unlock(&data->update_lock);
@@ -1086,20 +1136,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
}
static struct attribute *dme1737_attr_pwm[];
-static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -1122,7 +1172,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
/* Only valid for pwm[1-3] */
if (val < 0 || val > 2) {
count = -EINVAL;
- dev_warn(&client->dev, "PWM enable %ld not "
+ dev_warn(dev, "PWM enable %ld not "
"supported. Choose one of 0, 1, or 2.\n",
val);
goto exit;
@@ -1156,7 +1206,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
switch (val) {
case 0:
/* Change permissions of pwm[ix] to read-only */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO);
/* Turn fan fully on */
data->pwm_config[ix] = PWM_EN_TO_REG(0,
@@ -1171,12 +1221,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
/* Change permissions of pwm[ix] to read-writeable */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO | S_IWUSR);
break;
case 2:
/* Change permissions of pwm[ix] to read-only */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO);
/* Turn on auto mode using the saved zone channel
* assignment */
@@ -1223,7 +1273,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
if (!(val == 1 || val == 2 || val == 4 ||
val == 6 || val == 7)) {
count = -EINVAL;
- dev_warn(&client->dev, "PWM auto channels zone %ld "
+ dev_warn(dev, "PWM auto channels zone %ld "
"not supported. Choose one of 1, 2, 4, 6, "
"or 7.\n", val);
goto exit;
@@ -1257,12 +1307,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
dme1737_read(client,
DME1737_REG_PWM_RR(0)));
-
} else {
data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
dme1737_read(client,
DME1737_REG_PWM_RR(0)));
-
}
dme1737_write(client, DME1737_REG_PWM_RR(0),
data->pwm_rr[0]);
@@ -1274,7 +1322,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_min[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
exit:
mutex_unlock(&data->update_lock);
@@ -1298,8 +1346,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
data->vrm = val;
@@ -1314,6 +1361,14 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->client.name);
+}
+
/* ---------------------------------------------------------------------
* Sysfs device attribute defines and structs
* --------------------------------------------------------------------- */
@@ -1322,13 +1377,13 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
#define SENSOR_DEVICE_ATTR_IN(ix) \
static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
- show_in, NULL, SYS_IN_INPUT, ix); \
+ show_in, NULL, SYS_IN_INPUT, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
- show_in, set_in, SYS_IN_MIN, ix); \
+ show_in, set_in, SYS_IN_MIN, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
- show_in, set_in, SYS_IN_MAX, ix); \
+ show_in, set_in, SYS_IN_MAX, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
- show_in, NULL, SYS_IN_ALARM, ix)
+ show_in, NULL, SYS_IN_ALARM, ix)
SENSOR_DEVICE_ATTR_IN(0);
SENSOR_DEVICE_ATTR_IN(1);
@@ -1342,17 +1397,17 @@ SENSOR_DEVICE_ATTR_IN(6);
#define SENSOR_DEVICE_ATTR_TEMP(ix) \
static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+ show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
- show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+ show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
- show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+ show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
- show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+ show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+ show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+ show_temp, NULL, SYS_TEMP_FAULT, ix-1)
SENSOR_DEVICE_ATTR_TEMP(1);
SENSOR_DEVICE_ATTR_TEMP(2);
@@ -1362,15 +1417,15 @@ SENSOR_DEVICE_ATTR_TEMP(3);
#define SENSOR_DEVICE_ATTR_ZONE(ix) \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
- show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+ show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
SENSOR_DEVICE_ATTR_ZONE(1);
SENSOR_DEVICE_ATTR_ZONE(2);
@@ -1380,13 +1435,13 @@ SENSOR_DEVICE_ATTR_ZONE(3);
#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
- show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
- show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+ show_fan, set_fan, SYS_FAN_TYPE, ix-1)
SENSOR_DEVICE_ATTR_FAN_1TO4(1);
SENSOR_DEVICE_ATTR_FAN_1TO4(2);
@@ -1397,13 +1452,13 @@ SENSOR_DEVICE_ATTR_FAN_1TO4(4);
#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
- show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
- show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MAX, ix-1)
+ show_fan, set_fan, SYS_FAN_MAX, ix-1)
SENSOR_DEVICE_ATTR_FAN_5TO6(5);
SENSOR_DEVICE_ATTR_FAN_5TO6(6);
@@ -1412,21 +1467,21 @@ SENSOR_DEVICE_ATTR_FAN_5TO6(6);
#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
- show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+ show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
SENSOR_DEVICE_ATTR_PWM_1TO3(1);
SENSOR_DEVICE_ATTR_PWM_1TO3(2);
@@ -1436,11 +1491,11 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3);
#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
- show_pwm, set_pwm, SYS_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
- show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
- show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+ show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
SENSOR_DEVICE_ATTR_PWM_5TO6(5);
SENSOR_DEVICE_ATTR_PWM_5TO6(6);
@@ -1449,6 +1504,7 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6);
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */
#define SENSOR_DEV_ATTR_IN(ix) \
&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
@@ -1519,53 +1575,53 @@ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
* permissions are created read-only and write permissions are added or removed
* on the fly when required */
static struct attribute *dme1737_attr[] ={
- /* Voltages */
- SENSOR_DEV_ATTR_IN(0),
- SENSOR_DEV_ATTR_IN(1),
- SENSOR_DEV_ATTR_IN(2),
- SENSOR_DEV_ATTR_IN(3),
- SENSOR_DEV_ATTR_IN(4),
- SENSOR_DEV_ATTR_IN(5),
- SENSOR_DEV_ATTR_IN(6),
- /* Temperatures */
- SENSOR_DEV_ATTR_TEMP(1),
- SENSOR_DEV_ATTR_TEMP(2),
- SENSOR_DEV_ATTR_TEMP(3),
- /* Zones */
- SENSOR_DEV_ATTR_ZONE(1),
- SENSOR_DEV_ATTR_ZONE(2),
- SENSOR_DEV_ATTR_ZONE(3),
- /* Misc */
- &dev_attr_vrm.attr,
- &dev_attr_cpu0_vid.attr,
+ /* Voltages */
+ SENSOR_DEV_ATTR_IN(0),
+ SENSOR_DEV_ATTR_IN(1),
+ SENSOR_DEV_ATTR_IN(2),
+ SENSOR_DEV_ATTR_IN(3),
+ SENSOR_DEV_ATTR_IN(4),
+ SENSOR_DEV_ATTR_IN(5),
+ SENSOR_DEV_ATTR_IN(6),
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP(1),
+ SENSOR_DEV_ATTR_TEMP(2),
+ SENSOR_DEV_ATTR_TEMP(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE(1),
+ SENSOR_DEV_ATTR_ZONE(2),
+ SENSOR_DEV_ATTR_ZONE(3),
+ /* Misc */
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
NULL
};
static const struct attribute_group dme1737_group = {
- .attrs = dme1737_attr,
+ .attrs = dme1737_attr,
};
/* The following structs hold the PWM attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_pwm1[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(1),
+ SENSOR_DEV_ATTR_PWM_1TO3(1),
NULL
};
static struct attribute *dme1737_attr_pwm2[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(2),
+ SENSOR_DEV_ATTR_PWM_1TO3(2),
NULL
};
static struct attribute *dme1737_attr_pwm3[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(3),
+ SENSOR_DEV_ATTR_PWM_1TO3(3),
NULL
};
static struct attribute *dme1737_attr_pwm5[] = {
- SENSOR_DEV_ATTR_PWM_5TO6(5),
+ SENSOR_DEV_ATTR_PWM_5TO6(5),
NULL
};
static struct attribute *dme1737_attr_pwm6[] = {
- SENSOR_DEV_ATTR_PWM_5TO6(6),
+ SENSOR_DEV_ATTR_PWM_5TO6(6),
NULL
};
@@ -1582,27 +1638,27 @@ static const struct attribute_group dme1737_pwm_group[] = {
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_fan1[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(1),
+ SENSOR_DEV_ATTR_FAN_1TO4(1),
NULL
};
static struct attribute *dme1737_attr_fan2[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(2),
+ SENSOR_DEV_ATTR_FAN_1TO4(2),
NULL
};
static struct attribute *dme1737_attr_fan3[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(3),
+ SENSOR_DEV_ATTR_FAN_1TO4(3),
NULL
};
static struct attribute *dme1737_attr_fan4[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(4),
+ SENSOR_DEV_ATTR_FAN_1TO4(4),
NULL
};
static struct attribute *dme1737_attr_fan5[] = {
- SENSOR_DEV_ATTR_FAN_5TO6(5),
+ SENSOR_DEV_ATTR_FAN_5TO6(5),
NULL
};
static struct attribute *dme1737_attr_fan6[] = {
- SENSOR_DEV_ATTR_FAN_5TO6(6),
+ SENSOR_DEV_ATTR_FAN_5TO6(6),
NULL
};
@@ -1637,23 +1693,23 @@ static const struct attribute_group dme1737_lock_group = {
* writeable if the chip is *not* locked and the respective PWM is available.
* Otherwise they stay read-only. */
static struct attribute *dme1737_attr_pwm1_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
NULL
};
static struct attribute *dme1737_attr_pwm2_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
NULL
};
static struct attribute *dme1737_attr_pwm3_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
NULL
};
static struct attribute *dme1737_attr_pwm5_lock[] = {
- SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
NULL
};
static struct attribute *dme1737_attr_pwm6_lock[] = {
- SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
NULL
};
@@ -1678,6 +1734,16 @@ static struct attribute *dme1737_attr_pwm[] = {
* Super-IO functions
* --------------------------------------------------------------------- */
+static inline void dme1737_sio_enter(int sio_cip)
+{
+ outb(0x55, sio_cip);
+}
+
+static inline void dme1737_sio_exit(int sio_cip)
+{
+ outb(0xaa, sio_cip);
+}
+
static inline int dme1737_sio_inb(int sio_cip, int reg)
{
outb(reg, sio_cip);
@@ -1690,136 +1756,196 @@ static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
outb(val, sio_cip + 1);
}
-static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+/* ---------------------------------------------------------------------
+ * Device initialization
+ * --------------------------------------------------------------------- */
+
+static int dme1737_i2c_get_features(int, struct dme1737_data*);
+
+static void dme1737_chmod_file(struct device *dev,
+ struct attribute *attr, mode_t mode)
{
- struct dme1737_data *data = i2c_get_clientdata(client);
- int err = 0, reg;
- u16 addr;
+ if (sysfs_chmod_file(&dev->kobj, attr, mode)) {
+ dev_warn(dev, "Failed to change permissions of %s.\n",
+ attr->name);
+ }
+}
- /* Enter configuration mode */
- outb(0x55, sio_cip);
+static void dme1737_chmod_group(struct device *dev,
+ const struct attribute_group *group,
+ mode_t mode)
+{
+ struct attribute **attr;
- /* Check device ID
- * The DME1737 can return either 0x78 or 0x77 as its device ID. */
- reg = dme1737_sio_inb(sio_cip, 0x20);
- if (!(reg == 0x77 || reg == 0x78)) {
- err = -ENODEV;
- goto exit;
+ for (attr = group->attrs; *attr; attr++) {
+ dme1737_chmod_file(dev, *attr, mode);
}
+}
- /* Select logical device A (runtime registers) */
- dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+static void dme1737_remove_files(struct device *dev)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ int ix;
- /* Get the base address of the runtime registers */
- if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
- dme1737_sio_inb(sio_cip, 0x61))) {
- err = -ENODEV;
- goto exit;
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&dev->kobj,
+ &dme1737_fan_group[ix]);
+ }
}
- /* Read the runtime registers to determine which optional features
- * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
- * to '10' if the respective feature is enabled. */
- if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
- data->has_fan |= (1 << 5);
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&dev->kobj,
+ &dme1737_pwm_group[ix]);
+ }
}
- if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
- data->has_pwm |= (1 << 5);
+
+ sysfs_remove_group(&dev->kobj, &dme1737_group);
+
+ if (!data->client.driver) {
+ sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
}
- if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
- data->has_fan |= (1 << 4);
+}
+
+static int dme1737_create_files(struct device *dev)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ int err, ix;
+
+ /* Create a name attribute for ISA devices */
+ if (!data->client.driver &&
+ (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
+ goto exit;
}
- if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
- data->has_pwm |= (1 << 4);
+
+ /* Create standard sysfs attributes */
+ if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) {
+ goto exit_remove;
}
-exit:
- /* Exit configuration mode */
- outb(0xaa, sio_cip);
+ /* Create fan sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ if ((err = sysfs_create_group(&dev->kobj,
+ &dme1737_fan_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
- return err;
-}
+ /* Create PWM sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ if ((err = sysfs_create_group(&dev->kobj,
+ &dme1737_pwm_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
-/* ---------------------------------------------------------------------
- * Device detection, registration and initialization
- * --------------------------------------------------------------------- */
+ /* Inform if the device is locked. Otherwise change the permissions of
+ * selected attributes from read-only to read-writeable. */
+ if (data->config & 0x02) {
+ dev_info(dev, "Device is locked. Some attributes "
+ "will be read-only.\n");
+ } else {
+ /* Change permissions of standard attributes */
+ dme1737_chmod_group(dev, &dme1737_lock_group,
+ S_IRUGO | S_IWUSR);
-static struct i2c_driver dme1737_driver;
+ /* Change permissions of PWM attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ dme1737_chmod_group(dev,
+ &dme1737_pwm_lock_group[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
-static void dme1737_chmod_file(struct i2c_client *client,
- struct attribute *attr, mode_t mode)
-{
- if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
- dev_warn(&client->dev, "Failed to change permissions of %s.\n",
- attr->name);
+ /* Change permissions of pwm[1-3] if in manual mode */
+ for (ix = 0; ix < 3; ix++) {
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+ dme1737_chmod_file(dev,
+ dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
}
-}
-static void dme1737_chmod_group(struct i2c_client *client,
- const struct attribute_group *group,
- mode_t mode)
-{
- struct attribute **attr;
+ return 0;
- for (attr = group->attrs; *attr; attr++) {
- dme1737_chmod_file(client, *attr, mode);
- }
+exit_remove:
+ dme1737_remove_files(dev);
+exit:
+ return err;
}
-static int dme1737_init_client(struct i2c_client *client)
+static int dme1737_init_device(struct device *dev)
{
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
int ix;
u8 reg;
- data->config = dme1737_read(client, DME1737_REG_CONFIG);
- /* Inform if part is not monitoring/started */
- if (!(data->config & 0x01)) {
- if (!force_start) {
- dev_err(&client->dev, "Device is not monitoring. "
- "Use the force_start load parameter to "
- "override.\n");
- return -EFAULT;
- }
-
- /* Force monitoring */
- data->config |= 0x01;
- dme1737_write(client, DME1737_REG_CONFIG, data->config);
- }
+ data->config = dme1737_read(client, DME1737_REG_CONFIG);
+ /* Inform if part is not monitoring/started */
+ if (!(data->config & 0x01)) {
+ if (!force_start) {
+ dev_err(dev, "Device is not monitoring. "
+ "Use the force_start load parameter to "
+ "override.\n");
+ return -EFAULT;
+ }
+
+ /* Force monitoring */
+ data->config |= 0x01;
+ dme1737_write(client, DME1737_REG_CONFIG, data->config);
+ }
/* Inform if part is not ready */
if (!(data->config & 0x04)) {
- dev_err(&client->dev, "Device is not ready.\n");
+ dev_err(dev, "Device is not ready.\n");
return -EFAULT;
}
- data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
- /* Check if optional fan3 input is enabled */
- if (data->config2 & 0x04) {
- data->has_fan |= (1 << 2);
- }
+ /* Determine which optional fan and pwm features are enabled/present */
+ if (client->driver) { /* I2C chip */
+ data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+ /* Check if optional fan3 input is enabled */
+ if (data->config2 & 0x04) {
+ data->has_fan |= (1 << 2);
+ }
- /* Fan4 and pwm3 are only available if the client's I2C address
- * is the default 0x2e. Otherwise the I/Os associated with these
- * functions are used for addr enable/select. */
- if (client->addr == 0x2e) {
- data->has_fan |= (1 << 3);
- data->has_pwm |= (1 << 2);
- }
+ /* Fan4 and pwm3 are only available if the client's I2C address
+ * is the default 0x2e. Otherwise the I/Os associated with
+ * these functions are used for addr enable/select. */
+ if (data->client.addr == 0x2e) {
+ data->has_fan |= (1 << 3);
+ data->has_pwm |= (1 << 2);
+ }
- /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
- * For this, we need to query the runtime registers through the
- * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
- if (dme1737_sio_get_features(0x2e, client) &&
- dme1737_sio_get_features(0x4e, client)) {
- dev_warn(&client->dev, "Failed to query Super-IO for optional "
- "features.\n");
+ /* Determine which of the optional fan[5-6] and pwm[5-6]
+ * features are enabled. For this, we need to query the runtime
+ * registers through the Super-IO LPC interface. Try both
+ * config ports 0x2e and 0x4e. */
+ if (dme1737_i2c_get_features(0x2e, data) &&
+ dme1737_i2c_get_features(0x4e, data)) {
+ dev_warn(dev, "Failed to query Super-IO for optional "
+ "features.\n");
+ }
+ } else { /* ISA chip */
+ /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
+ * don't exist in the ISA chip. */
+ data->has_fan |= (1 << 2);
+ data->has_pwm |= (1 << 2);
}
/* Fan1, fan2, pwm1, and pwm2 are always present */
data->has_fan |= 0x03;
data->has_pwm |= 0x03;
- dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+ dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
"fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
(data->has_pwm & (1 << 2)) ? "yes" : "no",
(data->has_pwm & (1 << 4)) ? "yes" : "no",
@@ -1831,13 +1957,19 @@ static int dme1737_init_client(struct i2c_client *client)
reg = dme1737_read(client, DME1737_REG_TACH_PWM);
/* Inform if fan-to-pwm mapping differs from the default */
- if (reg != 0xa4) {
- dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+ if (client->driver && reg != 0xa4) { /* I2C chip */
+ dev_warn(dev, "Non-standard fan to pwm mapping: "
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
"fan4->pwm%d. Please report to the driver "
"maintainer.\n",
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+ } else if (!client->driver && reg != 0x24) { /* ISA chip */
+ dev_warn(dev, "Non-standard fan to pwm mapping: "
+ "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
+ "Please report to the driver maintainer.\n",
+ (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+ ((reg >> 4) & 0x03) + 1);
}
/* Switch pwm[1-3] to manual mode if they are currently disabled and
@@ -1849,7 +1981,7 @@ static int dme1737_init_client(struct i2c_client *client)
DME1737_REG_PWM_CONFIG(ix));
if ((data->has_pwm & (1 << ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
- dev_info(&client->dev, "Switching pwm%d to "
+ dev_info(dev, "Switching pwm%d to "
"manual mode.\n", ix + 1);
data->pwm_config[ix] = PWM_EN_TO_REG(1,
data->pwm_config[ix]);
@@ -1872,13 +2004,67 @@ static int dme1737_init_client(struct i2c_client *client)
return 0;
}
-static int dme1737_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* ---------------------------------------------------------------------
+ * I2C device detection and registration
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_i2c_driver;
+
+static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
+{
+ int err = 0, reg;
+ u16 addr;
+
+ dme1737_sio_enter(sio_cip);
+
+ /* Check device ID
+ * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x77 || reg == 0x78)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Select logical device A (runtime registers) */
+ dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+ /* Get the base address of the runtime registers */
+ if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61))) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Read the runtime registers to determine which optional features
+ * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+ * to '10' if the respective feature is enabled. */
+ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+ data->has_fan |= (1 << 5);
+ }
+ if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+ data->has_pwm |= (1 << 5);
+ }
+ if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+ data->has_fan |= (1 << 4);
+ }
+ if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+ data->has_pwm |= (1 << 4);
+ }
+
+exit:
+ dme1737_sio_exit(sio_cip);
+
+ return err;
+}
+
+static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
+ int kind)
{
u8 company, verstep = 0;
struct i2c_client *client;
struct dme1737_data *data;
- int ix, err = 0;
+ struct device *dev;
+ int err = 0;
const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -1894,7 +2080,8 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
i2c_set_clientdata(client, data);
client->addr = address;
client->adapter = adapter;
- client->driver = &dme1737_driver;
+ client->driver = &dme1737_i2c_driver;
+ dev = &client->dev;
/* A negative kind means that the driver was loaded with no force
* parameter (default), so we must identify the chip. */
@@ -1922,92 +2109,33 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
goto exit_kfree;
}
+ dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
+ client->addr, verstep);
+
/* Initialize the DME1737 chip */
- if ((err = dme1737_init_client(client))) {
+ if ((err = dme1737_init_device(dev))) {
+ dev_err(dev, "Failed to initialize device.\n");
goto exit_detach;
}
- /* Create standard sysfs attributes */
- if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
- goto exit_detach;
- }
-
- /* Create fan sysfs attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
- &dme1737_fan_group[ix]))) {
- goto exit_remove;
- }
- }
- }
-
- /* Create PWM sysfs attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]))) {
- goto exit_remove;
- }
- }
- }
-
- /* Inform if the device is locked. Otherwise change the permissions of
- * selected attributes from read-only to read-writeable. */
- if (data->config & 0x02) {
- dev_info(&client->dev, "Device is locked. Some attributes "
- "will be read-only.\n");
- } else {
- /* Change permissions of standard attributes */
- dme1737_chmod_group(client, &dme1737_lock_group,
- S_IRUGO | S_IWUSR);
-
- /* Change permissions of PWM attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- dme1737_chmod_group(client,
- &dme1737_pwm_lock_group[ix],
- S_IRUGO | S_IWUSR);
- }
- }
-
- /* Change permissions of pwm[1-3] if in manual mode */
- for (ix = 0; ix < 3; ix++) {
- if ((data->has_pwm & (1 << ix)) &&
- (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
- dme1737_chmod_file(client,
- dme1737_attr_pwm[ix],
- S_IRUGO | S_IWUSR);
- }
- }
+ /* Create sysfs files */
+ if ((err = dme1737_create_files(dev))) {
+ dev_err(dev, "Failed to create sysfs files.\n");
+ goto exit_detach;
}
/* Register device */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(dev, "Failed to register device.\n");
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
- dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
- "(rev 0x%02x)\n", client->addr, verstep);
-
return 0;
exit_remove:
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_fan_group[ix]);
- }
- }
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]);
- }
- }
- sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+ dme1737_remove_files(dev);
exit_detach:
i2c_detach_client(client);
exit_kfree:
@@ -2016,60 +2144,260 @@ exit:
return err;
}
-static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON)) {
return 0;
}
- return i2c_probe(adapter, &addr_data, dme1737_detect);
+ return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
}
-static int dme1737_detach_client(struct i2c_client *client)
+static int dme1737_i2c_detach_client(struct i2c_client *client)
{
struct dme1737_data *data = i2c_get_clientdata(client);
- int ix, err;
+ int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
+ dme1737_remove_files(&client->dev);
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_fan_group[ix]);
- }
+ if ((err = i2c_detach_client(client))) {
+ return err;
}
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]);
- }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver dme1737_i2c_driver = {
+ .driver = {
+ .name = "dme1737",
+ },
+ .attach_adapter = dme1737_i2c_attach_adapter,
+ .detach_client = dme1737_i2c_detach_client,
+};
+
+/* ---------------------------------------------------------------------
+ * ISA device detection and registration
+ * --------------------------------------------------------------------- */
+
+static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
+{
+ int err = 0, reg;
+ unsigned short base_addr;
+
+ dme1737_sio_enter(sio_cip);
+
+ /* Check device ID
+ * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
+ * SCH3116 (0x7f). */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+ err = -ENODEV;
+ goto exit;
}
- sysfs_remove_group(&client->dev.kobj, &dme1737_group);
- if ((err = i2c_detach_client(client))) {
- return err;
+ /* Select logical device A (runtime registers) */
+ dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+ /* Get the base address of the runtime registers */
+ if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61))) {
+ printk(KERN_ERR "dme1737: Base address not set.\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Access to the hwmon registers is through an index/data register
+ * pair located at offset 0x70/0x71. */
+ *addr = base_addr + 0x70;
+
+exit:
+ dme1737_sio_exit(sio_cip);
+ return err;
+}
+
+static int __init dme1737_isa_device_add(unsigned short addr)
+{
+ struct resource res = {
+ .start = addr,
+ .end = addr + DME1737_EXTENT - 1,
+ .name = "dme1737",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ if (!(pdev = platform_device_alloc("dme1737", addr))) {
+ printk(KERN_ERR "dme1737: Failed to allocate device.\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ if ((err = platform_device_add_resources(pdev, &res, 1))) {
+ printk(KERN_ERR "dme1737: Failed to add device resource "
+ "(err = %d).\n", err);
+ goto exit_device_put;
+ }
+
+ if ((err = platform_device_add(pdev))) {
+ printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+ pdev = NULL;
+exit:
+ return err;
+}
+
+static int __devinit dme1737_isa_probe(struct platform_device *pdev)
+{
+ u8 company, device;
+ struct resource *res;
+ struct i2c_client *client;
+ struct dme1737_data *data;
+ struct device *dev = &pdev->dev;
+ int err;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+ dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
+ (unsigned short)res->start,
+ (unsigned short)res->start + DME1737_EXTENT - 1);
+ err = -EBUSY;
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_release_region;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = res->start;
+ platform_set_drvdata(pdev, data);
+
+ company = dme1737_read(client, DME1737_REG_COMPANY);
+ device = dme1737_read(client, DME1737_REG_DEVICE);
+
+ if (!((company == DME1737_COMPANY_SMSC) &&
+ (device == SCH311X_DEVICE))) {
+ err = -ENODEV;
+ goto exit_kfree;
+ }
+
+ /* Fill in the remaining client fields and initialize the mutex */
+ strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+
+ /* Initialize the chip */
+ if ((err = dme1737_init_device(dev))) {
+ dev_err(dev, "Failed to initialize device.\n");
+ goto exit_kfree;
}
+ /* Create sysfs files */
+ if ((err = dme1737_create_files(dev))) {
+ dev_err(dev, "Failed to create sysfs files.\n");
+ goto exit_kfree;
+ }
+
+ /* Register device */
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(dev, "Failed to register device.\n");
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+exit_remove_files:
+ dme1737_remove_files(dev);
+exit_kfree:
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+exit_release_region:
+ release_region(res->start, DME1737_EXTENT);
+exit:
+ return err;
+}
+
+static int __devexit dme1737_isa_remove(struct platform_device *pdev)
+{
+ struct dme1737_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ dme1737_remove_files(&pdev->dev);
+ release_region(data->client.addr, DME1737_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
+
return 0;
}
-static struct i2c_driver dme1737_driver = {
+static struct platform_driver dme1737_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "dme1737",
},
- .attach_adapter = dme1737_attach_adapter,
- .detach_client = dme1737_detach_client,
+ .probe = dme1737_isa_probe,
+ .remove = __devexit_p(dme1737_isa_remove),
};
+/* ---------------------------------------------------------------------
+ * Module initialization and cleanup
+ * --------------------------------------------------------------------- */
+
static int __init dme1737_init(void)
{
- return i2c_add_driver(&dme1737_driver);
+ int err;
+ unsigned short addr;
+
+ if ((err = i2c_add_driver(&dme1737_i2c_driver))) {
+ goto exit;
+ }
+
+ if (dme1737_isa_detect(0x2e, &addr) &&
+ dme1737_isa_detect(0x4e, &addr)) {
+ /* Return 0 if we didn't find an ISA device */
+ return 0;
+ }
+
+ if ((err = platform_driver_register(&dme1737_isa_driver))) {
+ goto exit_del_i2c_driver;
+ }
+
+ /* Sets global pdev as a side effect */
+ if ((err = dme1737_isa_device_add(addr))) {
+ goto exit_del_isa_driver;
+ }
+
+ return 0;
+
+exit_del_isa_driver:
+ platform_driver_unregister(&dme1737_isa_driver);
+exit_del_i2c_driver:
+ i2c_del_driver(&dme1737_i2c_driver);
+exit:
+ return err;
}
static void __exit dme1737_exit(void)
{
- i2c_del_driver(&dme1737_driver);
+ if (pdev) {
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&dme1737_isa_driver);
+ }
+
+ i2c_del_driver(&dme1737_i2c_driver);
}
MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 1212d6b7f31..b7bd000b130 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = {
/* Each client has this additional data */
struct ds1621_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct ds1621_data *data = ds1621_update_client(dev);
- u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
+ u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
mutex_lock(&data->update_lock);
data->temp[attr->index] = val;
@@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client)
struct ds1621_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 6f60715f34f..5d9d5cc816a 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -10,6 +10,9 @@
* The F71872F/FG is almost the same, with two more voltages monitored,
* and 6 VID inputs.
*
+ * The F71806F/FG is essentially the same as the F71872F/FG. It even has
+ * the same chip ID, so the driver can't differentiate between.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -159,7 +162,7 @@ struct f71805f_auto_point {
struct f71805f_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
}
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
goto exit_remove_files;
}
@@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
struct resource *res;
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
@@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
static const char *names[] = {
"F71805F/FG",
- "F71872F/FG",
+ "F71872F/FG or F71806F/FG",
};
superio_enter(sioaddr);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
new file mode 100644
index 00000000000..6db74434a02
--- /dev/null
+++ b/drivers/hwmon/f71882fg.c
@@ -0,0 +1,950 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
+ * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+#define DRVNAME "f71882fg"
+
+#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/
+#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
+
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_DEVREV 0x22 /* Device revision */
+#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
+#define SIO_REG_ENABLE 0x30 /* Logical device enable */
+#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
+#define SIO_F71882_ID 0x0541 /* Chipset ID */
+
+#define REGION_LENGTH 8
+#define ADDR_REG_OFFSET 5
+#define DATA_REG_OFFSET 6
+
+#define F71882FG_REG_PECI 0x0A
+
+#define F71882FG_REG_IN_STATUS 0x12
+#define F71882FG_REG_IN_BEEP 0x13
+#define F71882FG_REG_IN(nr) (0x20 + (nr))
+#define F71882FG_REG_IN1_HIGH 0x32
+
+#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
+#define F71882FG_REG_FAN_STATUS 0x92
+#define F71882FG_REG_FAN_BEEP 0x93
+
+#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
+#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
+#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
+#define F71882FG_REG_TEMP_STATUS 0x62
+#define F71882FG_REG_TEMP_BEEP 0x63
+#define F71882FG_REG_TEMP_HYST1 0x6C
+#define F71882FG_REG_TEMP_HYST23 0x6D
+#define F71882FG_REG_TEMP_TYPE 0x6B
+#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
+
+#define F71882FG_REG_START 0x01
+
+#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
+
+static struct platform_device *f71882fg_pdev = NULL;
+
+/* Super-I/O Function prototypes */
+static inline int superio_inb(int base, int reg);
+static inline int superio_inw(int base, int reg);
+static inline void superio_enter(int base);
+static inline void superio_select(int base, int ld);
+static inline void superio_exit(int base);
+
+static inline u16 fan_from_reg ( u16 reg );
+
+struct f71882fg_data {
+ unsigned short addr;
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_limits; /* In jiffies */
+
+ /* Register Values */
+ u8 in[9];
+ u8 in1_max;
+ u8 in_status;
+ u8 in_beep;
+ u16 fan[4];
+ u8 fan_status;
+ u8 fan_beep;
+ u8 temp[3];
+ u8 temp_ovt[3];
+ u8 temp_high[3];
+ u8 temp_hyst[3];
+ u8 temp_type[3];
+ u8 temp_status;
+ u8 temp_beep;
+ u8 temp_diode_open;
+};
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
+
+/* Sysfs in*/
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs Fan */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs Temp */
+static ssize_t show_temp(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs misc */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+
+static int __devinit f71882fg_probe(struct platform_device * pdev);
+static int __devexit f71882fg_remove(struct platform_device *pdev);
+static int __init f71882fg_init(void);
+static int __init f71882fg_find(int sioaddr, unsigned short *address);
+static int __init f71882fg_device_add(unsigned short address);
+static void __exit f71882fg_exit(void);
+
+static struct platform_driver f71882fg_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = f71882fg_probe,
+ .remove = __devexit_p(f71882fg_remove),
+};
+
+static struct device_attribute f71882fg_dev_attr[] =
+{
+ __ATTR( name, S_IRUGO, show_name, NULL ),
+};
+
+static struct sensor_device_attribute f71882fg_in_temp_attr[] =
+{
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+ SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
+ SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1),
+ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+ SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0),
+ SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 0),
+ SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0),
+ SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
+ SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+ SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0),
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
+ SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
+ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+ SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 1),
+ SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 1),
+ SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 1),
+ SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
+ SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+ SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 1),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
+ SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
+ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+ SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 2),
+ SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 2),
+ SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 2),
+ SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
+ SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+ SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 2),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
+ SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
+};
+
+static struct sensor_device_attribute f71882fg_fan_attr[] =
+{
+ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+ SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0),
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
+ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+ SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 1),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
+ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+ SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 2),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
+ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+ SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 3),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
+};
+
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+ outb(reg, base);
+ return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+ int val;
+ outb(reg++, base);
+ val = inb(base + 1) << 8;
+ outb(reg, base);
+ val |= inb(base + 1);
+ return val;
+}
+
+static inline void superio_enter(int base)
+{
+ /* according to the datasheet the key must be send twice! */
+ outb( SIO_UNLOCK_KEY, base);
+ outb( SIO_UNLOCK_KEY, base);
+}
+
+static inline void superio_select( int base, int ld)
+{
+ outb(SIO_REG_LDSEL, base);
+ outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+ outb(SIO_LOCK_KEY, base);
+}
+
+static inline u16 fan_from_reg(u16 reg)
+{
+ return reg ? (1500000 / reg) : 0;
+}
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
+{
+ u8 val;
+
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ val = inb(data->addr + DATA_REG_OFFSET);
+
+ return val;
+}
+
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
+{
+ u16 val;
+
+ outb(reg++, data->addr + ADDR_REG_OFFSET);
+ val = inb(data->addr + DATA_REG_OFFSET) << 8;
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ val |= inb(data->addr + DATA_REG_OFFSET);
+
+ return val;
+}
+
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
+{
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ outb(val, data->addr + DATA_REG_OFFSET);
+}
+
+static struct f71882fg_data *f71882fg_update_device(struct device * dev)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr, reg, reg2;
+
+ mutex_lock(&data->update_lock);
+
+ /* Update once every 60 seconds */
+ if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
+ !data->valid) {
+ data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
+ data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+
+ /* Get High & boundary temps*/
+ for (nr = 0; nr < 3; nr++) {
+ data->temp_ovt[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_OVT(nr));
+ data->temp_high[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HIGH(nr));
+ }
+
+ /* Have to hardcode hyst*/
+ data->temp_hyst[0] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HYST1) >> 4;
+ /* Hyst temps 2 & 3 stored in same register */
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
+ data->temp_hyst[1] = reg & 0x0F;
+ data->temp_hyst[2] = reg >> 4;
+
+ /* Have to hardcode type, because temp1 is special */
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+ reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
+ if ((reg2 & 0x03) == 0x01)
+ data->temp_type[0] = 6 /* PECI */;
+ else if ((reg2 & 0x03) == 0x02)
+ data->temp_type[0] = 5 /* AMDSI */;
+ else
+ data->temp_type[0] = (reg & 0x02) ? 2 : 4;
+
+ data->temp_type[1] = (reg & 0x04) ? 2 : 4;
+ data->temp_type[2] = (reg & 0x08) ? 2 : 4;
+
+ data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
+
+ data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
+
+ data->last_limits = jiffies;
+ }
+
+ /* Update every second */
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ data->temp_status = f71882fg_read8(data,
+ F71882FG_REG_TEMP_STATUS);
+ data->temp_diode_open = f71882fg_read8(data,
+ F71882FG_REG_TEMP_DIODE_OPEN);
+ for (nr = 0; nr < 3; nr++)
+ data->temp[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP(nr));
+
+ data->fan_status = f71882fg_read8(data,
+ F71882FG_REG_FAN_STATUS);
+ for (nr = 0; nr < 4; nr++)
+ data->fan[nr] = f71882fg_read16(data,
+ F71882FG_REG_FAN(nr));
+
+ data->in_status = f71882fg_read8(data,
+ F71882FG_REG_IN_STATUS);
+ for (nr = 0; nr < 9; nr++)
+ data->in[nr] = f71882fg_read8(data,
+ F71882FG_REG_IN(nr));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* Sysfs Interface */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int speed = fan_from_reg(data->fan[nr]);
+
+ if (speed == FAN_MIN_DETECT)
+ speed = 0;
+
+ return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->fan_beep & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->fan_beep |= 1 << nr;
+ else
+ data->fan_beep &= ~(1 << nr);
+
+ f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->fan_status & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->in[nr] * 8);
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+
+ return sprintf(buf, "%d\n", data->in1_max * 8);
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int val = simple_strtoul(buf, NULL, 10) / 8;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
+ data->in1_max = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->in_beep & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->in_beep |= 1 << nr;
+ else
+ data->in_beep &= ~(1 << nr);
+
+ f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->in_status & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
+ data->temp_high[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n",
+ (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+ ssize_t ret = count;
+
+ mutex_lock(&data->update_lock);
+
+ /* convert abs to relative and check */
+ val = data->temp_high[nr] - val;
+ if (val < 0 || val > 15) {
+ ret = -EINVAL;
+ goto store_temp_max_hyst_exit;
+ }
+
+ data->temp_hyst[nr] = val;
+
+ /* convert value to register contents */
+ switch (nr) {
+ case 0:
+ val = val << 4;
+ break;
+ case 1:
+ val = val | (data->temp_hyst[2] << 4);
+ break;
+ case 2:
+ val = data->temp_hyst[1] | (val << 4);
+ break;
+ }
+
+ f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
+ F71882FG_REG_TEMP_HYST1, val);
+
+store_temp_max_hyst_exit:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
+ data->temp_ovt[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n",
+ (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_type[nr]);
+}
+
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_beep & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->temp_beep |= 1 << (nr + 1);
+ else
+ data->temp_beep &= ~(1 << (nr + 1));
+
+ f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_status & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_diode_open & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, DRVNAME "\n");
+}
+
+
+static int __devinit f71882fg_probe(struct platform_device * pdev)
+{
+ struct f71882fg_data *data;
+ int err, i;
+ u8 start_reg;
+
+ if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ /* Register sysfs interface files */
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
+ err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+
+ start_reg = f71882fg_read8(data, F71882FG_REG_START);
+ if (start_reg & 0x01) {
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
+ err = device_create_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+ }
+
+ if (start_reg & 0x02) {
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
+ err = device_create_file(&pdev->dev,
+ &f71882fg_fan_attr[i].dev_attr);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_unregister_sysfs;
+ }
+
+ return 0;
+
+exit_unregister_sysfs:
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+ device_remove_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+ kfree(data);
+
+ return err;
+}
+
+static int __devexit f71882fg_remove(struct platform_device *pdev)
+{
+ int i;
+ struct f71882fg_data *data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->hwmon_dev);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+ device_remove_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+ kfree(data);
+
+ return 0;
+}
+
+static int __init f71882fg_find(int sioaddr, unsigned short *address)
+{
+ int err = -ENODEV;
+ u16 devid;
+ u8 start_reg;
+ struct f71882fg_data data;
+
+ superio_enter(sioaddr);
+
+ devid = superio_inw(sioaddr, SIO_REG_MANID);
+ if (devid != SIO_FINTEK_ID) {
+ printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
+ goto exit;
+ }
+
+ devid = superio_inw(sioaddr, SIO_REG_DEVID);
+ if (devid != SIO_F71882_ID) {
+ printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
+ goto exit;
+ }
+
+ superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+ if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Device not activated\n");
+ goto exit;
+ }
+
+ *address = superio_inw(sioaddr, SIO_REG_ADDR);
+ if (*address == 0)
+ {
+ printk(KERN_WARNING DRVNAME ": Base address not set\n");
+ goto exit;
+ }
+ *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
+
+ data.addr = *address;
+ start_reg = f71882fg_read8(&data, F71882FG_REG_START);
+ if (!(start_reg & 0x03)) {
+ printk(KERN_WARNING DRVNAME
+ ": Hardware monitoring not activated\n");
+ goto exit;
+ }
+
+ err = 0;
+ printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
+ (unsigned int)*address,
+ (int)superio_inb(sioaddr, SIO_REG_DEVREV));
+exit:
+ superio_exit(sioaddr);
+ return err;
+}
+
+static int __init f71882fg_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + REGION_LENGTH - 1,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ f71882fg_pdev = platform_device_alloc(DRVNAME, address);
+ if (!f71882fg_pdev)
+ return -ENOMEM;
+
+ res.name = f71882fg_pdev->name;
+ err = platform_device_add_resources(f71882fg_pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(f71882fg_pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed\n");
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(f71882fg_pdev);
+
+ return err;
+}
+
+static int __init f71882fg_init(void)
+{
+ int err = -ENODEV;
+ unsigned short address;
+
+ if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
+ goto exit;
+
+ if ((err = platform_driver_register(&f71882fg_driver)))
+ goto exit;
+
+ if ((err = f71882fg_device_add(address)))
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&f71882fg_driver);
+exit:
+ return err;
+}
+
+static void __exit f71882fg_exit(void)
+{
+ platform_device_unregister(f71882fg_pdev);
+ platform_driver_unregister(&f71882fg_driver);
+}
+
+MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
+MODULE_LICENSE("GPL");
+
+module_init(f71882fg_init);
+module_exit(f71882fg_exit);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
new file mode 100644
index 00000000000..13a041326a0
--- /dev/null
+++ b/drivers/hwmon/f75375s.c
@@ -0,0 +1,691 @@
+/*
+ * f75375s.c - driver for the Fintek F75375/SP and F75373
+ * hardware monitoring features
+ * Copyright (C) 2006-2007 Riku Voipio <riku.voipio@movial.fi>
+ *
+ * Datasheets available at:
+ *
+ * f75375:
+ * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
+ *
+ * f75373:
+ * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(f75373, f75375);
+
+/* Fintek F75375 registers */
+#define F75375_REG_CONFIG0 0x0
+#define F75375_REG_CONFIG1 0x1
+#define F75375_REG_CONFIG2 0x2
+#define F75375_REG_CONFIG3 0x3
+#define F75375_REG_ADDR 0x4
+#define F75375_REG_INTR 0x31
+#define F75375_CHIP_ID 0x5A
+#define F75375_REG_VERSION 0x5C
+#define F75375_REG_VENDOR 0x5D
+#define F75375_REG_FAN_TIMER 0x60
+
+#define F75375_REG_VOLT(nr) (0x10 + (nr))
+#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2)
+#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2)
+
+#define F75375_REG_TEMP(nr) (0x14 + (nr))
+#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2)
+#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2)
+
+#define F75375_REG_FAN(nr) (0x16 + (nr) * 2)
+#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2)
+#define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10)
+
+#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10)
+#define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step))
+#define F75375_REG_FAN_B_SPEED(nr, step) \
+ ((0xA5 + (nr) * 0x10) + (step) * 2)
+
+#define F75375_REG_PWM1_RAISE_DUTY 0x69
+#define F75375_REG_PWM2_RAISE_DUTY 0x6A
+#define F75375_REG_PWM1_DROP_DUTY 0x6B
+#define F75375_REG_PWM2_DROP_DUTY 0x6C
+
+#define FAN_CTRL_LINEAR(nr) (4 + nr)
+#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2))
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct f75375_data {
+ unsigned short addr;
+ struct i2c_client client;
+ struct device *hwmon_dev;
+
+ const char *name;
+ int kind;
+ struct mutex update_lock; /* protect register access */
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_limits; /* In jiffies */
+
+ /* Register values */
+ u8 in[4];
+ u8 in_max[4];
+ u8 in_min[4];
+ u16 fan[2];
+ u16 fan_min[2];
+ u16 fan_full[2];
+ u16 fan_exp[2];
+ u8 fan_timer;
+ u8 pwm[2];
+ u8 pwm_mode[2];
+ u8 pwm_enable[2];
+ s8 temp[2];
+ s8 temp_high[2];
+ s8 temp_max_hyst[2];
+};
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter);
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
+static int f75375_detach_client(struct i2c_client *client);
+
+static struct i2c_driver f75375_driver = {
+ .driver = {
+ .name = "f75375",
+ },
+ .attach_adapter = f75375_attach_adapter,
+ .detach_client = f75375_detach_client,
+};
+
+static inline int f75375_read8(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* in most cases, should be called while holding update_lock */
+static inline u16 f75375_read16(struct i2c_client *client, u8 reg)
+{
+ return ((i2c_smbus_read_byte_data(client, reg) << 8)
+ | i2c_smbus_read_byte_data(client, reg + 1));
+}
+
+static inline void f75375_write8(struct i2c_client *client, u8 reg,
+ u8 value)
+{
+ i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline void f75375_write16(struct i2c_client *client, u8 reg,
+ u16 value)
+{
+ int err = i2c_smbus_write_byte_data(client, reg, (value << 8));
+ if (err)
+ return;
+ i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
+}
+
+static struct f75375_data *f75375_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int nr;
+
+ mutex_lock(&data->update_lock);
+
+ /* Limit registers cache is refreshed after 60 seconds */
+ if (time_after(jiffies, data->last_limits + 60 * HZ)
+ || !data->valid) {
+ for (nr = 0; nr < 2; nr++) {
+ data->temp_high[nr] =
+ f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
+ data->temp_max_hyst[nr] =
+ f75375_read8(client, F75375_REG_TEMP_HYST(nr));
+ data->fan_full[nr] =
+ f75375_read16(client, F75375_REG_FAN_FULL(nr));
+ data->fan_min[nr] =
+ f75375_read16(client, F75375_REG_FAN_MIN(nr));
+ data->fan_exp[nr] =
+ f75375_read16(client, F75375_REG_FAN_EXP(nr));
+ data->pwm[nr] = f75375_read8(client,
+ F75375_REG_FAN_PWM_DUTY(nr));
+
+ }
+ for (nr = 0; nr < 4; nr++) {
+ data->in_max[nr] =
+ f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
+ data->in_min[nr] =
+ f75375_read8(client, F75375_REG_VOLT_LOW(nr));
+ }
+ data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
+ data->last_limits = jiffies;
+ }
+
+ /* Measurement registers cache is refreshed after 2 second */
+ if (time_after(jiffies, data->last_updated + 2 * HZ)
+ || !data->valid) {
+ for (nr = 0; nr < 2; nr++) {
+ data->temp[nr] =
+ f75375_read8(client, F75375_REG_TEMP(nr));
+ data->fan[nr] =
+ f75375_read16(client, F75375_REG_FAN(nr));
+ }
+ for (nr = 0; nr < 4; nr++)
+ data->in[nr] =
+ f75375_read8(client, F75375_REG_VOLT(nr));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+static inline u16 rpm_from_reg(u16 reg)
+{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
+ return (1500000 / reg);
+}
+
+static inline u16 rpm_to_reg(int rpm)
+{
+ if (rpm < 367 || rpm > 0xffff)
+ return 0xffff;
+ return (1500000 / rpm);
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = rpm_to_reg(val);
+ f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_exp[nr] = rpm_to_reg(val);
+ f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ u8 fanmode;
+
+ if (val < 0 || val > 4)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
+ fanmode = ~(3 << FAN_CTRL_MODE(nr));
+
+ switch (val) {
+ case 0: /* Full speed */
+ fanmode |= (3 << FAN_CTRL_MODE(nr));
+ data->pwm[nr] = 255;
+ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+ data->pwm[nr]);
+ break;
+ case 1: /* PWM */
+ fanmode |= (3 << FAN_CTRL_MODE(nr));
+ break;
+ case 2: /* AUTOMATIC*/
+ fanmode |= (2 << FAN_CTRL_MODE(nr));
+ break;
+ case 3: /* fan speed */
+ break;
+ }
+ f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
+ data->pwm_enable[nr] = val;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ u8 conf = 0;
+
+ if (val != 0 || val != 1 || data->kind == f75373)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ conf = f75375_read8(client, F75375_REG_CONFIG1);
+ conf = ~(1 << FAN_CTRL_LINEAR(nr));
+
+ if (val == 0)
+ conf |= (1 << FAN_CTRL_LINEAR(nr)) ;
+
+ f75375_write8(client, F75375_REG_CONFIG1, conf);
+ data->pwm_mode[nr] = val;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm[nr]);
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_mode[nr]);
+}
+
+#define VOLT_FROM_REG(val) ((val) * 8)
+#define VOLT_TO_REG(val) ((val) / 8)
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ mutex_lock(&data->update_lock);
+ data->in_max[nr] = val;
+ f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ mutex_lock(&data->update_lock);
+ data->in_min[nr] = val;
+ f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define TEMP_TO_REG(val) ((val) / 1000)
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ mutex_lock(&data->update_lock);
+ data->temp_high[nr] = val;
+ f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ mutex_lock(&data->update_lock);
+ data->temp_max_hyst[nr] = val;
+ f75375_write8(client, F75375_REG_TEMP_HYST(nr),
+ data->temp_max_hyst[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define show_fan(thing) \
+static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
+ char *buf)\
+{\
+ int nr = to_sensor_dev_attr(attr)->index;\
+ struct f75375_data *data = f75375_update_device(dev); \
+ return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
+}
+
+show_fan(fan);
+show_fan(fan_min);
+show_fan(fan_full);
+show_fan(fan_exp);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
+ show_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
+ show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
+ show_temp_max_hyst, set_temp_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
+ show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR,
+ show_fan_exp, set_fan_exp, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR,
+ show_fan_exp, set_fan_exp, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
+ show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR,
+ show_pwm_mode, set_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
+ show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR,
+ show_pwm_mode, set_pwm_mode, 1);
+
+static struct attribute *f75375_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_full.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_exp.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_full.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_exp.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group f75375_group = {
+ .attrs = f75375_attributes,
+};
+
+static int f75375_detach_client(struct i2c_client *client)
+{
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int err;
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &f75375_group);
+
+ err = i2c_detach_client(client);
+ if (err) {
+ dev_err(&client->dev,
+ "Client deregistration failed, "
+ "client not detached.\n");
+ return err;
+ }
+ kfree(data);
+ return 0;
+}
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, f75375_detect);
+}
+
+/* This function is called by i2c_probe */
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct f75375_data *data;
+ u8 version = 0;
+ int err = 0;
+ const char *name = "";
+
+ if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &f75375_driver;
+
+ if (kind < 0) {
+ u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
+ u16 chipid = f75375_read16(client, F75375_CHIP_ID);
+ version = f75375_read8(client, F75375_REG_VERSION);
+ if (chipid == 0x0306 && vendid == 0x1934) {
+ kind = f75375;
+ } else if (chipid == 0x0204 && vendid == 0x1934) {
+ kind = f75373;
+ } else {
+ dev_err(&adapter->dev,
+ "failed,%02X,%02X,%02X\n",
+ chipid, version, vendid);
+ goto exit_free;
+ }
+ }
+
+ if (kind == f75375) {
+ name = "f75375";
+ } else if (kind == f75373) {
+ name = "f75373";
+ }
+
+ dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+ data->kind = kind;
+ mutex_init(&data->update_lock);
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
+ goto exit_detach;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &f75375_group);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __init sensors_f75375_init(void)
+{
+ return i2c_add_driver(&f75375_driver);
+}
+
+static void __exit sensors_f75375_exit(void)
+{
+ i2c_del_driver(&f75375_driver);
+}
+
+MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
+
+module_init(sensors_f75375_init);
+module_exit(sensors_f75375_exit);
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index b34b546c68b..e67c36953b2 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = {
struct fscher_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client)
struct fscher_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscher_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
new file mode 100644
index 00000000000..63a4df0580d
--- /dev/null
+++ b/drivers/hwmon/fschmd.c
@@ -0,0 +1,778 @@
+/* fschmd.c
+ *
+ * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
+ * Scylla, Heracles and Heimdall chips
+ *
+ * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
+ * (candidate) fschmd drivers:
+ * Copyright (C) 2006 Thilo Cestonaro
+ * <thilo.cestonaro.external@fujitsu-siemens.com>
+ * Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
+ * Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
+ * Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
+ * Copyright (C) 2000 Hermann Jung <hej@odn.de>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
+
+/*
+ * The FSCHMD registers and other defines
+ */
+
+/* chip identification */
+#define FSCHMD_REG_IDENT_0 0x00
+#define FSCHMD_REG_IDENT_1 0x01
+#define FSCHMD_REG_IDENT_2 0x02
+#define FSCHMD_REG_REVISION 0x03
+
+/* global control and status */
+#define FSCHMD_REG_EVENT_STATE 0x04
+#define FSCHMD_REG_CONTROL 0x05
+
+#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01
+
+/* watchdog (support to be implemented) */
+#define FSCHMD_REG_WDOG_PRESET 0x28
+#define FSCHMD_REG_WDOG_STATE 0x23
+#define FSCHMD_REG_WDOG_CONTROL 0x21
+
+/* voltages, weird order is to keep the same order as the old drivers */
+static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
+
+/* minimum pwm at which the fan is driven (pwm can by increased depending on
+ the temp. Notice that for the scy some fans share there minimum speed.
+ Also notice that with the scy the sensor order is different then with the
+ other chips, this order was in the 2.4 driver and kept for consistency. */
+static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
+ { 0x55, 0x65 }, /* pos */
+ { 0x55, 0x65, 0xb5 }, /* her */
+ { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
+ { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
+ { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
+};
+
+/* actual fan speed */
+static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
+ { 0x0e, 0x6b, 0xab }, /* pos */
+ { 0x0e, 0x6b, 0xbb }, /* her */
+ { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
+ { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
+ { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
+};
+
+/* fan status registers */
+static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
+ { 0x0d, 0x62, 0xa2 }, /* pos */
+ { 0x0d, 0x62, 0xb2 }, /* her */
+ { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
+ { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
+ { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
+};
+
+/* fan ripple / divider registers */
+static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
+ { 0x0f, 0x6f, 0xaf }, /* pos */
+ { 0x0f, 0x6f, 0xbf }, /* her */
+ { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
+ { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
+ { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
+};
+
+static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
+
+/* Fan status register bitmasks */
+#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */
+#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */
+
+
+/* actual temperature registers */
+static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
+ { 0x64, 0x32, 0x35 }, /* pos */
+ { 0x64, 0x32, 0x35 }, /* her */
+ { 0x64, 0xD0, 0x32, 0x35 }, /* scy */
+ { 0x64, 0x32, 0x35 }, /* hrc */
+ { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
+};
+
+/* temperature state registers */
+static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
+ { 0x71, 0x81, 0x91 }, /* pos */
+ { 0x71, 0x81, 0x91 }, /* her */
+ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */
+ { 0x71, 0x81, 0x91 }, /* hrc */
+ { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
+};
+
+/* temperature high limit registers, FSC does not document these. Proven to be
+ there with field testing on the fscher and fschrc, already supported / used
+ in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
+ at these addresses, but doesn't want to confirm they are the same as with
+ the fscher?? */
+static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
+ { 0, 0, 0 }, /* pos */
+ { 0x76, 0x86, 0x96 }, /* her */
+ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */
+ { 0x76, 0x86, 0x96 }, /* hrc */
+ { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
+};
+
+/* These were found through experimenting with an fscher, currently they are
+ not used, but we keep them around for future reference.
+static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
+static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
+
+static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
+
+/* temp status register bitmasks */
+#define FSCHMD_TEMP_WORKING_MASK 0x01
+#define FSCHMD_TEMP_ALERT_MASK 0x02
+/* there only really is an alarm if the sensor is working and alert == 1 */
+#define FSCHMD_TEMP_ALARM_MASK \
+ (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK)
+
+/* our driver name */
+#define FSCHMD_NAME "fschmd"
+
+/*
+ * Functions declarations
+ */
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter);
+static int fschmd_detach_client(struct i2c_client *client);
+static struct fschmd_data *fschmd_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver fschmd_driver = {
+ .driver = {
+ .name = FSCHMD_NAME,
+ },
+ .attach_adapter = fschmd_attach_adapter,
+ .detach_client = fschmd_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct fschmd_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ int kind;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* register values */
+ u8 global_control; /* global control register */
+ u8 volt[3]; /* 12, 5, battery voltage */
+ u8 temp_act[5]; /* temperature */
+ u8 temp_status[5]; /* status of sensor */
+ u8 temp_max[5]; /* high temp limit, notice: undocumented! */
+ u8 fan_act[6]; /* fans revolutions per second */
+ u8 fan_status[6]; /* fan status */
+ u8 fan_min[6]; /* fan min value for rps */
+ u8 fan_ripple[6]; /* divider for rps */
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static ssize_t show_in_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ const int max_reading[3] = { 14200, 6600, 3300 };
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", (data->volt[index] *
+ max_reading[index] + 128) / 255);
+}
+
+
+#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
+
+static ssize_t show_temp_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ long v = simple_strtol(buf, NULL, 10) / 1000;
+
+ v = SENSORS_LIMIT(v, -128, 127) + 128;
+
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
+ data->temp_max[index] = v;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ /* bit 0 set means sensor working ok, so no fault! */
+ if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK)
+ return sprintf(buf, "0\n");
+ else
+ return sprintf(buf, "1\n");
+}
+
+static ssize_t show_temp_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
+ FSCHMD_TEMP_ALARM_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+
+#define RPM_FROM_REG(val) ((val) * 60)
+
+static ssize_t show_fan_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ /* bits 2..7 reserved => mask with 3 */
+ return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
+}
+
+static ssize_t store_fan_div(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ u8 reg;
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ /* supported values: 2, 4, 8 */
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ switch (v) {
+ case 2: v = 1; break;
+ case 4: v = 2; break;
+ case 8: v = 3; break;
+ default:
+ dev_err(dev, "fan_div value %lu not supported. "
+ "Choose one of 2, 4 or 8!\n", v);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ reg = i2c_smbus_read_byte_data(&data->client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
+
+ /* bits 2..7 reserved => mask with 0x03 */
+ reg &= ~0x03;
+ reg |= v;
+
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
+
+ data->fan_ripple[index] = reg;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_fan_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+
+static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ int val = fschmd_update_device(dev)->fan_min[index];
+
+ /* 0 = allow turning off, 1-255 = 50-100% */
+ if (val)
+ val = val / 2 + 128;
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ /* register: 0 = allow turning off, 1-255 = 50-100% */
+ if (v) {
+ v = SENSORS_LIMIT(v, 128, 255);
+ v = (v - 128) * 2 + 1;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_FAN_MIN[data->kind][index], v);
+ data->fan_min[index] = v;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+
+/* The FSC hwmon family has the ability to force an attached alert led to flash
+ from software, we export this as an alert_led sysfs attr */
+static ssize_t show_alert_led(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_alert_led(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ u8 reg;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
+
+ if (v)
+ reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
+ else
+ reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
+
+ i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
+
+ data->global_control = reg;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute fschmd_attr[] = {
+ SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
+ SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
+ SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
+ SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
+};
+
+static struct sensor_device_attribute fschmd_temp_attr[] = {
+ SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+ SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
+ SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
+ SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+ SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
+ SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
+ SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
+ SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
+ SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
+ SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
+ SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
+ SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
+ SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
+ SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
+ SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
+ SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
+ SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
+ SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+};
+
+static struct sensor_device_attribute fschmd_fan_attr[] = {
+ SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
+ SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
+ SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
+ SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
+ SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 0),
+ SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
+ SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
+ SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
+ SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
+ SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 1),
+ SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
+ SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
+ SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
+ SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
+ SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 2),
+ SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
+ SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
+ SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
+ SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
+ SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 3),
+ SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
+ SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
+ SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
+ SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
+ SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 4),
+ SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
+ SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
+ SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
+ SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
+ SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 5),
+};
+
+
+/*
+ * Real code
+ */
+
+static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct fschmd_data *data;
+ u8 revision;
+ const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
+ "Heracles", "Heimdall" };
+ const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
+ "fschrc", "fschmd" };
+ int i, err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ * client structure, even though we cannot fill it completely yet.
+ * But it allows us to access i2c_smbus_read_byte_data. */
+ if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &fschmd_driver;
+ mutex_init(&data->update_lock);
+
+ /* Detect & Identify the chip */
+ if (kind <= 0) {
+ char id[4];
+
+ id[0] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_0);
+ id[1] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_1);
+ id[2] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_2);
+ id[3] = '\0';
+
+ if (!strcmp(id, "PEG"))
+ kind = fscpos;
+ else if (!strcmp(id, "HER"))
+ kind = fscher;
+ else if (!strcmp(id, "SCY"))
+ kind = fscscy;
+ else if (!strcmp(id, "HRC"))
+ kind = fschrc;
+ else if (!strcmp(id, "HMD"))
+ kind = fschmd;
+ else
+ goto exit_free;
+ }
+
+ if (kind == fscpos) {
+ /* The Poseidon has hardwired temp limits, fill these
+ in for the alarm resetting code */
+ data->temp_max[0] = 70 + 128;
+ data->temp_max[1] = 50 + 128;
+ data->temp_max[2] = 50 + 128;
+ }
+
+ /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
+ data->kind = kind - 1;
+ strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
+ err = device_create_file(&client->dev,
+ &fschmd_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
+ /* Poseidon doesn't have TEMP_LIMIT registers */
+ if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
+ show_temp_max)
+ continue;
+
+ err = device_create_file(&client->dev,
+ &fschmd_temp_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
+ /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
+ if (kind == fscpos &&
+ !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
+ "pwm3_auto_point1_pwm"))
+ continue;
+
+ err = device_create_file(&client->dev,
+ &fschmd_fan_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ data->hwmon_dev = NULL;
+ goto exit_detach;
+ }
+
+ revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
+ printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",
+ names[data->kind], (int) revision);
+
+ return 0;
+
+exit_detach:
+ fschmd_detach_client(client); /* will also free data for us */
+ return err;
+
+exit_free:
+ kfree(data);
+ return err;
+}
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, fschmd_detect);
+}
+
+static int fschmd_detach_client(struct i2c_client *client)
+{
+ struct fschmd_data *data = i2c_get_clientdata(client);
+ int i, err;
+
+ /* Check if registered in case we're called from fschmd_detect
+ to cleanup after an error */
+ if (data->hwmon_dev)
+ hwmon_device_unregister(data->hwmon_dev);
+
+ for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
+ device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
+ for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
+ device_remove_file(&client->dev,
+ &fschmd_temp_attr[i].dev_attr);
+ for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
+ device_remove_file(&client->dev,
+ &fschmd_fan_attr[i].dev_attr);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+ return 0;
+}
+
+static struct fschmd_data *fschmd_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fschmd_data *data = i2c_get_clientdata(client);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+
+ for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
+ data->temp_act[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_TEMP_ACT[data->kind][i]);
+ data->temp_status[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_TEMP_STATE[data->kind][i]);
+
+ /* The fscpos doesn't have TEMP_LIMIT registers */
+ if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
+ data->temp_max[i] = i2c_smbus_read_byte_data(
+ client,
+ FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
+
+ /* reset alarm if the alarm condition is gone,
+ the chip doesn't do this itself */
+ if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
+ FSCHMD_TEMP_ALARM_MASK &&
+ data->temp_act[i] < data->temp_max[i])
+ i2c_smbus_write_byte_data(client,
+ FSCHMD_REG_TEMP_STATE[data->kind][i],
+ FSCHMD_TEMP_ALERT_MASK);
+ }
+
+ for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
+ data->fan_act[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_ACT[data->kind][i]);
+ data->fan_status[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_STATE[data->kind][i]);
+ data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
+
+ /* The fscpos third fan doesn't have a fan_min */
+ if (FSCHMD_REG_FAN_MIN[data->kind][i])
+ data->fan_min[i] = i2c_smbus_read_byte_data(
+ client,
+ FSCHMD_REG_FAN_MIN[data->kind][i]);
+
+ /* reset fan status if speed is back to > 0 */
+ if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&
+ data->fan_act[i])
+ i2c_smbus_write_byte_data(client,
+ FSCHMD_REG_FAN_STATE[data->kind][i],
+ FSCHMD_FAN_ALARM_MASK);
+ }
+
+ for (i = 0; i < 3; i++)
+ data->volt[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_VOLT[i]);
+
+ data->global_control = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_CONTROL);
+
+ /* To be implemented in the future
+ data->watchdog[0] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_PRESET);
+ data->watchdog[1] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_STATE);
+ data->watchdog[2] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_CONTROL); */
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init fschmd_init(void)
+{
+ return i2c_add_driver(&fschmd_driver);
+}
+
+static void __exit fschmd_exit(void)
+{
+ i2c_del_driver(&fschmd_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
+ "Heimdall driver");
+MODULE_LICENSE("GPL");
+
+module_init(fschmd_init);
+module_exit(fschmd_exit);
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index ea506a77f9c..92c9703d0ac 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = {
*/
struct fscpos_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* 0 until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client)
struct fscpos_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index c103640455a..bb58d9866a3 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* Each client has this additional data */
struct gl518_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client)
struct gl518_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl518_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index ebe7b9aaa91..a3b56c816e1 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = {
/* Client data */
struct gl520_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until the following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client)
struct gl520_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl520_group);
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index a7c6d407572..8a7ae03aeee 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -28,7 +28,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/module.h>
@@ -61,13 +61,12 @@
#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */
#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */
-#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define HDAPS_POLL_INTERVAL 50 /* poll for input every 1/20s (50 ms)*/
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
#define HDAPS_INPUT_FLAT 4
-static struct timer_list hdaps_timer;
static struct platform_device *pdev;
-static struct input_dev *hdaps_idev;
+static struct input_polled_dev *hdaps_idev;
static unsigned int hdaps_invert;
static u8 km_activity;
static int rest_x;
@@ -323,24 +322,19 @@ static void hdaps_calibrate(void)
__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
}
-static void hdaps_mousedev_poll(unsigned long unused)
+static void hdaps_mousedev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *input_dev = dev->input;
int x, y;
- /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (mutex_trylock(&hdaps_mtx)) {
- mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
- return;
- }
+ mutex_lock(&hdaps_mtx);
if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
goto out;
- input_report_abs(hdaps_idev, ABS_X, x - rest_x);
- input_report_abs(hdaps_idev, ABS_Y, y - rest_y);
- input_sync(hdaps_idev);
-
- mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
+ input_report_abs(input_dev, ABS_X, x - rest_x);
+ input_report_abs(input_dev, ABS_Y, y - rest_y);
+ input_sync(input_dev);
out:
mutex_unlock(&hdaps_mtx);
@@ -536,6 +530,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = {
static int __init hdaps_init(void)
{
+ struct input_dev *idev;
int ret;
if (!dmi_check_system(hdaps_whitelist)) {
@@ -563,39 +558,37 @@ static int __init hdaps_init(void)
if (ret)
goto out_device;
- hdaps_idev = input_allocate_device();
+ hdaps_idev = input_allocate_polled_device();
if (!hdaps_idev) {
ret = -ENOMEM;
goto out_group;
}
+ hdaps_idev->poll = hdaps_mousedev_poll;
+ hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
+
/* initial calibrate for the input device */
hdaps_calibrate();
/* initialize the input class */
- hdaps_idev->name = "hdaps";
- hdaps_idev->dev.parent = &pdev->dev;
- hdaps_idev->evbit[0] = BIT(EV_ABS);
- input_set_abs_params(hdaps_idev, ABS_X,
+ idev = hdaps_idev->input;
+ idev->name = "hdaps";
+ idev->dev.parent = &pdev->dev;
+ idev->evbit[0] = BIT(EV_ABS);
+ input_set_abs_params(idev, ABS_X,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- input_set_abs_params(hdaps_idev, ABS_Y,
+ input_set_abs_params(idev, ABS_Y,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- ret = input_register_device(hdaps_idev);
+ ret = input_register_polled_device(hdaps_idev);
if (ret)
goto out_idev;
- /* start up our timer for the input device */
- init_timer(&hdaps_timer);
- hdaps_timer.function = hdaps_mousedev_poll;
- hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD;
- add_timer(&hdaps_timer);
-
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
return 0;
out_idev:
- input_free_device(hdaps_idev);
+ input_free_polled_device(hdaps_idev);
out_group:
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
out_device:
@@ -611,8 +604,8 @@ out:
static void __exit hdaps_exit(void)
{
- del_timer_sync(&hdaps_timer);
- input_unregister_device(hdaps_idev);
+ input_unregister_polled_device(hdaps_idev);
+ input_free_polled_device(hdaps_idev);
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
platform_device_unregister(pdev);
platform_driver_unregister(&hdaps_driver);
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index affcc00764d..3db28450a3b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr);
static DEFINE_SPINLOCK(idr_lock);
/**
- * hwmon_device_register - register w/ hwmon sysfs class
+ * hwmon_device_register - register w/ hwmon
* @dev: the device to register
*
- * hwmon_device_unregister() must be called when the class device is no
+ * hwmon_device_unregister() must be called when the device is no
* longer needed.
*
- * Returns the pointer to the new struct class device.
+ * Returns the pointer to the new device.
*/
-struct class_device *hwmon_device_register(struct device *dev)
+struct device *hwmon_device_register(struct device *dev)
{
- struct class_device *cdev;
+ struct device *hwdev;
int id, err;
again:
@@ -55,34 +55,33 @@ again:
return ERR_PTR(err);
id = id & MAX_ID_MASK;
- cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev,
- HWMON_ID_FORMAT, id);
+ hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id);
- if (IS_ERR(cdev)) {
+ if (IS_ERR(hwdev)) {
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
}
- return cdev;
+ return hwdev;
}
/**
* hwmon_device_unregister - removes the previously registered class device
*
- * @cdev: the class device to destroy
+ * @dev: the class device to destroy
*/
-void hwmon_device_unregister(struct class_device *cdev)
+void hwmon_device_unregister(struct device *dev)
{
int id;
- if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) {
- class_device_unregister(cdev);
+ if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) {
+ device_unregister(dev);
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
} else
- dev_dbg(cdev->dev,
+ dev_dbg(dev->parent,
"hwmon_device_unregister() failed: bad class ID!\n");
}
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
new file mode 100644
index 00000000000..c462824ffcc
--- /dev/null
+++ b/drivers/hwmon/ibmpex.c
@@ -0,0 +1,607 @@
+/*
+ * A hwmon driver for the IBM PowerExecutive temperature/power sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+
+#define REFRESH_INTERVAL (2 * HZ)
+#define DRVNAME "ibmpex"
+
+#define PEX_GET_VERSION 1
+#define PEX_GET_SENSOR_COUNT 2
+#define PEX_GET_SENSOR_NAME 3
+#define PEX_RESET_HIGH_LOW 4
+#define PEX_GET_SENSOR_DATA 6
+
+#define PEX_NET_FUNCTION 0x3A
+#define PEX_COMMAND 0x3C
+
+static inline u16 extract_value(const char *data, int offset)
+{
+ return be16_to_cpup((u16 *)&data[offset]);
+}
+
+#define TEMP_SENSOR 1
+#define POWER_SENSOR 2
+
+#define PEX_SENSOR_TYPE_LEN 3
+static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
+static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D};
+
+#define PEX_MULT_LEN 2
+static u8 const watt_sensor_sig[] = {0x41, 0x43};
+
+#define PEX_NUM_SENSOR_FUNCS 3
+static char const * const power_sensor_name_templates[] = {
+ "%s%d_average",
+ "%s%d_average_lowest",
+ "%s%d_average_highest"
+};
+static char const * const temp_sensor_name_templates[] = {
+ "%s%d_input",
+ "%s%d_input_lowest",
+ "%s%d_input_highest"
+};
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void ibmpex_register_bmc(int iface, struct device *dev);
+static void ibmpex_bmc_gone(int iface);
+
+struct ibmpex_sensor_data {
+ int in_use;
+ s16 values[PEX_NUM_SENSOR_FUNCS];
+ int multiplier;
+
+ struct sensor_device_attribute_2 attr[PEX_NUM_SENSOR_FUNCS];
+};
+
+struct ibmpex_bmc_data {
+ struct list_head list;
+ struct device *hwmon_dev;
+ struct device *bmc_device;
+ struct mutex lock;
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+
+ struct ipmi_addr address;
+ struct completion read_complete;
+ ipmi_user_t user;
+ int interface;
+
+ struct kernel_ipmi_msg tx_message;
+ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH];
+ long tx_msgid;
+
+ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH];
+ unsigned long rx_msg_len;
+ unsigned char rx_result;
+ int rx_recv_type;
+
+ unsigned char sensor_major;
+ unsigned char sensor_minor;
+
+ unsigned char num_sensors;
+ struct ibmpex_sensor_data *sensors;
+};
+
+struct ibmpex_driver_data {
+ struct list_head bmc_data;
+ struct ipmi_smi_watcher bmc_events;
+ struct ipmi_user_hndl ipmi_hndlrs;
+};
+
+static struct ibmpex_driver_data driver_data = {
+ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
+ .bmc_events = {
+ .owner = THIS_MODULE,
+ .new_smi = ibmpex_register_bmc,
+ .smi_gone = ibmpex_bmc_gone,
+ },
+ .ipmi_hndlrs = {
+ .ipmi_recv_hndl = ibmpex_msg_handler,
+ },
+};
+
+static int ibmpex_send_message(struct ibmpex_bmc_data *data)
+{
+ int err;
+
+ err = ipmi_validate_addr(&data->address, sizeof(data->address));
+ if (err)
+ goto out;
+
+ data->tx_msgid++;
+ err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+ &data->tx_message, data, 0, 0, 0);
+ if (err)
+ goto out1;
+
+ return 0;
+out1:
+ printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err);
+ return err;
+out:
+ printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err);
+ return err;
+}
+
+static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_GET_VERSION;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len != 6)
+ return -ENOENT;
+
+ data->sensor_major = data->rx_msg_data[0];
+ data->sensor_minor = data->rx_msg_data[1];
+
+ printk(KERN_INFO DRVNAME ": Found BMC with sensor interface "
+ "v%d.%d %d-%02d-%02d on interface %d\n",
+ data->sensor_major,
+ data->sensor_minor,
+ extract_value(data->rx_msg_data, 2),
+ data->rx_msg_data[4],
+ data->rx_msg_data[5],
+ data->interface);
+
+ return 0;
+}
+
+static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len != 1)
+ return -ENOENT;
+
+ return data->rx_msg_data[0];
+}
+
+static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
+ data->tx_msg_data[1] = sensor;
+ data->tx_message.data_len = 2;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len < 1)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
+ data->tx_msg_data[1] = sensor;
+ data->tx_message.data_len = 2;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len < 26) {
+ printk(KERN_ERR "Error reading sensor %d, please check.\n",
+ sensor);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ return 0;
+}
+
+static void ibmpex_update_device(struct ibmpex_bmc_data *data)
+{
+ int i, err;
+
+ mutex_lock(&data->lock);
+ if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+ data->valid)
+ goto out;
+
+ for (i = 0; i < data->num_sensors; i++) {
+ if (!data->sensors[i].in_use)
+ continue;
+ err = ibmpex_query_sensor_data(data, i);
+ if (err)
+ continue;
+ data->sensors[i].values[0] =
+ extract_value(data->rx_msg_data, 16);
+ data->sensors[i].values[1] =
+ extract_value(data->rx_msg_data, 18);
+ data->sensors[i].values[2] =
+ extract_value(data->rx_msg_data, 20);
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+
+out:
+ mutex_unlock(&data->lock);
+}
+
+static struct ibmpex_bmc_data *get_bmc_data(int iface)
+{
+ struct ibmpex_bmc_data *p, *next;
+
+ list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+ if (p->interface == iface)
+ return p;
+
+ return NULL;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static ssize_t ibmpex_show_sensor(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+ int mult = data->sensors[attr->index].multiplier;
+ ibmpex_update_device(data);
+
+ return sprintf(buf, "%d\n",
+ data->sensors[attr->index].values[attr->nr] * mult);
+}
+
+static ssize_t ibmpex_reset_high_low(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+
+ ibmpex_reset_high_low_data(data);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL,
+ ibmpex_reset_high_low, 0);
+
+static int is_power_sensor(const char *sensor_id, int len)
+{
+ if (len < PEX_SENSOR_TYPE_LEN)
+ return 0;
+
+ if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
+ return 1;
+ return 0;
+}
+
+static int is_temp_sensor(const char *sensor_id, int len)
+{
+ if (len < PEX_SENSOR_TYPE_LEN)
+ return 0;
+
+ if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
+ return 1;
+ return 0;
+}
+
+static int power_sensor_multiplier(const char *sensor_id, int len)
+{
+ int i;
+
+ for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
+ if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
+ return 1000000;
+
+ return 100000;
+}
+
+static int create_sensor(struct ibmpex_bmc_data *data, int type,
+ int counter, int sensor, int func)
+{
+ int err;
+ char *n;
+
+ n = kmalloc(32, GFP_KERNEL);
+ if (!n)
+ return -ENOMEM;
+
+ if (type == TEMP_SENSOR)
+ sprintf(n, temp_sensor_name_templates[func], "temp", counter);
+ else if (type == POWER_SENSOR)
+ sprintf(n, power_sensor_name_templates[func], "power", counter);
+
+ data->sensors[sensor].attr[func].dev_attr.attr.name = n;
+ data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
+ data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
+ data->sensors[sensor].attr[func].index = sensor;
+ data->sensors[sensor].attr[func].nr = func;
+
+ err = device_create_file(data->bmc_device,
+ &data->sensors[sensor].attr[func].dev_attr);
+ if (err) {
+ data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
+ kfree(n);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
+{
+ int i, j, err;
+ int sensor_type;
+ int sensor_counter;
+ int num_power = 0;
+ int num_temp = 0;
+
+ err = ibmpex_query_sensor_count(data);
+ if (err <= 0)
+ return -ENOENT;
+ data->num_sensors = err;
+
+ data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors),
+ GFP_KERNEL);
+ if (!data->sensors)
+ return -ENOMEM;
+
+ for (i = 0; i < data->num_sensors; i++) {
+ err = ibmpex_query_sensor_name(data, i);
+ if (err)
+ continue;
+
+ if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
+ sensor_type = POWER_SENSOR;
+ num_power++;
+ sensor_counter = num_power;
+ data->sensors[i].multiplier =
+ power_sensor_multiplier(data->rx_msg_data,
+ data->rx_msg_len);
+ } else if (is_temp_sensor(data->rx_msg_data,
+ data->rx_msg_len)) {
+ sensor_type = TEMP_SENSOR;
+ num_temp++;
+ sensor_counter = num_temp;
+ data->sensors[i].multiplier = 1;
+ } else
+ continue;
+
+ data->sensors[i].in_use = 1;
+
+ /* Create attributes */
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ err = create_sensor(data, sensor_type, sensor_counter,
+ i, j);
+ if (err)
+ goto exit_remove;
+ }
+ }
+
+ err = device_create_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ err = device_create_file(data->bmc_device,
+ &sensor_dev_attr_name.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ return 0;
+
+exit_remove:
+ device_remove_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+ for (i = 0; i < data->num_sensors; i++)
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ if (!data->sensors[i].attr[j].dev_attr.attr.name)
+ continue;
+ device_remove_file(data->bmc_device,
+ &data->sensors[i].attr[j].dev_attr);
+ kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+ }
+
+ kfree(data->sensors);
+ return err;
+}
+
+static void ibmpex_register_bmc(int iface, struct device *dev)
+{
+ struct ibmpex_bmc_data *data;
+ int err;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR DRVNAME ": Insufficient memory for BMC "
+ "interface %d.\n", data->interface);
+ return;
+ }
+
+ data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ data->address.channel = IPMI_BMC_CHANNEL;
+ data->address.data[0] = 0;
+ data->interface = iface;
+ data->bmc_device = dev;
+
+ /* Create IPMI messaging interface user */
+ err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+ data, &data->user);
+ if (err < 0) {
+ printk(KERN_ERR DRVNAME ": Error, unable to register user with "
+ "ipmi interface %d\n",
+ data->interface);
+ goto out;
+ }
+
+ mutex_init(&data->lock);
+
+ /* Initialize message */
+ data->tx_msgid = 0;
+ init_completion(&data->read_complete);
+ data->tx_message.netfn = PEX_NET_FUNCTION;
+ data->tx_message.cmd = PEX_COMMAND;
+ data->tx_message.data = data->tx_msg_data;
+
+ /* Does this BMC support PowerExecutive? */
+ err = ibmpex_ver_check(data);
+ if (err)
+ goto out_user;
+
+ /* Register the BMC as a HWMON class device */
+ data->hwmon_dev = hwmon_device_register(data->bmc_device);
+
+ if (IS_ERR(data->hwmon_dev)) {
+ printk(KERN_ERR DRVNAME ": Error, unable to register hwmon "
+ "class device for interface %d\n",
+ data->interface);
+ goto out_user;
+ }
+
+ /* finally add the new bmc data to the bmc data list */
+ dev_set_drvdata(dev, data);
+ list_add_tail(&data->list, &driver_data.bmc_data);
+
+ /* Now go find all the sensors */
+ err = ibmpex_find_sensors(data);
+ if (err) {
+ printk(KERN_ERR "Error %d allocating memory\n", err);
+ goto out_register;
+ }
+
+ return;
+
+out_register:
+ hwmon_device_unregister(data->hwmon_dev);
+out_user:
+ ipmi_destroy_user(data->user);
+out:
+ kfree(data);
+}
+
+static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
+{
+ int i, j;
+
+ device_remove_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+ for (i = 0; i < data->num_sensors; i++)
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ if (!data->sensors[i].attr[j].dev_attr.attr.name)
+ continue;
+ device_remove_file(data->bmc_device,
+ &data->sensors[i].attr[j].dev_attr);
+ kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+ }
+
+ list_del(&data->list);
+ dev_set_drvdata(data->bmc_device, NULL);
+ hwmon_device_unregister(data->hwmon_dev);
+ ipmi_destroy_user(data->user);
+ kfree(data->sensors);
+ kfree(data);
+}
+
+static void ibmpex_bmc_gone(int iface)
+{
+ struct ibmpex_bmc_data *data = get_bmc_data(iface);
+
+ if (!data)
+ return;
+
+ ibmpex_bmc_delete(data);
+}
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+ struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
+
+ if (msg->msgid != data->tx_msgid) {
+ printk(KERN_ERR "Received msgid (%02x) and transmitted "
+ "msgid (%02x) mismatch!\n",
+ (int)msg->msgid,
+ (int)data->tx_msgid);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+
+ data->rx_recv_type = msg->recv_type;
+ if (msg->msg.data_len > 0)
+ data->rx_result = msg->msg.data[0];
+ else
+ data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+ if (msg->msg.data_len > 1) {
+ data->rx_msg_len = msg->msg.data_len - 1;
+ memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+ } else
+ data->rx_msg_len = 0;
+
+ ipmi_free_recv_msg(msg);
+ complete(&data->read_complete);
+}
+
+static int __init ibmpex_init(void)
+{
+ return ipmi_smi_watcher_register(&driver_data.bmc_events);
+}
+
+static void __exit ibmpex_exit(void)
+{
+ struct ibmpex_bmc_data *p, *next;
+
+ ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+ list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+ ibmpex_bmc_delete(p);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(ibmpex_init);
+module_exit(ibmpex_exit);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index d75dba9b810..6a182e14cf5 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -141,10 +141,10 @@ static int fix_pwm_polarity;
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
-#define IT87_REG_FAN(nr) (0x0d + (nr))
-#define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
-#define IT87_REG_FANX(nr) (0x18 + (nr))
-#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
+static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
+static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 };
+static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
+static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr))
@@ -222,7 +222,7 @@ struct it87_sio_data {
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct it87_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
unsigned short addr;
@@ -235,8 +235,8 @@ struct it87_data {
u8 in_max[8]; /* Register value */
u8 in_min[8]; /* Register value */
u8 has_fan; /* Bitfield, fans enabled */
- u16 fan[3]; /* Register values, possibly combined */
- u16 fan_min[3]; /* Register values, possibly combined */
+ u16 fan[5]; /* Register values, possibly combined */
+ u16 fan_min[5]; /* Register values, possibly combined */
u8 temp[3]; /* Register value */
u8 temp_high[3]; /* Register value */
u8 temp_low[3]; /* Register value */
@@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
}
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Restore fan min limit */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN16_TO_REG(val);
- it87_write_value(data, IT87_REG_FAN_MIN(nr),
+ it87_write_value(data, IT87_REG_FAN_MIN[nr],
data->fan_min[nr] & 0xff);
- it87_write_value(data, IT87_REG_FANX_MIN(nr),
+ it87_write_value(data, IT87_REG_FANX_MIN[nr],
data->fan_min[nr] >> 8);
mutex_unlock(&data->update_lock);
return count;
@@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
show_fan16_offset(1);
show_fan16_offset(2);
show_fan16_offset(3);
+show_fan16_offset(4);
+show_fan16_offset(5);
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
@@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct it87_data *data = it87_update_device(dev);
+ struct it87_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t
@@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = {
&sensor_dev_attr_fan2_min16.dev_attr.attr,
&sensor_dev_attr_fan3_input16.dev_attr.attr,
&sensor_dev_attr_fan3_min16.dev_attr.attr,
+ &sensor_dev_attr_fan4_input16.dev_attr.attr,
+ &sensor_dev_attr_fan4_min16.dev_attr.attr,
+ &sensor_dev_attr_fan5_input16.dev_attr.attr,
+ &sensor_dev_attr_fan5_min16.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
@@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev)
&sensor_dev_attr_fan3_min16.dev_attr)))
goto ERROR4;
}
+ if (data->has_fan & (1 << 3)) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan4_input16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan4_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 4)) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan5_input16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan5_min16.dev_attr)))
+ goto ERROR4;
+ }
} else {
/* 8-bit tachometers with clock divider */
if (data->has_fan & (1 << 0)) {
@@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
goto ERROR4;
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
{
struct it87_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &it87_group);
sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
@@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
+ if (tmp & (1 << 4))
+ data->has_fan |= (1 << 3); /* fan4 enabled */
+ if (tmp & (1 << 5))
+ data->has_fan |= (1 << 4); /* fan5 enabled */
}
/* Set current fan mode registers and the default settings for the
@@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev)
data->in[8] =
it87_read_value(data, IT87_REG_VIN(8));
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 5; i++) {
/* Skip disabled fans */
if (!(data->has_fan & (1 << i)))
continue;
data->fan_min[i] =
- it87_read_value(data, IT87_REG_FAN_MIN(i));
+ it87_read_value(data, IT87_REG_FAN_MIN[i]);
data->fan[i] = it87_read_value(data,
- IT87_REG_FAN(i));
+ IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */
if (data->type == it8716 || data->type == it8718) {
data->fan[i] |= it87_read_value(data,
- IT87_REG_FANX(i)) << 8;
+ IT87_REG_FANX[i]) << 8;
data->fan_min[i] |= it87_read_value(data,
- IT87_REG_FANX_MIN(i)) << 8;
+ IT87_REG_FANX_MIN[i]) << 8;
}
}
for (i = 0; i < 3; i++) {
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 5d8d0ca08fa..bd2bde0ef95 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -38,7 +38,7 @@
#define SEL_CORE 0x04
struct k8temp_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
const char *name;
char valid; /* zero until following fields are valid */
@@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
if (err)
goto exit_remove;
- data->class_dev = hwmon_device_register(&pdev->dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
{
struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&pdev->dev,
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 2162d69a8c0..f207434730d 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = {
struct lm63_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client)
struct lm63_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm63_group);
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 275d392eca6..dd366889ce9 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -37,7 +37,7 @@
#define DRVNAME "lm70"
struct lm70 {
- struct class_device *cdev;
+ struct device *hwmon_dev;
struct semaphore sem;
};
@@ -81,7 +81,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
* So it's equivalent to multiplying by 0.25 * 1000 = 250.
*/
val = ((int)raw/32) * 250;
- status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */
+ status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
out:
up(&p_lm70->sem);
return status;
@@ -89,6 +89,14 @@ out:
static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
+static ssize_t lm70_show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ return sprintf(buf, "lm70\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
+
/*----------------------------------------------------------------------*/
static int __devinit lm70_probe(struct spi_device *spi)
@@ -107,15 +115,16 @@ static int __devinit lm70_probe(struct spi_device *spi)
init_MUTEX(&p_lm70->sem);
/* sysfs hook */
- p_lm70->cdev = hwmon_device_register(&spi->dev);
- if (IS_ERR(p_lm70->cdev)) {
+ p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
+ if (IS_ERR(p_lm70->hwmon_dev)) {
dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
- status = PTR_ERR(p_lm70->cdev);
+ status = PTR_ERR(p_lm70->hwmon_dev);
goto out_dev_reg_failed;
}
dev_set_drvdata(&spi->dev, p_lm70);
- if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) {
+ if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
+ || (status = device_create_file(&spi->dev, &dev_attr_name))) {
dev_dbg(&spi->dev, "device_create_file failure.\n");
goto out_dev_create_file_failed;
}
@@ -123,7 +132,8 @@ static int __devinit lm70_probe(struct spi_device *spi)
return 0;
out_dev_create_file_failed:
- hwmon_device_unregister(p_lm70->cdev);
+ device_remove_file(&spi->dev, &dev_attr_temp1_input);
+ hwmon_device_unregister(p_lm70->hwmon_dev);
out_dev_reg_failed:
dev_set_drvdata(&spi->dev, NULL);
kfree(p_lm70);
@@ -135,7 +145,8 @@ static int __devexit lm70_remove(struct spi_device *spi)
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
device_remove_file(&spi->dev, &dev_attr_temp1_input);
- hwmon_device_unregister(p_lm70->cdev);
+ device_remove_file(&spi->dev, &dev_attr_name);
+ hwmon_device_unregister(p_lm70->hwmon_dev);
dev_set_drvdata(&spi->dev, NULL);
kfree(p_lm70);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index a40166ffad1..37a8cc032ff 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = {
/* Each client has this additional data */
struct lm75_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
struct i2c_client *client = to_i2c_client(dev);
struct lm75_data *data = i2c_get_clientdata(client);
int nr = attr->index;
- unsigned long temp = simple_strtoul(buf, NULL, 10);
+ long temp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp[nr] = LM75_TEMP_TO_REG(temp);
@@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -240,7 +240,7 @@ exit:
static int lm75_detach_client(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm75_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index af7dc650ee1..7c93454bb4e 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -33,7 +33,7 @@
/* TEMP: 0.001C/bit (-55C to +125C)
REG: (0.5C/bit, two's complement) << 7 */
-static inline u16 LM75_TEMP_TO_REG(int temp)
+static inline u16 LM75_TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
ntemp += (ntemp<0 ? -250 : 250);
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index dd969f1e841..cee5c2e8cfa 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77);
/* Each client has this additional data */
struct lm77_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
@@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm77_data *data = i2c_get_clientdata(client); \
- long val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->value = val; \
@@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -358,7 +358,7 @@ exit:
static int lm77_detach_client(struct i2c_client *client)
{
struct lm77_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm77_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 6eea3476b90..3f7055ee679 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val)
the driver field to differentiate between I2C and ISA chips. */
struct lm78_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct lm78_data *data = lm78_update_device(dev);
+ int nr = to_sensor_dev_attr(da)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+
/* This function is called when:
* lm78_driver is inserted (when this module is loaded), for each
available adapter
@@ -453,36 +472,47 @@ static struct attribute *lm78_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in6_min.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_cpu0_vid.attr,
@@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client)
struct lm78_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm78_group);
if ((err = i2c_detach_client(client)))
@@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
|| (err = device_create_file(&pdev->dev, &dev_attr_name)))
goto exit_remove_files;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev)
{
struct lm78_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
device_remove_file(&pdev->dev, &dev_attr_name);
release_region(data->client.addr, LM78_EXTENT);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 064516d824a..063cdba00a8 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp)
struct lm80_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
goto error_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove;
}
@@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client)
struct lm80_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm80_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 654c0f73464..0336b4572a6 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = {
struct lm83_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client)
struct lm83_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm83_group);
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 20a8c648280..a02480be65f 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -30,6 +30,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -122,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
#define EMC6D102_REG_EXTEND_ADC3 0x87
#define EMC6D102_REG_EXTEND_ADC4 0x88
-#define LM85_ALARM_IN0 0x0001
-#define LM85_ALARM_IN1 0x0002
-#define LM85_ALARM_IN2 0x0004
-#define LM85_ALARM_IN3 0x0008
-#define LM85_ALARM_TEMP1 0x0010
-#define LM85_ALARM_TEMP2 0x0020
-#define LM85_ALARM_TEMP3 0x0040
-#define LM85_ALARM_ALARM2 0x0080
-#define LM85_ALARM_IN4 0x0100
-#define LM85_ALARM_RESERVED 0x0200
-#define LM85_ALARM_FAN1 0x0400
-#define LM85_ALARM_FAN2 0x0800
-#define LM85_ALARM_FAN3 0x1000
-#define LM85_ALARM_FAN4 0x2000
-#define LM85_ALARM_TEMP1_FAULT 0x4000
-#define LM85_ALARM_TEMP3_FAULT 0x8000
-
/* Conversions. Rounding and limit checking is only done on the TO_REG
variants. Note that you should be a bit careful with which arguments
@@ -155,22 +139,26 @@ static int lm85_scaling[] = { /* .001 Volts */
#define INS_TO_REG(n,val) \
SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
-#define INSEXT_FROM_REG(n,val,ext,scale) \
- SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+#define INSEXT_FROM_REG(n,val,ext) \
+ SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
-#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1)
+#define INS_FROM_REG(n,val) SCALE((val), 192, lm85_scaling[n])
/* FAN speed is measured using 90kHz clock */
-#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
+static inline u16 FAN_TO_REG(unsigned long val)
+{
+ if (!val)
+ return 0xffff;
+ return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+}
#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val))
/* Temperature is reported in .001 degC increments */
#define TEMP_TO_REG(val) \
SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
-#define TEMPEXT_FROM_REG(val,ext,scale) \
- SCALE((val)*scale + (ext),scale,1000)
-#define TEMP_FROM_REG(val) \
- TEMPEXT_FROM_REG(val,0,1)
+#define TEMPEXT_FROM_REG(val,ext) \
+ SCALE(((val) << 4) + (ext), 16, 1000)
+#define TEMP_FROM_REG(val) ((val) * 1000)
#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
#define PWM_FROM_REG(val) (val)
@@ -328,7 +316,7 @@ struct lm85_autofan {
The structure is dynamically allocated. */
struct lm85_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -350,7 +338,6 @@ struct lm85_data {
u8 tach_mode; /* Register encoding, combined */
u8 temp_ext[3]; /* Decoded values */
u8 in_ext[8]; /* Decoded values */
- u8 adc_scale; /* ADC Extended bits scaling factor */
u8 fan_ppr; /* Register value */
u8 smooth[3]; /* Register encoding */
u8 vid; /* Register value */
@@ -387,22 +374,29 @@ static struct i2c_driver lm85_driver = {
/* 4 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
- long val = simple_strtol(buf, NULL, 10);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val);
@@ -412,23 +406,10 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \
- NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1)
show_fan_offset(1);
show_fan_offset(2);
@@ -457,7 +438,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lm85_data *data = lm85_update_device(dev);
+ struct lm85_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
@@ -482,16 +463,46 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct lm85_data *data = lm85_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13);
+
/* pwm */
-static ssize_t show_pwm(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) );
}
-static ssize_t set_pwm(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -502,8 +513,11 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+ *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
int pwm_zone;
@@ -512,23 +526,10 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
}
#define show_pwm_reg(offset) \
-static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_enable(dev, buf, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_pwm_##offset, set_pwm_##offset); \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
- show_pwm_enable##offset, NULL);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
+ show_pwm_enable, NULL, offset - 1)
show_pwm_reg(1);
show_pwm_reg(2);
@@ -536,22 +537,28 @@ show_pwm_reg(3);
/* Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr,
data->in[nr],
- data->in_ext[nr],
- data->adc_scale) );
+ data->in_ext[nr]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) );
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -562,14 +569,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) );
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -580,59 +592,47 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define show_in_reg(offset) \
-static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \
- NULL); \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in_##offset##_min, set_in_##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in_##offset##_max, set_in_##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset)
show_in_reg(0);
show_in_reg(1);
show_in_reg(2);
show_in_reg(3);
show_in_reg(4);
+show_in_reg(5);
+show_in_reg(6);
+show_in_reg(7);
/* Temps */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
- data->temp_ext[nr],
- data->adc_scale) );
+ data->temp_ext[nr]));
}
-static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) );
}
-static ssize_t set_temp_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -643,14 +643,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) );
}
-static ssize_t set_temp_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -661,35 +666,14 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define show_temp_reg(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_max(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \
- NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_min, set_temp_##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_max, set_temp_##offset##_max);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, offset - 1);
show_temp_reg(1);
show_temp_reg(2);
@@ -698,14 +682,18 @@ show_temp_reg(3);
/* Automatic PWM control */
-static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config));
}
-static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -718,14 +706,19 @@ static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm));
}
-static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -737,14 +730,19 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_minctl(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", data->autofan[nr].min_off);
}
-static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -760,14 +758,19 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq));
}
-static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_freq(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -781,74 +784,40 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define pwm_auto(offset) \
-static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_channels(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_channels(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_channels, \
- set_pwm##offset##_auto_channels); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_min, \
- set_pwm##offset##_auto_pwm_min); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_minctl, \
- set_pwm##offset##_auto_pwm_minctl); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_freq, \
- set_pwm##offset##_auto_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_channels, \
+ set_pwm_auto_channels, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min, \
+ set_pwm_auto_pwm_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl, \
+ set_pwm_auto_pwm_minctl, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_freq, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_freq, \
+ set_pwm_auto_pwm_freq, offset - 1);
+
pwm_auto(1);
pwm_auto(2);
pwm_auto(3);
/* Temperature settings for automatic PWM control */
-static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_auto_temp_off(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) -
HYST_FROM_REG(data->zone[nr].hyst));
}
-static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_off(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int min;
@@ -871,14 +840,19 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) );
}
-static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_min(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -913,15 +887,20 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) +
RANGE_FROM_REG(data->zone[nr].range));
}
-static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_max(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int min;
@@ -938,14 +917,19 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_crit(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical));
}
-static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_crit(struct device *dev,
+ struct device_attribute *attr,const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -957,59 +941,21 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define temp_auto(offset) \
-static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_off(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_off(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_max(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_crit(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_off, \
- set_temp##offset##_auto_temp_off); \
-static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_min, \
- set_temp##offset##_auto_temp_min); \
-static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_max, \
- set_temp##offset##_auto_temp_max); \
-static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_crit, \
- set_temp##offset##_auto_temp_crit);
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_off, \
+ set_temp_auto_temp_off, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_min, \
+ set_temp_auto_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_max, \
+ set_temp_auto_temp_max, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_crit, \
+ set_temp_auto_temp_crit, offset - 1);
+
temp_auto(1);
temp_auto(2);
temp_auto(3);
@@ -1022,69 +968,87 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *lm85_attributes[] = {
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan3_input.attr,
- &dev_attr_fan4_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan4_min.attr,
- &dev_attr_pwm1.attr,
- &dev_attr_pwm2.attr,
- &dev_attr_pwm3.attr,
- &dev_attr_pwm1_enable.attr,
- &dev_attr_pwm2_enable.attr,
- &dev_attr_pwm3_enable.attr,
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp3_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp3_max.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_freq.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr,
+
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_alarms.attr,
- &dev_attr_pwm1_auto_channels.attr,
- &dev_attr_pwm2_auto_channels.attr,
- &dev_attr_pwm3_auto_channels.attr,
- &dev_attr_pwm1_auto_pwm_min.attr,
- &dev_attr_pwm2_auto_pwm_min.attr,
- &dev_attr_pwm3_auto_pwm_min.attr,
- &dev_attr_pwm1_auto_pwm_minctl.attr,
- &dev_attr_pwm2_auto_pwm_minctl.attr,
- &dev_attr_pwm3_auto_pwm_minctl.attr,
- &dev_attr_pwm1_auto_pwm_freq.attr,
- &dev_attr_pwm2_auto_pwm_freq.attr,
- &dev_attr_pwm3_auto_pwm_freq.attr,
- &dev_attr_temp1_auto_temp_off.attr,
- &dev_attr_temp2_auto_temp_off.attr,
- &dev_attr_temp3_auto_temp_off.attr,
- &dev_attr_temp1_auto_temp_min.attr,
- &dev_attr_temp2_auto_temp_min.attr,
- &dev_attr_temp3_auto_temp_min.attr,
- &dev_attr_temp1_auto_temp_max.attr,
- &dev_attr_temp2_auto_temp_max.attr,
- &dev_attr_temp3_auto_temp_max.attr,
- &dev_attr_temp1_auto_temp_crit.attr,
- &dev_attr_temp2_auto_temp_crit.attr,
- &dev_attr_temp3_auto_temp_crit.attr,
-
NULL
};
@@ -1092,16 +1056,36 @@ static const struct attribute_group lm85_group = {
.attrs = lm85_attributes,
};
-static struct attribute *lm85_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
+static struct attribute *lm85_attributes_in4[] = {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm85_group_in4 = {
+ .attrs = lm85_attributes_in4,
+};
+static struct attribute *lm85_attributes_in567[] = {
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
NULL
};
-static const struct attribute_group lm85_group_opt = {
- .attrs = lm85_attributes_opt,
+static const struct attribute_group lm85_group_in567 = {
+ .attrs = lm85_attributes_in567,
};
static int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1249,17 +1233,19 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
as a sixth digital VID input rather than an analog input. */
data->vid = lm85_read_value(new_client, LM85_REG_VID);
if (!(kind == adt7463 && (data->vid & 0x80)))
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm85_group_in4)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* The EMC6D100 has 3 additional voltage inputs */
+ if (kind == emc6d100)
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm85_group_in567)))
+ goto ERROR3;
+
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR3;
}
@@ -1268,7 +1254,9 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
/* Error out and cleanup code */
ERROR3:
sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
- sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4);
+ if (kind == emc6d100)
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -1280,9 +1268,11 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
static int lm85_detach_client(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm85_group);
- sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
+ if (data->type == emc6d100)
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
i2c_detach_client(client);
kfree(data);
return 0;
@@ -1405,6 +1395,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
/* Have to read extended bits first to "freeze" the
* more significant bits that are read later.
+ * There are 2 additional resolution bits per channel and we
+ * have room for 4, so we shift them to the left.
*/
if ( (data->type == adm1027) || (data->type == adt7463) ) {
int ext1 = lm85_read_value(client,
@@ -1414,18 +1406,12 @@ static struct lm85_data *lm85_update_device(struct device *dev)
int val = (ext1 << 8) + ext2;
for(i = 0; i <= 4; i++)
- data->in_ext[i] = (val>>(i * 2))&0x03;
+ data->in_ext[i] = ((val>>(i * 2))&0x03) << 2;
for(i = 0; i <= 2; i++)
- data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
+ data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c;
}
- /* adc_scale is 2^(number of LSBs). There are 4 extra bits in
- the emc6d102 and 2 in the adt7463 and adm1027. In all
- other chips ext is always 0 and the value of scale is
- irrelevant. So it is left in 4*/
- data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
-
data->vid = lm85_read_value(client, LM85_REG_VID);
for (i = 0; i <= 3; ++i) {
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 988ae1c4aad..28cdff0c556 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -58,6 +58,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
(((val) < 0 ? (val)-500 : (val)+500) / 1000))
#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \
- 1350000 + (reg)*(div) / 2) / ((reg)*(div))
+ (1350000 + (reg)*(div) / 2) / ((reg)*(div)))
#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \
(1350000 + (val)*(div) / 2) / ((val)*(div)))
@@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
#define CHAN_NO_FAN(nr) (1 << (nr))
#define CHAN_TEMP3 (1 << 2)
#define CHAN_VCC_5V (1 << 3)
-#define CHAN_NO_VID (1 << 8)
+#define CHAN_NO_VID (1 << 7)
/*
* Functions declaration
@@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = {
struct lm87_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -500,7 +501,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lm87_data *data = lm87_update_device(dev);
+ struct lm87_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm87_data *data = lm87_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+
/*
* Real code
*/
@@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = {
&dev_attr_in1_input.attr,
&dev_attr_in1_min.attr,
&dev_attr_in1_max.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&dev_attr_in2_input.attr,
&dev_attr_in2_min.attr,
&dev_attr_in2_max.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&dev_attr_in3_input.attr,
&dev_attr_in3_min.attr,
&dev_attr_in3_max.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&dev_attr_in4_input.attr,
&dev_attr_in4_min.attr,
&dev_attr_in4_max.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_min.attr,
&dev_attr_temp1_crit.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&dev_attr_temp2_input.attr,
&dev_attr_temp2_max.attr,
&dev_attr_temp2_min.attr,
&dev_attr_temp2_crit.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
@@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = {
&dev_attr_in6_input.attr,
&dev_attr_in6_min.attr,
&dev_attr_in6_max.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
&dev_attr_fan1_input.attr,
&dev_attr_fan1_min.attr,
&dev_attr_fan1_div.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&dev_attr_in7_input.attr,
&dev_attr_in7_min.attr,
&dev_attr_in7_max.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
&dev_attr_fan2_input.attr,
&dev_attr_fan2_min.attr,
&dev_attr_fan2_div.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_temp3_input.attr,
&dev_attr_temp3_max.attr,
&dev_attr_temp3_min.attr,
&dev_attr_temp3_crit.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&dev_attr_in5_input.attr,
&dev_attr_in5_min.attr,
&dev_attr_in5_max.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in6_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in6_max)))
+ &dev_attr_in6_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in6_alarm.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_fan1_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_fan1_div)))
+ &dev_attr_fan1_div))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_alarm.dev_attr)))
goto exit_remove;
}
@@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in7_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in7_max)))
+ &dev_attr_in7_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in7_alarm.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_fan2_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_fan2_div)))
+ &dev_attr_fan2_div))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_alarm.dev_attr)))
goto exit_remove;
}
@@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_temp3_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_crit)))
+ &dev_attr_temp3_crit))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_alarm.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_fault.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -738,11 +789,15 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in0_max))
|| (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in0_alarm.dev_attr))
+ || (err = device_create_file(&new_client->dev,
&dev_attr_in5_input))
|| (err = device_create_file(&new_client->dev,
&dev_attr_in5_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in5_max)))
+ &dev_attr_in5_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in5_alarm.dev_attr)))
goto exit_remove;
}
@@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client)
struct lm87_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm87_group);
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index af541d67245..960df9fa75a 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -41,7 +41,8 @@
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
* Note that there is no easy way to differentiate between the three
* variants. The extra address and features of the MAX6659 are not
- * supported by this driver.
+ * supported by this driver. These chips lack the remote temperature
+ * offset feature.
*
* This driver also supports the MAX6680 and MAX6681, two other sensor
* chips made by Maxim. These are quite similar to the other Maxim
@@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = {
struct lm90_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -226,9 +227,10 @@ struct lm90_data {
2: local high limit
3: local critical limit
4: remote critical limit */
- s16 temp11[3]; /* 0: remote input
+ s16 temp11[4]; /* 0: remote input
1: remote low limit
- 2: remote high limit */
+ 2: remote high limit
+ 3: remote offset (except max6657) */
u8 temp_hyst;
u8 alarms; /* bitvector */
};
@@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- static const u8 reg[4] = {
+ static const u8 reg[6] = {
LM90_REG_W_REMOTE_LOWH,
LM90_REG_W_REMOTE_LOWL,
LM90_REG_W_REMOTE_HIGHH,
LM90_REG_W_REMOTE_HIGHL,
+ LM90_REG_W_REMOTE_OFFSH,
+ LM90_REG_W_REMOTE_OFFSL,
};
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -367,6 +371,8 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
set_temphyst, 3);
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 3);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
@@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
&dev_attr_pec)))
goto exit_remove_files;
}
+ if (data->kind != max6657) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_offset.dev_attr)))
+ goto exit_remove_files;
+ }
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client)
struct lm90_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm90_group);
device_remove_file(&client->dev, &dev_attr_pec);
+ if (data->kind != max6657)
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp2_offset.dev_attr);
if ((err = i2c_detach_client(client)))
return err;
@@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0
&& lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0)
data->temp11[2] = (newh << 8) | l;
+ if (data->kind != max6657) {
+ if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+ &newh) == 0
+ && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+ &l) == 0)
+ data->temp11[3] = (newh << 8) | l;
+ }
lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
data->last_updated = jiffies;
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 30b536333f1..61d1bd1d5b6 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver;
/* Client data (each client gets its own) */
struct lm92_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client)
struct lm92_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm92_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index d84f8bf6f28..ea61946a4bf 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -201,7 +201,7 @@ struct block1_t {
*/
struct lm93_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
@@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
/* TEMP: 1/1000 degrees C (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 LM93_TEMP_TO_REG(int temp)
+static u8 LM93_TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
@@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
@@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->block10.base[nr] = LM93_TEMP_TO_REG(val);
@@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->boost[nr] = LM93_TEMP_TO_REG(val);
@@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
}
-static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
-static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1);
static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = {
&sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
&dev_attr_pwm_auto_prochot_ramp.attr,
&dev_attr_pwm_auto_vrdhot_ramp.attr,
- &sensor_dev_attr_vid1.dev_attr.attr,
- &sensor_dev_attr_vid2.dev_attr.attr,
+ &sensor_dev_attr_cpu0_vid.dev_attr.attr,
+ &sensor_dev_attr_cpu1_vid.dev_attr.attr,
&sensor_dev_attr_prochot1.dev_attr.attr,
&sensor_dev_attr_prochot2.dev_attr.attr,
&sensor_dev_attr_prochot1_avg.dev_attr.attr,
@@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
goto err_detach;
/* Register hwmon driver class */
- data->class_dev = hwmon_device_register(&client->dev);
- if ( !IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if ( !IS_ERR(data->hwmon_dev))
return 0;
- err = PTR_ERR(data->class_dev);
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
err_detach:
@@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client)
struct lm93_data *data = i2c_get_clientdata(client);
int err = 0;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 2f58f651f03..38a44c3d6ce 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = {
struct max1619_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client)
struct max1619_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &max1619_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 8415664f33c..755570c1f4e 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = {
struct max6650_data
{
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto err_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (!IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (!IS_ERR(data->hwmon_dev))
return 0;
- err = PTR_ERR(data->class_dev);
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
err_detach:
@@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client)
int err;
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
err = i2c_detach_client(client);
if (!err)
kfree(data);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index f57c75d59a5..9d660133d51 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
struct pc87360_data {
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -500,7 +500,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct pc87360_data *data = pc87360_update_device(dev);
+ struct pc87360_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_name)))
goto ERROR3;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR3;
}
return 0;
@@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev)
struct pc87360_data *data = platform_get_drvdata(pdev);
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 2915bc4ad0d..d40509ad6ae 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -42,7 +42,7 @@ static struct platform_device *pdev;
device is using banked registers) and the register cache (needed to keep
the data in the registers and the cache in sync at any time). */
struct pc87427_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
int address[2];
const char *name;
@@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
goto exit_remove_files;
}
@@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
struct resource *res;
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
for (i = 0; i < 8; i++) {
if (!(data->fan_enabled & (1 << i)))
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 92956eb3f3c..860b71ccbb8 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val)
struct sis5595_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -517,7 +517,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
/* Check revision and pin registers to determine whether 4 or 5 voltages */
- pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
+ data->revision = s_bridge->revision;
/* 4 voltages, 1 temp */
data->maxins = 3;
if (data->revision >= REV2MIN) {
@@ -557,9 +557,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -580,7 +580,7 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
{
struct sis5595_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
@@ -739,11 +739,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
int *i;
for (i = blacklist; *i != 0; i++) {
- struct pci_dev *dev;
- dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
- if (dev) {
- dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
- pci_dev_put(dev);
+ struct pci_dev *d;
+ if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
+ dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+ pci_dev_put(d);
return -ENODEV;
}
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 45266b30ce1..0b57d2ea2cf 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
struct smsc47b397_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev)
struct smsc47b397_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, SMSC_EXTENT);
@@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
goto error_free;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index d3181967f16..a10a380868e 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -116,7 +116,7 @@ struct smsc47m1_data {
unsigned short addr;
const char *name;
enum chips type;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
@@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_div.dev_attr)))
goto error_remove_files;
- } else
+ } else if (data->type == smsc47m2)
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
if (pwm1) {
@@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_pwm3_enable.dev_attr)))
goto error_remove_files;
- } else
+ } else if (data->type == smsc47m2)
dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
if ((err = device_create_file(dev, &dev_attr_alarms)))
@@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_name)))
goto error_remove_files;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove_files;
}
@@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index d3a3ba04cb0..b8755265258 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val)
struct smsc47m192_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -334,7 +334,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ struct smsc47m192_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client)
struct smsc47m192_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 9395b52d9b9..04dd7699b3a 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
#define THMC50_REG_COMPANY_ID 0x3E
#define THMC50_REG_DIE_CODE 0x3F
#define THMC50_REG_ANALOG_OUT 0x19
+/*
+ * The mirror status register cannot be used as
+ * reading it does not clear alarms.
+ */
+#define THMC50_REG_INTR 0x41
const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
@@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
/* Each client has this additional data */
struct thmc50_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
enum chips type;
@@ -69,6 +74,7 @@ struct thmc50_data {
s8 temp_max[3];
s8 temp_min[3];
u8 analog_out;
+ u8 alarms;
};
static int thmc50_attach_adapter(struct i2c_adapter *adapter);
@@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct thmc50_data *data = thmc50_update_device(dev);
+
+ return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
#define temp_reg(offset) \
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
NULL, offset - 1); \
@@ -192,6 +207,12 @@ temp_reg(1);
temp_reg(2);
temp_reg(3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
set_analog_out, 0);
static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
@@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
NULL
@@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = {
};
/* for ADM1022 3rd temperature mode */
-static struct attribute *adm1022_attributes[] = {
+static struct attribute *temp3_attributes[] = {
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
NULL
};
-static const struct attribute_group adm1022_group = {
- .attrs = adm1022_attributes,
+static const struct attribute_group temp3_group = {
+ .attrs = temp3_attributes,
};
static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
struct thmc50_data *data;
struct device *dev;
int err = 0;
- const char *type_name = "";
+ const char *type_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("thmc50: detect failed, "
@@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
goto exit_free;
}
- pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
- type_name, (revision >> 4) - 0xc, revision & 0xf);
data->type = kind;
- if (kind == thmc50)
- type_name = "thmc50";
- else if (kind == adm1022) {
+ if (kind == adm1022) {
int id = i2c_adapter_id(client->adapter);
int i;
@@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
data->has_temp3 = 1;
break;
}
+ } else {
+ type_name = "thmc50";
}
+ pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+ type_name, (revision >> 4) - 0xc, revision & 0xf);
/* Fill in the remaining client fields & put it into the global list */
strlcpy(client->name, type_name, I2C_NAME_SIZE);
@@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_detach;
/* Register ADM1022 sysfs hooks */
- if (data->type == adm1022)
+ if (data->has_temp3)
if ((err = sysfs_create_group(&client->dev.kobj,
- &adm1022_group)))
+ &temp3_group)))
goto exit_remove_sysfs_thmc50;
/* Register a new directory entry with module sensors */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_sysfs;
}
return 0;
exit_remove_sysfs:
- if (data->type == adm1022)
- sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+ if (data->has_temp3)
+ sysfs_remove_group(&client->dev.kobj, &temp3_group);
exit_remove_sysfs_thmc50:
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
exit_detach:
@@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client)
struct thmc50_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
- if (data->type == adm1022)
- sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+ if (data->has_temp3)
+ sysfs_remove_group(&client->dev.kobj, &temp3_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
}
data->analog_out =
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+ data->alarms =
+ i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
data->last_updated = jiffies;
data->valid = 1;
}
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 696c8a2e537..8f63dada601 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val)
struct via686a_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
goto exit_free;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev)
{
struct via686a_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
release_region(data->addr, VIA686A_EXTENT);
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 9f3e332c5b7..e69416465e6 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -108,7 +108,7 @@ static const u8 bitalarmfan[] = {6, 7};
struct vt1211_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
}
/* Register device */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(dev, "Class registration failed (%d)\n", err);
goto EXIT_DEV_REMOVE_SILENT;
}
@@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
struct vt1211_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
vt1211_remove_sysfs(pdev);
platform_set_drvdata(pdev, NULL);
kfree(data);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 3e63eaf1904..2196a84603f 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -148,7 +148,7 @@ struct vt8231_data {
const char *name;
struct mutex update_lock;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = {
.probe = vt8231_pci_probe,
};
-int vt8231_probe(struct platform_device *pdev)
+static int vt8231_probe(struct platform_device *pdev)
{
struct resource *res;
struct vt8231_data *data;
@@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev)
}
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
return 0;
@@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
struct vt8231_data *data = platform_get_drvdata(pdev);
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index d9a9ec7dd84..b15c6a998b7 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -223,7 +223,7 @@ temp1_from_reg(s8 reg)
}
static inline s8
-temp1_to_reg(int temp, int min, int max)
+temp1_to_reg(long temp, int min, int max)
{
if (temp <= min)
return min / 1000;
@@ -256,7 +256,7 @@ struct w83627ehf_data {
int addr; /* IO base of hw monitor block */
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- u32 val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
@@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- u32 val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->reg[nr] = LM75_TEMP_TO_REG(val); \
@@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev)
{
struct w83627ehf_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
w83627ehf_device_remove_files(&pdev->dev);
release_region(data->addr, IOREGION_LENGTH);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 7a4a15f4bf8..20ae425a198 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -45,6 +45,7 @@
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -218,7 +219,7 @@ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
W83627THF_REG_PWM3 };
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
- regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+ regpwm_627hf[nr] : regpwm[nr])
#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
@@ -263,7 +264,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* TEMP: 0.001C/bit (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -346,7 +347,7 @@ static inline u8 DIV_TO_REG(long val)
struct w83627hf_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -372,11 +373,8 @@ struct w83627hf_data {
u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
u8 pwm_freq[3]; /* Register value */
- u16 sens[3]; /* 782D/783S only.
- 1 = pentium diode; 2 = 3904 diode;
- 3000-5000 = thermistor beta.
- Default = 3435.
- Other Betas unimplemented */
+ u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
+ 4 = thermistor */
u8 vrm;
u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
};
@@ -391,6 +389,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev);
static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
+static void w83627hf_update_fan_div(struct w83627hf_data *data);
static struct w83627hf_data *w83627hf_update_device(struct device *dev);
static void w83627hf_init_device(struct platform_device *pdev);
@@ -403,72 +402,71 @@ static struct platform_driver w83627hf_driver = {
.remove = __devexit_p(w83627hf_remove),
};
-/* following are the sysfs callback functions */
-#define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
+static ssize_t
+show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
}
-show_in_reg(in)
-show_in_reg(in_min)
-show_in_reg(in_max)
-
-#define store_in_reg(REG, reg) \
-static ssize_t \
-store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
- struct w83627hf_data *data = dev_get_drvdata(dev); \
- u32 val; \
- \
- val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->in_##reg[nr] = IN_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
- data->in_##reg[nr]); \
- \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
}
-store_in_reg(MIN, min)
-store_in_reg(MAX, max)
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
+}
+static ssize_t
+store_in_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
-#define sysfs_in_offset(offset) \
-static ssize_t \
-show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
+ mutex_lock(&data->update_lock);
+ data->in_min[nr] = IN_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+static ssize_t
+store_in_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
-#define sysfs_in_reg_offset(reg, offset) \
-static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_in_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
- show_regs_in_##reg##offset, store_regs_in_##reg##offset);
-
-#define sysfs_in_offsets(offset) \
-sysfs_in_offset(offset) \
-sysfs_in_reg_offset(min, offset) \
-sysfs_in_reg_offset(max, offset)
-
-sysfs_in_offsets(1);
-sysfs_in_offsets(2);
-sysfs_in_offsets(3);
-sysfs_in_offsets(4);
-sysfs_in_offsets(5);
-sysfs_in_offsets(6);
-sysfs_in_offsets(7);
-sysfs_in_offsets(8);
+ mutex_lock(&data->update_lock);
+ data->in_max[nr] = IN_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+#define sysfs_vin_decl(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
+ show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
+ show_in_max, store_in_max, offset);
+
+sysfs_vin_decl(1);
+sysfs_vin_decl(2);
+sysfs_vin_decl(3);
+sysfs_vin_decl(4);
+sysfs_vin_decl(5);
+sysfs_vin_decl(6);
+sysfs_vin_decl(7);
+sysfs_vin_decl(8);
/* use a different set of functions for in0 */
static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
@@ -566,134 +564,148 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
show_regs_in_max0, store_regs_in_max0);
-#define show_fan_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- return sprintf(buf,"%ld\n", \
- FAN_FROM_REG(data->reg[nr-1], \
- (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+static ssize_t
+show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
+ (long)DIV_FROM_REG(data->fan_div[nr])));
}
-show_fan_reg(fan);
-show_fan_reg(fan_min);
-
static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
+ (long)DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
- u32 val;
-
- val = simple_strtoul(buf, NULL, 10);
+ u32 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->fan_min[nr - 1] =
- FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
- w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
- data->fan_min[nr - 1]);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
+ data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
+#define sysfs_fan_decl(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan_input, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, store_fan_min, offset - 1);
-#define sysfs_fan_offset(offset) \
-static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
+sysfs_fan_decl(1);
+sysfs_fan_decl(2);
+sysfs_fan_decl(3);
-#define sysfs_fan_min_offset(offset) \
-static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_fan_min(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_regs_fan_min##offset, store_regs_fan_min##offset);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
-
-#define show_temp_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- if (nr >= 2) { /* TEMP2 and TEMP3 */ \
- return sprintf(buf,"%ld\n", \
- (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
- } else { /* TEMP1 */ \
- return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
- } \
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ if (nr >= 2) { /* TEMP2 and TEMP3 */
+ return sprintf(buf, "%ld\n",
+ (long)LM75_TEMP_FROM_REG(data->temp_add[nr-2]));
+ } else { /* TEMP1 */
+ return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp));
+ }
}
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
-#define store_temp_reg(REG, reg) \
-static ssize_t \
-store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
- struct w83627hf_data *data = dev_get_drvdata(dev); \
- u32 val; \
- \
- val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- \
- if (nr >= 2) { /* TEMP2 and TEMP3 */ \
- data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
- data->temp_##reg##_add[nr-2]); \
- } else { /* TEMP1 */ \
- data->temp_##reg = TEMP_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
- data->temp_##reg); \
- } \
- \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ if (nr >= 2) { /* TEMP2 and TEMP3 */
+ return sprintf(buf, "%ld\n",
+ (long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2]));
+ } else { /* TEMP1 */
+ return sprintf(buf, "%ld\n",
+ (long)TEMP_FROM_REG(data->temp_max));
+ }
}
-store_temp_reg(OVER, max);
-store_temp_reg(HYST, max_hyst);
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
+static ssize_t
+show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ if (nr >= 2) { /* TEMP2 and TEMP3 */
+ return sprintf(buf, "%ld\n",
+ (long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2]));
+ } else { /* TEMP1 */
+ return sprintf(buf, "%ld\n",
+ (long)TEMP_FROM_REG(data->temp_max_hyst));
+ }
+}
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_temp_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
- show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
+static ssize_t
+store_temp_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
-#define sysfs_temp_offsets(offset) \
-sysfs_temp_offset(offset) \
-sysfs_temp_reg_offset(max, offset) \
-sysfs_temp_reg_offset(max_hyst, offset)
+ mutex_lock(&data->update_lock);
-sysfs_temp_offsets(1);
-sysfs_temp_offsets(2);
-sysfs_temp_offsets(3);
+ if (nr >= 2) { /* TEMP2 and TEMP3 */
+ data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
+ data->temp_max_add[nr-2]);
+ } else { /* TEMP1 */
+ data->temp_max = TEMP_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
+ data->temp_max);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ if (nr >= 2) { /* TEMP2 and TEMP3 */
+ data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
+ data->temp_max_hyst_add[nr-2]);
+ } else { /* TEMP1 */
+ data->temp_max_hyst = TEMP_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
+ data->temp_max_hyst);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define sysfs_temp_decl(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
+ show_temp_max, store_temp_max, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
+ show_temp_max_hyst, store_temp_max_hyst, offset);
+
+sysfs_temp_decl(1);
+sysfs_temp_decl(2);
+sysfs_temp_decl(3);
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -706,7 +718,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct w83627hf_data *data = w83627hf_update_device(dev);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
static ssize_t
@@ -791,20 +803,22 @@ sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
static ssize_t
-show_fan_div_reg(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
return sprintf(buf, "%ld\n",
- (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+ (long) DIV_FROM_REG(data->fan_div[nr]));
}
-
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_div(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
unsigned long min;
u8 reg;
@@ -836,92 +850,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define sysfs_fan_div(offset) \
-static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_fan_div_reg(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_regs_fan_div_##offset, store_regs_fan_div_##offset);
-
-sysfs_fan_div(1);
-sysfs_fan_div(2);
-sysfs_fan_div(3);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 2);
static ssize_t
-show_pwm_reg(struct device *dev, char *buf, int nr)
+show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
+ return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
}
static ssize_t
-store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
- u32 val;
-
- val = simple_strtoul(buf, NULL, 10);
+ u32 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
if (data->type == w83627thf) {
/* bits 0-3 are reserved in 627THF */
- data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
+ data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
- data->pwm[nr - 1] |
+ data->pwm[nr] |
(w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
} else {
- data->pwm[nr - 1] = PWM_TO_REG(val);
+ data->pwm[nr] = PWM_TO_REG(val);
w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
- data->pwm[nr - 1]);
+ data->pwm[nr]);
}
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_pwm(offset) \
-static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_pwm_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_regs_pwm_##offset, store_regs_pwm_##offset);
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwm(3);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
static ssize_t
-show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
if (data->type == w83627hf)
return sprintf(buf, "%ld\n",
- pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+ pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
else
return sprintf(buf, "%ld\n",
- pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+ pwm_freq_from_reg(data->pwm_freq[nr]));
}
static ssize_t
-store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm_freq(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
static const u8 mask[]={0xF8, 0x8F};
u32 val;
@@ -931,50 +925,42 @@ store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
mutex_lock(&data->update_lock);
if (data->type == w83627hf) {
- data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+ data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
- (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+ (data->pwm_freq[nr] << (nr*4)) |
(w83627hf_read_value(data,
- W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+ W83627HF_REG_PWM_FREQ) & mask[nr]));
} else {
- data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
- w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
- data->pwm_freq[nr - 1]);
+ data->pwm_freq[nr] = pwm_freq_to_reg(val);
+ w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
+ data->pwm_freq[nr]);
}
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_pwm_freq(offset) \
-static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_freq_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_freq_##offset(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_pwm_freq_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
- show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
-
-sysfs_pwm_freq(1);
-sysfs_pwm_freq(2);
-sysfs_pwm_freq(3);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 2);
static ssize_t
-show_sensor_reg(struct device *dev, char *buf, int nr)
+show_temp_type(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+ return sprintf(buf, "%ld\n", (long) data->sens[nr]);
}
static ssize_t
-store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_temp_type(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val, tmp;
@@ -986,31 +972,35 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
case 1: /* PII/Celeron diode */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
+ tmp | BIT_SCFG1[nr]);
tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
w83627hf_write_value(data, W83781D_REG_SCFG2,
- tmp | BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp | BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
case 2: /* 3904 */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
+ tmp | BIT_SCFG1[nr]);
tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
w83627hf_write_value(data, W83781D_REG_SCFG2,
- tmp & ~BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp & ~BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
- case W83781D_DEFAULT_BETA: /* thermistor */
+ case W83781D_DEFAULT_BETA:
+ dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+ "instead\n", W83781D_DEFAULT_BETA);
+ /* fall through */
+ case 4: /* thermistor */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp & ~BIT_SCFG1[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp & ~BIT_SCFG1[nr]);
+ data->sens[nr] = val;
break;
default:
dev_err(dev,
- "Invalid sensor type %ld; must be 1, 2, or %d\n",
- (long) val, W83781D_DEFAULT_BETA);
+ "Invalid sensor type %ld; must be 1, 2, or 4\n",
+ (long) val);
break;
}
@@ -1018,25 +1008,16 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define sysfs_sensor(offset) \
-static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_sensor_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_sensor_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
- show_regs_sensor_##offset, store_regs_sensor_##offset);
+#define sysfs_temp_type(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+ show_temp_type, store_temp_type, offset - 1);
-sysfs_sensor(1);
-sysfs_sensor(2);
-sysfs_sensor(3);
+sysfs_temp_type(1);
+sysfs_temp_type(2);
+sysfs_temp_type(3);
-static ssize_t show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -1118,49 +1099,44 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
return err;
}
+#define VIN_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_max.dev_attr.attr
+
+#define FAN_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
+
static struct attribute *w83627hf_attributes[] = {
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
- &dev_attr_in7_input.attr,
- &dev_attr_in7_min.attr,
- &dev_attr_in7_max.attr,
- &dev_attr_in8_input.attr,
- &dev_attr_in8_min.attr,
- &dev_attr_in8_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp1_type.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_max_hyst.attr,
- &dev_attr_temp2_type.attr,
+ VIN_UNIT_ATTRS(2),
+ VIN_UNIT_ATTRS(3),
+ VIN_UNIT_ATTRS(4),
+ VIN_UNIT_ATTRS(7),
+ VIN_UNIT_ATTRS(8),
+
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
&dev_attr_alarms.attr,
&dev_attr_beep_enable.attr,
&dev_attr_beep_mask.attr,
- &dev_attr_pwm1.attr,
- &dev_attr_pwm2.attr,
-
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
&dev_attr_name.attr,
NULL
};
@@ -1170,30 +1146,17 @@ static const struct attribute_group w83627hf_group = {
};
static struct attribute *w83627hf_attributes_opt[] = {
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_in6_input.attr,
- &dev_attr_in6_min.attr,
- &dev_attr_in6_max.attr,
-
- &dev_attr_fan3_input.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan3_div.attr,
-
- &dev_attr_temp3_input.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp3_max_hyst.attr,
- &dev_attr_temp3_type.attr,
-
- &dev_attr_pwm3.attr,
-
- &dev_attr_pwm1_freq.attr,
- &dev_attr_pwm2_freq.attr,
- &dev_attr_pwm3_freq.attr,
+ VIN_UNIT_ATTRS(1),
+ VIN_UNIT_ATTRS(5),
+ VIN_UNIT_ATTRS(6),
+
+ FAN_UNIT_ATTRS(3),
+ TEMP_UNIT_ATTRS(3),
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_freq.dev_attr.attr,
NULL
};
@@ -1244,6 +1207,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
+ w83627hf_update_fan_div(data);
/* Register common device attributes */
if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
@@ -1251,27 +1215,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
/* Register chip-specific device attributes */
if (data->type == w83627hf || data->type == w83697hf)
- if ((err = device_create_file(dev, &dev_attr_in5_input))
- || (err = device_create_file(dev, &dev_attr_in5_min))
- || (err = device_create_file(dev, &dev_attr_in5_max))
- || (err = device_create_file(dev, &dev_attr_in6_input))
- || (err = device_create_file(dev, &dev_attr_in6_min))
- || (err = device_create_file(dev, &dev_attr_in6_max))
- || (err = device_create_file(dev, &dev_attr_pwm1_freq))
- || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in5_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in5_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in5_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_freq.dev_attr)))
goto ERROR4;
if (data->type != w83697hf)
- if ((err = device_create_file(dev, &dev_attr_in1_input))
- || (err = device_create_file(dev, &dev_attr_in1_min))
- || (err = device_create_file(dev, &dev_attr_in1_max))
- || (err = device_create_file(dev, &dev_attr_fan3_input))
- || (err = device_create_file(dev, &dev_attr_fan3_min))
- || (err = device_create_file(dev, &dev_attr_fan3_div))
- || (err = device_create_file(dev, &dev_attr_temp3_input))
- || (err = device_create_file(dev, &dev_attr_temp3_max))
- || (err = device_create_file(dev, &dev_attr_temp3_max_hyst))
- || (err = device_create_file(dev, &dev_attr_temp3_type)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in1_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_type.dev_attr)))
goto ERROR4;
if (data->type != w83697hf && data->vid != 0xff) {
@@ -1285,18 +1267,22 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
if (data->type == w83627thf || data->type == w83637hf
|| data->type == w83687thf)
- if ((err = device_create_file(dev, &dev_attr_pwm3)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm3.dev_attr)))
goto ERROR4;
if (data->type == w83637hf || data->type == w83687thf)
- if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
- || (err = device_create_file(dev, &dev_attr_pwm2_freq))
- || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm3_freq.dev_attr)))
goto ERROR4;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1319,7 +1305,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
struct w83627hf_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
@@ -1333,6 +1319,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
}
+/* Registers 0x50-0x5f are banked */
+static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
+{
+ if ((reg & 0x00f0) == 0x50) {
+ outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
+ }
+}
+
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
+{
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
+ }
+}
+
static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
{
int res, word_sized;
@@ -1343,12 +1347,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
&& (((reg & 0x00ff) == 0x50)
|| ((reg & 0x00ff) == 0x53)
|| ((reg & 0x00ff) == 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_set_bank(data, reg);
outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
if (word_sized) {
@@ -1358,11 +1357,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
(res << 8) + inb_p(data->addr +
W83781D_DATA_REG_OFFSET);
}
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return res;
}
@@ -1433,12 +1428,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
|| ((reg & 0xff00) == 0x200))
&& (((reg & 0x00ff) == 0x53)
|| ((reg & 0x00ff) == 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_set_bank(data, reg);
outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
if (word_sized) {
outb_p(value >> 8,
@@ -1448,11 +1438,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
}
outb_p(value & 0xff,
data->addr + W83781D_DATA_REG_OFFSET);
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return 0;
}
@@ -1513,7 +1499,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
- data->sens[i - 1] = W83781D_DEFAULT_BETA;
+ data->sens[i - 1] = 4;
} else {
if (w83627hf_read_value
(data,
@@ -1556,6 +1542,24 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
| 0x01);
}
+static void w83627hf_update_fan_div(struct w83627hf_data *data)
+{
+ int reg;
+
+ reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+ data->fan_div[0] = (reg >> 4) & 0x03;
+ data->fan_div[1] = (reg >> 6) & 0x03;
+ if (data->type != w83697hf) {
+ data->fan_div[2] = (w83627hf_read_value(data,
+ W83781D_REG_PIN) >> 6) & 0x03;
+ }
+ reg = w83627hf_read_value(data, W83781D_REG_VBAT);
+ data->fan_div[0] |= (reg >> 3) & 0x04;
+ data->fan_div[1] |= (reg >> 4) & 0x04;
+ if (data->type != w83697hf)
+ data->fan_div[2] |= (reg >> 5) & 0x04;
+}
+
static struct w83627hf_data *w83627hf_update_device(struct device *dev)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -1587,15 +1591,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
w83627hf_read_value(data,
W83781D_REG_FAN_MIN(i));
}
- for (i = 1; i <= 3; i++) {
+ for (i = 0; i <= 2; i++) {
u8 tmp = w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, i));
/* bits 0-3 are reserved in 627THF */
if (data->type == w83627thf)
tmp &= 0xf0;
- data->pwm[i - 1] = tmp;
- if(i == 2 &&
- (data->type == w83627hf || data->type == w83697hf))
+ data->pwm[i] = tmp;
+ if (i == 1 &&
+ (data->type == w83627hf || data->type == w83697hf))
break;
}
if (data->type == w83627hf) {
@@ -1633,18 +1637,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
}
- i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
- data->fan_div[0] = (i >> 4) & 0x03;
- data->fan_div[1] = (i >> 6) & 0x03;
- if (data->type != w83697hf) {
- data->fan_div[2] = (w83627hf_read_value(data,
- W83781D_REG_PIN) >> 6) & 0x03;
- }
- i = w83627hf_read_value(data, W83781D_REG_VBAT);
- data->fan_div[0] |= (i >> 3) & 0x04;
- data->fan_div[1] |= (i >> 4) & 0x04;
- if (data->type != w83697hf)
- data->fan_div[2] |= (i >> 5) & 0x04;
+ w83627hf_update_fan_div(data);
+
data->alarms =
w83627hf_read_value(data, W83781D_REG_ALARM1) |
(w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index dcc941a5aaf..a6a1edfe761 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type)
the driver field to differentiate between I2C and ISA chips. */
struct w83781d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -251,9 +251,7 @@ struct w83781d_data {
u8 pwm2_enable; /* Boolean */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
- 3000-5000 = thermistor beta.
- Default = 3435.
- Other Betas unimplemented */
+ 4 = thermistor */
u8 vrm;
};
@@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
struct w83781d_data *data = dev_get_drvdata(dev); \
int nr = attr->index; \
- s32 val; \
+ long val; \
\
val = simple_strtol(buf, NULL, 10); \
\
@@ -456,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct w83781d_data *data = w83781d_update_device(dev);
+ struct w83781d_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
@@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+/* The W83781D has a single alarm bit for temp2 and temp3 */
+static ssize_t show_temp3_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = (data->type == w83781d) ? 5 : 13;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
+
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
@@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
show_beep_enable, store_beep_enable);
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ unsigned long bit;
+ u8 reg;
+
+ bit = simple_strtoul(buf, NULL, 10);
+ if (bit & ~1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (bit)
+ data->beep_mask |= (1 << bitnr);
+ else
+ data->beep_mask &= ~(1 << bitnr);
+
+ if (bitnr < 8) {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
+ if (bit)
+ reg |= (1 << bitnr);
+ else
+ reg &= ~(1 << bitnr);
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+ } else if (bitnr < 16) {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
+ if (bit)
+ reg |= (1 << (bitnr - 8));
+ else
+ reg &= ~(1 << (bitnr - 8));
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+ } else {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
+ if (bit)
+ reg |= (1 << (bitnr - 16));
+ else
+ reg &= ~(1 << (bitnr - 16));
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* The W83781D has a single beep bit for temp2 and temp3 */
+static ssize_t show_temp3_beep(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = (data->type == w83781d) ? 5 : 13;
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
+ show_temp3_beep, store_beep, 13);
+
static ssize_t
show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
{
@@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da,
tmp & ~BIT_SCFG2[nr]);
data->sens[nr] = val;
break;
- case W83781D_DEFAULT_BETA: /* thermistor */
+ case W83781D_DEFAULT_BETA:
+ dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+ "instead\n", W83781D_DEFAULT_BETA);
+ /* fall through */
+ case 4: /* thermistor */
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
w83781d_write_value(data, W83781D_REG_SCFG1,
tmp & ~BIT_SCFG1[nr]);
data->sens[nr] = val;
break;
default:
- dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
- (long) val, W83781D_DEFAULT_BETA);
+ dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
+ (long) val);
break;
}
@@ -875,17 +1004,23 @@ ERROR_SC_0:
#define IN_UNIT_ATTRS(X) \
&sensor_dev_attr_in##X##_input.dev_attr.attr, \
&sensor_dev_attr_in##X##_min.dev_attr.attr, \
- &sensor_dev_attr_in##X##_max.dev_attr.attr
+ &sensor_dev_attr_in##X##_max.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_beep.dev_attr.attr
#define FAN_UNIT_ATTRS(X) \
&sensor_dev_attr_fan##X##_input.dev_attr.attr, \
&sensor_dev_attr_fan##X##_min.dev_attr.attr, \
- &sensor_dev_attr_fan##X##_div.dev_attr.attr
+ &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_beep.dev_attr.attr
#define TEMP_UNIT_ATTRS(X) \
&sensor_dev_attr_temp##X##_input.dev_attr.attr, \
&sensor_dev_attr_temp##X##_max.dev_attr.attr, \
- &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
+ &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_beep.dev_attr.attr
static struct attribute* w83781d_attributes[] = {
IN_UNIT_ATTRS(0),
@@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_in1_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_in1_max.dev_attr)))
+ &sensor_dev_attr_in1_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_beep.dev_attr)))
return err;
}
if (kind != as99127f && kind != w83781d && kind != w83783s) {
@@ -955,11 +1094,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_in7_max.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_in7_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in7_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_in8_input.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_in8_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_in8_max.dev_attr)))
+ &sensor_dev_attr_in8_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_beep.dev_attr)))
return err;
}
if (kind != w83783s) {
@@ -968,8 +1115,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_temp3_max.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_temp3_max_hyst.dev_attr)))
+ &sensor_dev_attr_temp3_max_hyst.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_beep.dev_attr)))
return err;
+
+ if (kind != w83781d)
+ err = sysfs_chmod_file(&dev->kobj,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ S_IRUGO | S_IWUSR);
+ if (err)
+ return err;
}
if (kind != w83781d && kind != as99127f) {
@@ -1156,9 +1314,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto ERROR4;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1192,7 +1350,7 @@ w83781d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83781d_group);
sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
}
@@ -1259,9 +1417,9 @@ w83781d_isa_probe(struct platform_device *pdev)
if (err)
goto exit_remove_files;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -1283,7 +1441,7 @@ w83781d_isa_remove(struct platform_device *pdev)
{
struct w83781d_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
device_remove_file(&pdev->dev, &dev_attr_name);
@@ -1485,7 +1643,7 @@ w83781d_init_device(struct device *dev)
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
- data->sens[i - 1] = W83781D_DEFAULT_BETA;
+ data->sens[i - 1] = 4;
} else {
if (w83781d_read_value
(data,
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 9e5f885368b..b6f2ebf9f9c 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -2,7 +2,7 @@
w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
- Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
+ Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val)
struct w83791d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = {
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
};
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ int bitnr = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int bitnr = sensor_attr->index;
+ int bytenr = bitnr / 8;
+ long val = simple_strtol(buf, NULL, 10) ? 1 : 0;
+
+ mutex_lock(&data->update_lock);
+
+ data->beep_mask &= ~(0xff << (bytenr * 8));
+ data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
+ << (bytenr * 8);
+
+ data->beep_mask &= ~(1 << bitnr);
+ data->beep_mask |= val << bitnr;
+
+ w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
+ (data->beep_mask >> (bytenr * 8)) & 0xff);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ int bitnr = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+/* Note: The bitmask for the beep enable/disable is different than
+ the bitmask for the alarm. */
+static struct sensor_device_attribute sda_in_beep[] = {
+ SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
+ SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
+ SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
+ SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
+ SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
+ SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
+ SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
+ SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
+ SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
+ SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
+ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
+ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
+ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
+ SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
+};
+
#define show_fan_reg(reg) \
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = {
show_fan_div, store_fan_div, 4),
};
+static struct sensor_device_attribute sda_fan_beep[] = {
+ SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
+ SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
+ SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
+ SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
+ SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
+ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
+};
+
/* read/write the temperature1, includes measured value and limits */
static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
char *buf)
@@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
show_temp23, store_temp23, 1, 2),
};
+/* Note: The bitmask for the beep enable/disable is different than
+ the bitmask for the alarm. */
+static struct sensor_device_attribute sda_temp_beep[] = {
+ SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
+ SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
+ SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
/* get reatime status of all sensors items: voltage, temp, fan */
static ssize_t show_alarms_reg(struct device *dev,
@@ -724,7 +832,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct w83791d_data *data = w83791d_update_device(dev);
+ struct w83791d_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
#define IN_UNIT_ATTRS(X) \
&sda_in_input[X].dev_attr.attr, \
&sda_in_min[X].dev_attr.attr, \
- &sda_in_max[X].dev_attr.attr
+ &sda_in_max[X].dev_attr.attr, \
+ &sda_in_beep[X].dev_attr.attr, \
+ &sda_in_alarm[X].dev_attr.attr
#define FAN_UNIT_ATTRS(X) \
&sda_fan_input[X].dev_attr.attr, \
&sda_fan_min[X].dev_attr.attr, \
- &sda_fan_div[X].dev_attr.attr
+ &sda_fan_div[X].dev_attr.attr, \
+ &sda_fan_beep[X].dev_attr.attr, \
+ &sda_fan_alarm[X].dev_attr.attr
#define TEMP_UNIT_ATTRS(X) \
&sda_temp_input[X].dev_attr.attr, \
&sda_temp_max[X].dev_attr.attr, \
- &sda_temp_max_hyst[X].dev_attr.attr
+ &sda_temp_max_hyst[X].dev_attr.attr, \
+ &sda_temp_beep[X].dev_attr.attr, \
+ &sda_temp_alarm[X].dev_attr.attr
static struct attribute *w83791d_attributes[] = {
IN_UNIT_ATTRS(0),
@@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
goto error3;
/* Everything is ready, now register the working device */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error4;
}
@@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index b0fa296740d..f836198b705 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -267,7 +267,7 @@ DIV_TO_REG(long val)
struct w83792d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", (data->alarms >> nr) & 1);
+}
+
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
show_temp23, store_temp23, 1, 4);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
show_chassis_clear, store_chassis_clear);
@@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
show_fan_div, store_fan_div, 7);
-static struct attribute *w83792d_attributes_fan[4][4] = {
+static struct attribute *w83792d_attributes_fan[4][5] = {
{
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_div.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_div.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan6_min.dev_attr.attr,
&sensor_dev_attr_fan6_div.dev_attr.attr,
+ &sensor_dev_attr_fan6_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan7_input.dev_attr.attr,
&sensor_dev_attr_fan7_min.dev_attr.attr,
&sensor_dev_attr_fan7_div.dev_attr.attr,
+ &sensor_dev_attr_fan7_alarm.dev_attr.attr,
NULL
}
};
@@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in8_max.dev_attr.attr,
&sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
@@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
NULL
};
@@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
&w83792d_group_fan[3])))
goto exit_remove_files;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83792d_group);
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
sysfs_remove_group(&client->dev.kobj,
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 253ffaf1568..48599e1cc55 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
struct w83793_data {
struct i2c_client client;
struct i2c_client *lm75[2];
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
device_remove_file(dev,
@@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index a3fcace412f..b5db354e2f1 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = {
struct w83l785ts_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client)
struct w83l785ts_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&client->dev,
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9f3a4cd0b07..de95c75efb4 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -75,11 +75,19 @@ config I2C_AMD8111
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 && EXPERIMENTAL
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
help
This supports the use of the I2C interface on Atmel AT91
processors.
+ This driver is BROKEN because the controller which it uses
+ will easily trigger RX overrun and TX underrun errors. Using
+ low I2C clock rates may partially work around those issues
+ on some systems. Another serious problem is that there is no
+ documented way to issue repeated START conditions, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with those limitations.
+
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
depends on SOC_AU1550 || SOC_AU1200
@@ -106,6 +114,19 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
help
The unit of the TWI clock is kHz.
+config I2C_DAVINCI
+ tristate "DaVinci I2C driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for TI DaVinci I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-davinci.
+
+ Please note that this driver might be needed to bring up other
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
config I2C_ELEKTOR
tristate "Elektor ISA card"
depends on ISA && BROKEN_ON_SMP
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 5b752e4e191..81d43c27cf9 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index c9fca7b4926..5d1a27ef250 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -326,7 +326,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
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;
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index d7e7c359fc3..2f684166c43 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -48,17 +48,14 @@ wait_xfer_done(struct i2c_au1550_data *adap)
sp = (volatile psc_smb_t *)(adap->psc_base);
- /* Wait for Tx FIFO Underflow.
+ /* Wait for Tx Buffer Empty
*/
for (i = 0; i < adap->xfer_timeout; i++) {
- stat = sp->psc_smbevnt;
+ stat = sp->psc_smbstat;
au_sync();
- if ((stat & PSC_SMBEVNT_TU) != 0) {
- /* Clear it. */
- sp->psc_smbevnt = PSC_SMBEVNT_TU;
- au_sync();
+ if ((stat & PSC_SMBSTAT_TE) != 0)
return 0;
- }
+
udelay(1);
}
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 6311039dfe6..67224a424ab 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -44,7 +44,6 @@
#define TWI_I2C_MODE_COMBINED 0x04
struct bfin_twi_iface {
- struct mutex twi_lock;
int irq;
spinlock_t lock;
char read_write;
@@ -228,12 +227,8 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
return -ENXIO;
- mutex_lock(&iface->twi_lock);
-
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
- mutex_unlock(&iface->twi_lock);
yield();
- mutex_lock(&iface->twi_lock);
}
ret = 0;
@@ -310,9 +305,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
break;
}
- /* Release mutex */
- mutex_unlock(&iface->twi_lock);
-
return ret;
}
@@ -330,12 +322,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
return -ENXIO;
- mutex_lock(&iface->twi_lock);
-
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
- mutex_unlock(&iface->twi_lock);
yield();
- mutex_lock(&iface->twi_lock);
}
iface->writeNum = 0;
@@ -502,9 +490,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
rc = (iface->result >= 0) ? 0 : -1;
- /* Release mutex */
- mutex_unlock(&iface->twi_lock);
-
return rc;
}
@@ -555,7 +540,6 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
struct i2c_adapter *p_adap;
int rc;
- mutex_init(&(iface->twi_lock));
spin_lock_init(&(iface->lock));
init_completion(&(iface->complete));
iface->irq = IRQ_TWI;
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 00000000000..bd7aaff3524
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,586 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/i2c.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
+ DAVINCI_I2C_IMR_SCD | \
+ DAVINCI_I2C_IMR_ARDY | \
+ DAVINCI_I2C_IMR_NACK | \
+ DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG 0x00
+#define DAVINCI_I2C_IMR_REG 0x04
+#define DAVINCI_I2C_STR_REG 0x08
+#define DAVINCI_I2C_CLKL_REG 0x0c
+#define DAVINCI_I2C_CLKH_REG 0x10
+#define DAVINCI_I2C_CNT_REG 0x14
+#define DAVINCI_I2C_DRR_REG 0x18
+#define DAVINCI_I2C_SAR_REG 0x1c
+#define DAVINCI_I2C_DXR_REG 0x20
+#define DAVINCI_I2C_MDR_REG 0x24
+#define DAVINCI_I2C_IVR_REG 0x28
+#define DAVINCI_I2C_EMDR_REG 0x2c
+#define DAVINCI_I2C_PSC_REG 0x30
+
+#define DAVINCI_I2C_IVR_AAS 0x07
+#define DAVINCI_I2C_IVR_SCD 0x06
+#define DAVINCI_I2C_IVR_XRDY 0x05
+#define DAVINCI_I2C_IVR_RDR 0x04
+#define DAVINCI_I2C_IVR_ARDY 0x03
+#define DAVINCI_I2C_IVR_NACK 0x02
+#define DAVINCI_I2C_IVR_AL 0x01
+
+#define DAVINCI_I2C_STR_BB (1 << 12)
+#define DAVINCI_I2C_STR_RSFULL (1 << 11)
+#define DAVINCI_I2C_STR_SCD (1 << 5)
+#define DAVINCI_I2C_STR_ARDY (1 << 2)
+#define DAVINCI_I2C_STR_NACK (1 << 1)
+#define DAVINCI_I2C_STR_AL (1 << 0)
+
+#define DAVINCI_I2C_MDR_NACK (1 << 15)
+#define DAVINCI_I2C_MDR_STT (1 << 13)
+#define DAVINCI_I2C_MDR_STP (1 << 11)
+#define DAVINCI_I2C_MDR_MST (1 << 10)
+#define DAVINCI_I2C_MDR_TRX (1 << 9)
+#define DAVINCI_I2C_MDR_XA (1 << 8)
+#define DAVINCI_I2C_MDR_IRS (1 << 5)
+
+#define DAVINCI_I2C_IMR_AAS (1 << 6)
+#define DAVINCI_I2C_IMR_SCD (1 << 5)
+#define DAVINCI_I2C_IMR_XRDY (1 << 4)
+#define DAVINCI_I2C_IMR_RRDY (1 << 3)
+#define DAVINCI_I2C_IMR_ARDY (1 << 2)
+#define DAVINCI_I2C_IMR_NACK (1 << 1)
+#define DAVINCI_I2C_IMR_AL (1 << 0)
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) { \
+ val |= mask; \
+ } else { \
+ val &= ~mask; \
+ } \
+} while (0)
+
+struct davinci_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ int cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ int irq;
+ struct i2c_adapter adapter;
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+ .bus_freq = 100,
+ .bus_delay = 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+/*
+ * This functions configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u16 psc;
+ u32 clk;
+ u32 clkh;
+ u32 clkl;
+ u32 input_clock = clk_get_rate(dev->clk);
+ u16 w;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+
+ /* put I2C into reset */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* NOTE: I2C Clock divider programming info
+ * As per I2C specs the following formulas provide prescaler
+ * and low/high divider values
+ * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+ * module clk
+ *
+ * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+ *
+ * Thus,
+ * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+ *
+ * where if PSC == 0, d = 7,
+ * if PSC == 1, d = 6
+ * if PSC > 1 , d = 5
+ */
+
+ psc = 26; /* To get 1MHz clock */
+
+ clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10;
+ clkh = (50 * clk) / 100;
+ clkl = clk - clkh;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+ dev_dbg(dev->dev, "CLK = %d\n", clk);
+ dev_dbg(dev->dev, "PSC = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+ dev_dbg(dev->dev, "CLKL = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+ dev_dbg(dev->dev, "CLKH = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+
+ /* Take the I2C module out of reset: */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* Enable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+ return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+ char allow_sleep)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + DAVINCI_I2C_TIMEOUT;
+ while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+ & DAVINCI_I2C_STR_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ if (allow_sleep)
+ schedule_timeout(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u32 flag;
+ u32 stat;
+ u16 w;
+ int r;
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+ /* Introduce a delay, required for some boards (e.g Davinci EVM) */
+ if (pdata->bus_delay)
+ udelay(pdata->bus_delay);
+
+ /* set the slave address */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ /* Clear any pending interrupts by reading the IVR */
+ stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG);
+
+ /* Take I2C out of reset, configure it as master and set the
+ * start bit */
+ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT;
+
+ /* if the slave address is ten bit address, enable XA bit */
+ if (msg->flags & I2C_M_TEN)
+ flag |= DAVINCI_I2C_MDR_XA;
+ if (!(msg->flags & I2C_M_RD))
+ flag |= DAVINCI_I2C_MDR_TRX;
+ if (stop)
+ flag |= DAVINCI_I2C_MDR_STP;
+
+ /* Enable receive or transmit interrupts */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+ if (msg->flags & I2C_M_RD)
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1);
+ else
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+ /* write the data into mode register */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ DAVINCI_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_davinci_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ /* no error */
+ if (likely(!dev->cmd_err))
+ return msg->len;
+
+ /* We have an error */
+ if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+ i2c_davinci_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return msg->len;
+ if (stop) {
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
+
+ ret = i2c_davinci_wait_bus_not_busy(dev, 1);
+ if (ret < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (ret < 0)
+ return ret;
+ }
+
+ dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret);
+
+ return num;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+ struct davinci_i2c_dev *dev = dev_id;
+ u32 stat;
+ int count = 0;
+ u16 w;
+
+ while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+ dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ switch (stat) {
+ case DAVINCI_I2C_IVR_AL:
+ dev->cmd_err |= DAVINCI_I2C_STR_AL;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_NACK:
+ dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_ARDY:
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_STR_ARDY, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_RDR:
+ if (dev->buf_len) {
+ *dev->buf++ =
+ davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_DRR_REG);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 0);
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG,
+ w);
+ } else
+ dev_err(dev->dev, "RDR IRQ while no"
+ "data requested\n");
+ break;
+
+ case DAVINCI_I2C_IVR_XRDY:
+ if (dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+ *dev->buf++);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_IMR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0);
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_IMR_REG,
+ w);
+ } else
+ dev_err(dev->dev, "TDR IRQ while no data to"
+ "send\n");
+ break;
+
+ case DAVINCI_I2C_IVR_SCD:
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_STR_SCD, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_AAS:
+ dev_warn(dev->dev, "Address as slave interrupt\n");
+ }/* switch */
+ }/* while */
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq->start;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, "I2CCLK");
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+ i2c_davinci_init(dev);
+
+ r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+ adap->algo = &i2c_davinci_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* FIXME */
+ adap->timeout = 1;
+ adap->retries = 1;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+ free_irq(IRQ_I2C, dev);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver davinci_i2c_driver = {
+ .probe = davinci_i2c_probe,
+ .remove = davinci_i2c_remove,
+ .driver = {
+ .name = "i2c_davinci",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+ return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 289816db52a..ac27e5f84eb 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -34,6 +34,7 @@
ESB2 269B
ICH8 283E
ICH9 2930
+ Tolapai 5032
This driver supports several versions of Intel's I/O Controller Hubs (ICH).
For SMBus support, they are similar to the PIIX4 and are part
of Intel's '810' and other chipsets.
@@ -515,7 +516,7 @@ static u32 i801_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_WRITE_I2C_BLOCK
- | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
+ | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
}
static const struct i2c_algorithm smbus_algorithm = {
@@ -543,6 +544,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
{ 0, }
};
@@ -563,6 +565,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_ESB2_17:
case PCI_DEVICE_ID_INTEL_ICH8_5:
case PCI_DEVICE_ID_INTEL_ICH9_6:
+ case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
isich4 = 1;
break;
default:
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 8b14d14e60c..e08bacadd6b 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -738,7 +738,14 @@ static int __devinit iic_probe(struct ocp_device *ocp){
adap->timeout = 1;
adap->retries = 1;
- if ((ret = i2c_add_adapter(adap)) != 0){
+ /*
+ * If "dev->idx" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ adap->nr = dev->idx >= 0 ? dev->idx : 0;
+
+ if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
dev->idx);
goto fail;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index ace644e21b1..c70146e4c2c 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -389,13 +389,6 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
return im;
}
-static int
-iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
static u32
iop3xx_i2c_func(struct i2c_adapter *adap)
{
@@ -404,7 +397,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
static const struct i2c_algorithm iop3xx_i2c_algo = {
.master_xfer = iop3xx_i2c_master_xfer,
- .algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index c48140f782d..1bf590c7416 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -62,6 +62,7 @@ struct nforce2_smbus {
int base;
int size;
int blockops;
+ int can_abort;
};
@@ -83,7 +84,14 @@ struct nforce2_smbus {
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
bytes */
-
+#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to
+ check the status of
+ the abort command */
+#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that
+ abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT 0x20
#define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40
#define NVIDIA_SMB_STS_RES 0x20
@@ -98,15 +106,61 @@ struct nforce2_smbus {
#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
#define NVIDIA_SMB_PRTCL_PEC 0x80
+/* Misc definitions */
+#define MAX_TIMEOUT 100
+
static struct pci_driver nforce2_driver;
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+ outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+ } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+ (timeout++ < MAX_TIMEOUT));
+ if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+ dev_err(&adap->dev, "Can't reset the smbus\n");
+ outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STS);
+ } while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout >= MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ if (smbus->can_abort)
+ nforce2_abort(adap);
+ return -1;
+ }
+ if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+ dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+ return -1;
+ }
+ return 0;
+}
+
/* Return -1 on error */
static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data)
{
struct nforce2_smbus *smbus = adap->algo_data;
- unsigned char protocol, pec, temp;
+ unsigned char protocol, pec;
u8 len;
int i;
@@ -170,21 +224,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
outb_p(protocol, NVIDIA_SMB_PRTCL);
- temp = inb_p(NVIDIA_SMB_STS);
-
- if (~temp & NVIDIA_SMB_STS_DONE) {
- udelay(500);
- temp = inb_p(NVIDIA_SMB_STS);
- }
- if (~temp & NVIDIA_SMB_STS_DONE) {
- msleep(10);
- temp = inb_p(NVIDIA_SMB_STS);
- }
-
- if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
- dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
+ if (nforce2_check_status(adap))
return -1;
- }
if (read_write == I2C_SMBUS_WRITE)
return 0;
@@ -202,7 +243,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_BLOCK_DATA:
len = inb_p(NVIDIA_SMB_BCNT);
- len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+ if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev, "Transaction failed "
+ "(received block size: 0x%02x)\n",
+ len);
+ return -1;
+ }
for (i = 0; i < len; i++)
data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
data->block[0] = len;
@@ -218,6 +264,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
/* other functionality might be possible, but is not tested */
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PEC |
(((struct nforce2_smbus*)adapter->algo_data)->blockops ?
I2C_FUNC_SMBUS_BLOCK_DATA : 0);
}
@@ -308,6 +355,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
smbuses[0].blockops = 1;
smbuses[1].blockops = 1;
+ smbuses[0].can_abort = 1;
+ smbuses[1].can_abort = 1;
}
/* SMBus adapter 1 */
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index a54adc50d16..84df29da1dd 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -24,24 +24,41 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-static unsigned short chip_addr;
-module_param(chip_addr, ushort, S_IRUGO);
-MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+#define MAX_CHIPS 10
-static u8 stub_pointer;
-static u8 stub_bytes[256];
-static u16 stub_words[256];
+static unsigned short chip_addr[MAX_CHIPS];
+module_param_array(chip_addr, ushort, NULL, S_IRUGO);
+MODULE_PARM_DESC(chip_addr,
+ "Chip addresses (up to 10, between 0x03 and 0x77)\n");
+
+struct stub_chip {
+ u8 pointer;
+ u8 bytes[256];
+ u16 words[256];
+};
+
+static struct stub_chip *stub_chips;
/* Return -1 on error. */
static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size, union i2c_smbus_data * data)
{
s32 ret;
-
- if (addr != chip_addr)
+ int i;
+ struct stub_chip *chip = NULL;
+
+ /* Search for the right chip */
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (addr == chip_addr[i]) {
+ chip = stub_chips + i;
+ break;
+ }
+ }
+ if (!chip)
return -ENODEV;
switch (size) {
@@ -53,12 +70,12 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
- stub_pointer = command;
+ chip->pointer = command;
dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
"wrote 0x%02x.\n",
addr, command);
} else {
- data->byte = stub_bytes[stub_pointer++];
+ data->byte = chip->bytes[chip->pointer++];
dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
"read 0x%02x.\n",
addr, data->byte);
@@ -69,29 +86,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_WRITE) {
- stub_bytes[command] = data->byte;
+ chip->bytes[command] = data->byte;
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"wrote 0x%02x at 0x%02x.\n",
addr, data->byte, command);
} else {
- data->byte = stub_bytes[command];
+ data->byte = chip->bytes[command];
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"read 0x%02x at 0x%02x.\n",
addr, data->byte, command);
}
- stub_pointer = command + 1;
+ chip->pointer = command + 1;
ret = 0;
break;
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_WRITE) {
- stub_words[command] = data->word;
+ chip->words[command] = data->word;
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"wrote 0x%04x at 0x%02x.\n",
addr, data->word, command);
} else {
- data->word = stub_words[command];
+ data->word = chip->words[command];
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"read 0x%04x at 0x%02x.\n",
addr, data->word, command);
@@ -129,23 +146,41 @@ static struct i2c_adapter stub_adapter = {
static int __init i2c_stub_init(void)
{
- if (!chip_addr) {
+ int i, ret;
+
+ if (!chip_addr[0]) {
printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
return -ENODEV;
}
- if (chip_addr < 0x03 || chip_addr > 0x77) {
- printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
- chip_addr);
- return -EINVAL;
+
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address "
+ "0x%02x\n", chip_addr[i]);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
+ chip_addr[i]);
}
- printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
- return i2c_add_adapter(&stub_adapter);
+ /* Allocate memory for all chips at once */
+ stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
+ if (!stub_chips) {
+ printk(KERN_ERR "i2c-stub: Out of memory\n");
+ return -ENOMEM;
+ }
+
+ ret = i2c_add_adapter(&stub_adapter);
+ if (ret)
+ kfree(stub_chips);
+ return ret;
}
static void __exit i2c_stub_exit(void)
{
i2c_del_adapter(&stub_adapter);
+ kfree(stub_chips);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index 32b25427eab..21c6dd69193 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -48,14 +48,11 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
-/* Initial values */
-#define PCF8574_INIT 255 /* All outputs on (input mode) */
-
/* Each client has this additional data */
struct pcf8574_data {
struct i2c_client client;
- u8 write; /* Remember last written value */
+ int write; /* Remember last written value */
};
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
@@ -85,7 +82,11 @@ static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
- return sprintf(buf, "%u\n", data->write);
+
+ if (data->write < 0)
+ return data->write;
+
+ return sprintf(buf, "%d\n", data->write);
}
static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -206,8 +207,7 @@ static int pcf8574_detach_client(struct i2c_client *client)
static void pcf8574_init_client(struct i2c_client *client)
{
struct pcf8574_data *data = i2c_get_clientdata(client);
- data->write = PCF8574_INIT;
- i2c_smbus_write_byte(client, data->write);
+ data->write = -EAGAIN;
}
static int __init pcf8574_init(void)
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 503ffec2ce0..e320994b981 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -24,20 +24,13 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
#include <asm/arch/tps65010.h>
/*-------------------------------------------------------------------------*/
@@ -48,10 +41,6 @@
MODULE_DESCRIPTION("TPS6501x Power Management Driver");
MODULE_LICENSE("GPL");
-static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
static struct i2c_driver tps65010_driver;
/*-------------------------------------------------------------------------*/
@@ -79,9 +68,8 @@ enum tps_model {
};
struct tps65010 {
- struct i2c_client client;
+ struct i2c_client *client;
struct mutex lock;
- int irq;
struct delayed_work work;
struct dentry *file;
unsigned charging:1;
@@ -229,22 +217,22 @@ static int dbg_show(struct seq_file *s, void *_)
/* registers for monitoring battery charging and status; note
* that reading chgstat and regstat may ack IRQs...
*/
- value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
dbg_chgconf(tps->por, buf, sizeof buf, value);
seq_printf(s, "chgconfig %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
dbg_chgstat(buf, sizeof buf, value);
seq_printf(s, "chgstat %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1);
dbg_chgstat(buf, sizeof buf, value);
seq_printf(s, "mask1 %s", buf);
/* ignore ackint1 */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
dbg_regstat(buf, sizeof buf, value);
seq_printf(s, "regstat %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2);
dbg_regstat(buf, sizeof buf, value);
seq_printf(s, "mask2 %s\n", buf);
/* ignore ackint2 */
@@ -253,21 +241,21 @@ static int dbg_show(struct seq_file *s, void *_)
/* VMAIN voltage, enable lowpower, etc */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1);
seq_printf(s, "vdcdc1 %02x\n", value);
/* VCORE voltage, vibrator on/off */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2);
seq_printf(s, "vdcdc2 %02x\n", value);
/* both LD0s, and their lowpower behavior */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1);
seq_printf(s, "vregs1 %02x\n\n", value);
/* LEDs and GPIOs */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER);
seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n",
(value & 0x80)
? ((v2 & 0x80) ? "on" : "off")
@@ -275,8 +263,8 @@ static int dbg_show(struct seq_file *s, void *_)
value, v2,
(value & 0x7f) * 10, (v2 & 0x7f) * 100);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER);
seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n",
(value & 0x80)
? ((v2 & 0x80) ? "on" : "off")
@@ -284,8 +272,8 @@ static int dbg_show(struct seq_file *s, void *_)
value, v2,
(value & 0x7f) * 10, (v2 & 0x7f) * 100);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3);
seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
for (i = 0; i < 4; i++) {
@@ -335,7 +323,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
/* regstatus irqs */
if (tps->nmask2) {
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
mask = tmp ^ tps->regstatus;
tps->regstatus = tmp;
mask &= tps->nmask2;
@@ -362,7 +350,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
/* chgstatus irqs */
if (tps->nmask1) {
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
mask = tmp ^ tps->chgstatus;
tps->chgstatus = tmp;
mask &= tps->nmask1;
@@ -426,7 +414,7 @@ static void tps65010_work(struct work_struct *work)
int status;
u8 chgconfig, tmp;
- chgconfig = i2c_smbus_read_byte_data(&tps->client,
+ chgconfig = i2c_smbus_read_byte_data(tps->client,
TPS_CHGCONFIG);
chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING);
if (tps->vbus == 500)
@@ -434,17 +422,17 @@ static void tps65010_work(struct work_struct *work)
else if (tps->vbus >= 100)
chgconfig |= TPS_VBUS_CHARGING;
- status = i2c_smbus_write_byte_data(&tps->client,
+ status = i2c_smbus_write_byte_data(tps->client,
TPS_CHGCONFIG, chgconfig);
/* vbus update fails unless VBUS is connected! */
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
tps->chgconf = tmp;
show_chgconfig(tps->por, "update vbus", tmp);
}
if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags))
- enable_irq(tps->irq);
+ enable_irq(tps->client->irq);
mutex_unlock(&tps->lock);
}
@@ -463,114 +451,75 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
static struct tps65010 *the_tps;
-static int __exit tps65010_detach_client(struct i2c_client *client)
+static int __exit tps65010_remove(struct i2c_client *client)
{
- struct tps65010 *tps;
+ struct tps65010 *tps = i2c_get_clientdata(client);
- tps = container_of(client, struct tps65010, client);
- free_irq(tps->irq, tps);
-#ifdef CONFIG_ARM
- if (machine_is_omap_h2())
- omap_free_gpio(58);
- if (machine_is_omap_osk())
- omap_free_gpio(OMAP_MPUIO(1));
-#endif
+ if (client->irq > 0)
+ free_irq(client->irq, tps);
cancel_delayed_work(&tps->work);
flush_scheduled_work();
debugfs_remove(tps->file);
- if (i2c_detach_client(client) == 0)
- kfree(tps);
+ kfree(tps);
the_tps = NULL;
return 0;
}
-static int tps65010_noscan(struct i2c_adapter *bus)
-{
- /* pure paranoia, in case someone adds another i2c bus
- * after our init section's gone...
- */
- return -ENODEV;
-}
-
-/* no error returns, they'd just make bus scanning stop */
-static int __init
-tps65010_probe(struct i2c_adapter *bus, int address, int kind)
+static int tps65010_probe(struct i2c_client *client)
{
struct tps65010 *tps;
int status;
- unsigned long irqflags;
if (the_tps) {
- dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
- return 0;
+ dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
+ return -ENODEV;
}
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EINVAL;
+
tps = kzalloc(sizeof *tps, GFP_KERNEL);
if (!tps)
- return 0;
+ return -ENOMEM;
mutex_init(&tps->lock);
INIT_DELAYED_WORK(&tps->work, tps65010_work);
- tps->irq = -1;
- tps->client.addr = address;
- tps->client.adapter = bus;
- tps->client.driver = &tps65010_driver;
- strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-
- status = i2c_attach_client(&tps->client);
- if (status < 0) {
- dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
- DRIVER_NAME, address, status);
- goto fail1;
- }
+ tps->client = client;
- /* the IRQ is active low, but many gpio lines can't support that
- * so this driver can use falling-edge triggers instead.
- */
- irqflags = IRQF_SAMPLE_RANDOM;
-#ifdef CONFIG_ARM
- if (machine_is_omap_h2()) {
- tps->model = TPS65010;
- omap_cfg_reg(W4_GPIO58);
- tps->irq = OMAP_GPIO_IRQ(58);
- omap_request_gpio(58);
- omap_set_gpio_direction(58, 1);
- irqflags |= IRQF_TRIGGER_FALLING;
- }
- if (machine_is_omap_osk()) {
+ if (strcmp(client->name, "tps65010") == 0)
tps->model = TPS65010;
- // omap_cfg_reg(U19_1610_MPUIO1);
- tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
- omap_request_gpio(OMAP_MPUIO(1));
- omap_set_gpio_direction(OMAP_MPUIO(1), 1);
- irqflags |= IRQF_TRIGGER_FALLING;
- }
- if (machine_is_omap_h3()) {
+ else if (strcmp(client->name, "tps65011") == 0)
+ tps->model = TPS65011;
+ else if (strcmp(client->name, "tps65012") == 0)
+ tps->model = TPS65012;
+ else if (strcmp(client->name, "tps65013") == 0)
tps->model = TPS65013;
-
- // FIXME set up this board's IRQ ...
+ else {
+ dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
+ status = -ENODEV;
+ goto fail1;
}
-#endif
- if (tps->irq > 0) {
- status = request_irq(tps->irq, tps65010_irq,
- irqflags, DRIVER_NAME, tps);
+ /* the IRQ is active low, but many gpio lines can't support that
+ * so this driver uses falling-edge triggers instead.
+ */
+ if (client->irq > 0) {
+ status = request_irq(client->irq, tps65010_irq,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+ DRIVER_NAME, tps);
if (status < 0) {
- dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
- tps->irq, status);
- i2c_detach_client(&tps->client);
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
+ client->irq, status);
goto fail1;
}
-#ifdef CONFIG_ARM
/* annoying race here, ideally we'd have an option
* to claim the irq now and enable it later.
+ * FIXME genirq IRQF_NOAUTOEN now solves that ...
*/
- disable_irq(tps->irq);
+ disable_irq(client->irq);
set_bit(FLAG_IRQ_ENABLE, &tps->flags);
-#endif
} else
- printk(KERN_WARNING "%s: IRQ not configured!\n",
- DRIVER_NAME);
+ dev_warn(&client->dev, "IRQ not configured!\n");
switch (tps->model) {
@@ -583,23 +532,22 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
break;
/* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
}
- tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
show_chgconfig(tps->por, "conf/init", tps->chgconf);
show_chgstatus("chg/init",
- i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS));
+ i2c_smbus_read_byte_data(client, TPS_CHGSTATUS));
show_regstatus("reg/init",
- i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS));
+ i2c_smbus_read_byte_data(client, TPS_REGSTATUS));
pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1),
- i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2),
- i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(client, TPS_VDCDC1),
+ i2c_smbus_read_byte_data(client, TPS_VDCDC2),
+ i2c_smbus_read_byte_data(client, TPS_VREGS1));
pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO),
- i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+ i2c_smbus_read_byte_data(client, TPS_DEFGPIO),
+ i2c_smbus_read_byte_data(client, TPS_MASK3));
- tps65010_driver.attach_adapter = tps65010_noscan;
the_tps = tps;
#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
@@ -615,15 +563,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
* registers, and maybe disable VBUS draw.
*/
tps->nmask1 = ~0;
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1);
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1);
tps->nmask2 = TPS_REG_ONOFF;
if (tps->model == TPS65013)
tps->nmask2 |= TPS_REG_NO_CHG;
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2);
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2);
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f
- | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f
+ | i2c_smbus_read_byte_data(client, TPS_MASK3));
tps65010_work(&tps->work.work);
@@ -632,22 +580,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
return 0;
fail1:
kfree(tps);
- return 0;
-}
-
-static int __init tps65010_scan_bus(struct i2c_adapter *bus)
-{
- if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EINVAL;
- return i2c_probe(bus, &addr_data, tps65010_probe);
+ return status;
}
static struct i2c_driver tps65010_driver = {
.driver = {
.name = "tps65010",
},
- .attach_adapter = tps65010_scan_bus,
- .detach_client = __exit_p(tps65010_detach_client),
+ .probe = tps65010_probe,
+ .remove = __exit_p(tps65010_remove),
};
/*-------------------------------------------------------------------------*/
@@ -702,7 +643,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
mutex_lock(&the_tps->lock);
- defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
+ defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO);
/* Configure GPIO for output */
defgpio |= 1 << (gpio + 3);
@@ -718,12 +659,12 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_DEFGPIO, defgpio);
pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME,
gpio, value ? "high" : "low",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO));
mutex_unlock(&the_tps->lock);
return status;
@@ -753,11 +694,11 @@ int tps65010_set_led(unsigned led, unsigned mode)
mutex_lock(&the_tps->lock);
pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_ON + offs));
pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_PER + offs));
switch (mode) {
@@ -780,7 +721,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
return -EINVAL;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_LED1_ON + offs, led_on);
if (status != 0) {
@@ -791,9 +732,9 @@ int tps65010_set_led(unsigned led, unsigned mode)
}
pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs));
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_LED1_PER + offs, led_per);
if (status != 0) {
@@ -804,7 +745,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
}
pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_PER + offs));
mutex_unlock(&the_tps->lock);
@@ -827,11 +768,11 @@ int tps65010_set_vib(unsigned value)
mutex_lock(&the_tps->lock);
- vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2);
+ vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2);
vdcdc2 &= ~(1 << 1);
if (value)
vdcdc2 |= (1 << 1);
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC2, vdcdc2);
pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off");
@@ -857,9 +798,9 @@ int tps65010_set_low_pwr(unsigned mode)
pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME,
mode ? "enable" : "disable",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
- vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+ vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
switch (mode) {
case OFF:
@@ -871,7 +812,7 @@ int tps65010_set_low_pwr(unsigned mode)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC1, vdcdc1);
if (status != 0)
@@ -879,7 +820,7 @@ int tps65010_set_low_pwr(unsigned mode)
DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
mutex_unlock(&the_tps->lock);
@@ -902,9 +843,9 @@ int tps65010_config_vregs1(unsigned value)
mutex_lock(&the_tps->lock);
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VREGS1, value);
if (status != 0)
@@ -912,7 +853,7 @@ int tps65010_config_vregs1(unsigned value)
DRIVER_NAME);
else
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
mutex_unlock(&the_tps->lock);
@@ -941,11 +882,11 @@ int tps65013_set_low_pwr(unsigned mode)
pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n",
DRIVER_NAME,
mode ? "enable" : "disable",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG),
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG),
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
- chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
- vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+ chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
+ vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
switch (mode) {
case OFF:
@@ -959,7 +900,7 @@ int tps65013_set_low_pwr(unsigned mode)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_CHGCONFIG, chgconfig);
if (status != 0) {
printk(KERN_ERR "%s: Failed to write chconfig register\n",
@@ -968,11 +909,11 @@ int tps65013_set_low_pwr(unsigned mode)
return status;
}
- chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
+ chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
the_tps->chgconf = chgconfig;
show_chgconfig(0, "chgconf", chgconfig);
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC1, vdcdc1);
if (status != 0)
@@ -980,7 +921,7 @@ int tps65013_set_low_pwr(unsigned mode)
DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
mutex_unlock(&the_tps->lock);
@@ -1011,52 +952,6 @@ static int __init tps_init(void)
msleep(10);
}
-#ifdef CONFIG_ARM
- if (machine_is_omap_osk()) {
-
- // FIXME: More should be placed in the initialization code
- // of the submodules (DSP, ethernet, power management,
- // board-osk.c). Careful: I2C is initialized "late".
-
- /* Let LED1 (D9) blink */
- tps65010_set_led(LED1, BLINK);
-
- /* Disable LED 2 (D2) */
- tps65010_set_led(LED2, OFF);
-
- /* Set GPIO 1 HIGH to disable VBUS power supply;
- * OHCI driver powers it up/down as needed.
- */
- tps65010_set_gpio_out_value(GPIO1, HIGH);
-
- /* Set GPIO 2 low to turn on LED D3 */
- tps65010_set_gpio_out_value(GPIO2, HIGH);
-
- /* Set GPIO 3 low to take ethernet out of reset */
- tps65010_set_gpio_out_value(GPIO3, LOW);
-
- /* gpio4 for VDD_DSP */
-
- /* Enable LOW_PWR */
- tps65010_set_low_pwr(ON);
-
- /* Switch VLDO2 to 3.0V for AIC23 */
- tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE);
-
- } else if (machine_is_omap_h2()) {
- /* gpio3 for SD, gpio4 for VDD_DSP */
-
- /* Enable LOW_PWR */
- tps65010_set_low_pwr(ON);
- } else if (machine_is_omap_h3()) {
- /* gpio4 for SD, gpio3 for VDD_DSP */
-#ifdef CONFIG_PM
- /* Enable LOW_PWR */
- tps65013_set_low_pwr(ON);
-#endif
- }
-#endif
-
return status;
}
/* NOTE: this MUST be initialized before the other parts of the system
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d663e6960d9..e73d58c43f3 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
#ifdef CONFIG_HOTPLUG
/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct i2c_client *client = to_i2c_client(dev);
- int i = 0, length = 0;
/* by definition, legacy drivers can't hotplug */
if (dev->driver || !client->driver_name)
return 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=%s", client->driver_name))
+ if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
return -ENOMEM;
- envp[i] = NULL;
dev_dbg(dev, "uevent\n");
return 0;
}
@@ -190,7 +186,7 @@ static struct device_attribute i2c_dev_attrs[] = {
{ },
};
-struct bus_type i2c_bus_type = {
+static struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
@@ -201,7 +197,6 @@ struct bus_type i2c_bus_type = {
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
-EXPORT_SYMBOL_GPL(i2c_bus_type);
/**
* i2c_new_device - instantiate an i2c device for use with a new style driver
@@ -230,7 +225,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->adapter = adap;
client->dev.platform_data = info->platform_data;
- client->flags = info->flags;
+ device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);
+
+ client->flags = info->flags & ~I2C_CLIENT_WAKE;
client->addr = info->addr;
client->irq = info->irq;
@@ -283,7 +280,7 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device);
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
-void i2c_adapter_dev_release(struct device *dev)
+static void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
@@ -301,7 +298,7 @@ static struct device_attribute i2c_adapter_attrs[] = {
{ },
};
-struct class i2c_adapter_class = {
+static struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
@@ -934,28 +931,6 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
}
EXPORT_SYMBOL(i2c_master_recv);
-int i2c_control(struct i2c_client *client,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
- struct i2c_adapter *adap = client->adapter;
-
- dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
- switch (cmd) {
- case I2C_RETRIES:
- adap->retries = arg;
- break;
- case I2C_TIMEOUT:
- adap->timeout = arg;
- break;
- default:
- if (adap->algo->algo_control!=NULL)
- ret = adap->algo->algo_control(adap,cmd,arg);
- }
- return ret;
-}
-EXPORT_SYMBOL(i2c_control);
-
/* ----------------------------------------------------
* the i2c address scanning function
* Will not work for 10-bit addresses!
@@ -1310,7 +1285,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
}
EXPORT_SYMBOL(i2c_smbus_write_word_data);
-/* Returns the number of read bytes */
+/**
+ * i2c_smbus_read_block_data - SMBus block read request
+ * @client: Handle to slave device
+ * @command: Command byte issued to let the slave know what data should
+ * be returned
+ * @values: Byte array into which data will be read; big enough to hold
+ * the data returned by the slave. SMBus allows at most 32 bytes.
+ *
+ * Returns the number of bytes read in the slave's response, else a
+ * negative number to indicate some kind of error.
+ *
+ * Note that using this function requires that the client's adapter support
+ * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers
+ * support this; its emulation through I2C messaging relies on a specific
+ * mechanism (I2C_M_RECV_LEN) which may not be implemented.
+ */
s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
u8 *values)
{
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 64eee9551b2..5a15e50748d 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -226,8 +226,10 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
res = 0;
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
- /* Limit the size of the message to a sane amount */
- if (rdwr_pa[i].len > 8192) {
+ /* Limit the size of the message to a sane amount;
+ * and don't let length change either. */
+ if ((rdwr_pa[i].len > 8192) ||
+ (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
res = -EINVAL;
break;
}
@@ -352,9 +354,19 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
}
return res;
-
+ case I2C_RETRIES:
+ client->adapter->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ client->adapter->timeout = arg;
+ break;
default:
- return i2c_control(client,cmd,arg);
+ /* NOTE: returning a fault code here could cause trouble
+ * in buggy userspace code. Some old kernel bugs returned
+ * zero in this case, and userspace code might accidentally
+ * have depended on that bug.
+ */
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index aa0e0c9f74c..8982c093243 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -1074,22 +1074,6 @@ endif
config BLK_DEV_IDEDMA
def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-config IDEDMA_IVB
- bool "IGNORE word93 Validation BITS"
- depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
- ---help---
- There are unclear terms in ATA-4 and ATA-5 standards how certain
- hardware (an 80c ribbon) should be detected. Different interpretations
- of the standards have been released in hardware. This causes problems:
- for example, a host with Ultra Mode 4 (or higher) will not run
- in that mode with an 80c ribbon.
-
- If you are experiencing compatibility or performance problems, you
- MAY try to answer Y here. However, it does not necessarily solve
- any of your problems, it could even cause more of them.
-
- It is normally safe to answer Y; however, the default is N.
-
endif
config BLK_DEV_HD_ONLY
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 7912a471f10..bd1f5b67037 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -248,7 +248,7 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
* MW1 80 50 50 150 C
* MW2 70 25 25 120 C
*/
-static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
+static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
{
int cycle_time, use_dma_info = 0;
@@ -273,7 +273,7 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
cycle_time = 480;
break;
default:
- return 1;
+ return;
}
/*
@@ -287,8 +287,6 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
printk("%s: %s selected (peak %dMB/s)\n", drive->name,
ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
- return ide_config_drive_speed(drive, xfer_mode);
}
static void icside_dma_host_off(ide_drive_t *drive)
@@ -313,41 +311,10 @@ static int icside_dma_on(ide_drive_t *drive)
static int icside_dma_check(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- int xfer_mode = 0;
-
- if (!(id->capability & 1) || !hwif->autodma)
- goto out;
-
- /*
- * Consult the list of known "bad" drives
- */
- if (__ide_dma_bad_drive(drive))
- goto out;
-
- /*
- * Enable DMA on any drive that has multiword DMA
- */
- if (id->field_valid & 2) {
- xfer_mode = ide_max_dma_mode(drive);
- goto out;
- }
-
- /*
- * Consult the list of known "good" drives
- */
- if (__ide_dma_good_drive(drive)) {
- if (id->eide_dma_time > 150)
- goto out;
- xfer_mode = XFER_MW_DMA_1;
- }
-
-out:
- if (xfer_mode == 0)
- return -1;
+ if (ide_tune_dma(drive))
+ return 0;
- return icside_set_speed(drive, xfer_mode) ? -1 : 0;
+ return -1;
}
static int icside_dma_end(ide_drive_t *drive)
@@ -464,7 +431,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
hwif->dmatable_cpu = NULL;
hwif->dmatable_dma = 0;
- hwif->speedproc = icside_set_speed;
+ hwif->set_dma_mode = icside_set_dma_mode;
hwif->autodma = 1;
hwif->ide_dma_check = icside_dma_check;
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 4bb42b30bfc..2b4d2a0ae5c 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -716,11 +716,9 @@ static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
}
cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
-
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
+static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
int cyc = 0, dvs = 0, strobe = 0, hold = 0;
@@ -759,8 +757,6 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
else
cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
-
- return ide_config_drive_speed(drive, speed);
}
void __init
@@ -791,7 +787,7 @@ init_e100_ide (void)
hwif->mmio = 1;
hwif->chipset = ide_etrax100;
hwif->set_pio_mode = &cris_set_pio_mode;
- hwif->speedproc = &speed_cris_ide;
+ hwif->set_dma_mode = &cris_set_dma_mode;
hwif->ata_input_data = &cris_ide_input_data;
hwif->ata_output_data = &cris_ide_output_data;
hwif->atapi_input_bytes = &cris_atapi_input_bytes;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 6bff81a58bf..1d5f6823101 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -649,7 +649,6 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
if (!on)
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
}
-EXPORT_SYMBOL_GPL(ide_acpi_set_state);
/**
* ide_acpi_init - initialize the ACPI link for an IDE interface
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 6000c08f51b..b453211ee0f 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -169,6 +169,11 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
EXPORT_SYMBOL_GPL(ide_dma_intr);
+static int ide_dma_good_drive(ide_drive_t *drive)
+{
+ return ide_in_drive_list(drive->id, drive_whitelist);
+}
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
/**
* ide_build_sglist - map IDE scatter gather for DMA I/O
@@ -357,7 +362,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
return 0;
/* Consult the list of known "good" drives */
- if (__ide_dma_good_drive(drive))
+ if (ide_dma_good_drive(drive))
return 0;
}
@@ -639,14 +644,6 @@ int __ide_dma_bad_drive (ide_drive_t *drive)
EXPORT_SYMBOL(__ide_dma_bad_drive);
-int __ide_dma_good_drive (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- return ide_in_drive_list(id, drive_whitelist);
-}
-
-EXPORT_SYMBOL(__ide_dma_good_drive);
-
static const u8 xfer_mode_bases[] = {
XFER_UDMA_0,
XFER_MW_DMA_0,
@@ -746,6 +743,14 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
}
}
+ if (hwif->chipset == ide_acorn && mode == 0) {
+ /*
+ * is this correct?
+ */
+ if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+ mode = XFER_MW_DMA_1;
+ }
+
printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
return min(mode, req_mode);
@@ -769,7 +774,10 @@ int ide_tune_dma(ide_drive_t *drive)
if (!speed)
return 0;
- if (drive->hwif->speedproc(drive, speed))
+ if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
+
+ if (ide_set_dma_mode(drive, speed))
return 0;
return 1;
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 9560a8f4a86..4cece930114 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -836,9 +836,17 @@ static ide_startstop_t do_special (ide_drive_t *drive)
if (set_pio_mode_abuse(drive->hwif, req_pio)) {
if (hwif->set_pio_mode)
hwif->set_pio_mode(drive, req_pio);
- } else
+ } else {
+ int keep_dma = drive->using_dma;
+
ide_set_pio(drive, req_pio);
+ if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+ if (keep_dma)
+ hwif->ide_dma_on(drive);
+ }
+ }
+
return ide_stopped;
} else {
if (drive->media == ide_disk)
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index cf0678b6116..aa738833bed 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -473,57 +473,22 @@ int drive_is_ready (ide_drive_t *drive)
EXPORT_SYMBOL(drive_is_ready);
/*
- * Global for All, and taken from ide-pmac.c. Can be called
- * with spinlock held & IRQs disabled, so don't schedule !
- */
-int wait_for_ready (ide_drive_t *drive, int timeout)
-{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat = 0;
-
- while(--timeout) {
- stat = hwif->INB(IDE_STATUS_REG);
- if (!(stat & BUSY_STAT)) {
- if (drive->ready_stat == 0)
- break;
- else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
- break;
- }
- mdelay(1);
- }
- if ((stat & ERR_STAT) || timeout <= 0) {
- if (stat & ERR_STAT) {
- printk(KERN_ERR "%s: wait_for_ready, "
- "error status: %x\n", drive->name, stat);
- }
- return 1;
- }
- return 0;
-}
-
-/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
* of the "bad" bits, and if all is okay it returns 0. All other
- * cases return 1 after invoking ide_error() -- caller should just return.
+ * cases return error -- caller may then invoke ide_error().
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
- int i;
+ ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
-
- /* bail early if we've exceeded max_failures */
- if (drive->max_failures && (drive->failures > drive->max_failures)) {
- *startstop = ide_stopped;
- return 1;
- }
+ int i;
+ u8 stat;
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
@@ -541,8 +506,8 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
break;
local_irq_restore(flags);
- *startstop = ide_error(drive, "status timeout", stat);
- return 1;
+ *rstat = stat;
+ return -EBUSY;
}
}
local_irq_restore(flags);
@@ -556,11 +521,39 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+ *rstat = stat;
return 0;
+ }
}
- *startstop = ide_error(drive, "status error", stat);
- return 1;
+ *rstat = stat;
+ return -EFAULT;
+}
+
+/*
+ * In case of error returns error value after doing "*startstop = ide_error()".
+ * The caller should return the updated value of "startstop" in this case,
+ * "startstop" is unchanged when the function returns 0.
+ */
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+ int err;
+ u8 stat;
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
+ err = __ide_wait_stat(drive, good, bad, timeout, &stat);
+
+ if (err) {
+ char *s = (err == -EBUSY) ? "status timeout" : "status error";
+ *startstop = ide_error(drive, s, stat);
+ }
+
+ return err;
}
EXPORT_SYMBOL(ide_wait_stat);
@@ -620,15 +613,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
/*
* FIXME:
- * - change master/slave IDENTIFY order
* - force bit13 (80c cable present) check also for !ivb devices
* (unless the slave device is pre-ATA3)
*/
-#ifndef CONFIG_IDEDMA_IVB
if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
-#else
- if (id->hw_config & 0x6000)
-#endif
return 1;
no_80w:
@@ -778,15 +766,10 @@ int ide_driveid_update (ide_drive_t *drive)
#endif
}
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- int i, error = 1;
+ ide_hwif_t *hwif = drive->hwif;
+ int error;
u8 stat;
// while (HWGROUP(drive)->busy)
@@ -826,35 +809,10 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
- udelay(1);
- /*
- * Wait for drive to become non-BUSY
- */
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- unsigned long flags, timeout;
- local_irq_set(flags);
- timeout = jiffies + WAIT_CMD;
- while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- if (time_after(jiffies, timeout))
- break;
- }
- local_irq_restore(flags);
- }
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
- error = 0;
- break;
- }
- }
+ error = __ide_wait_stat(drive, drive->ready_stat,
+ BUSY_STAT|DRQ_STAT|ERR_STAT,
+ WAIT_CMD, &stat);
SELECT_MASK(drive, 0);
@@ -899,9 +857,6 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
return error;
}
-EXPORT_SYMBOL(ide_config_drive_speed);
-
-
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index d97390c0543..0e2562f0f74 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -349,7 +349,7 @@ void ide_set_pio(ide_drive_t *drive, u8 req_pio)
drive->name, host_pio, req_pio,
req_pio == 255 ? "(auto-tune)" : "", pio);
- hwif->set_pio_mode(drive, pio);
+ (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
}
EXPORT_SYMBOL_GPL(ide_set_pio);
@@ -378,39 +378,83 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
blk_queue_bounce_limit(drive->queue, addr);
}
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->set_pio_mode == NULL)
+ return -1;
+
+ /*
+ * TODO: temporary hack for some legacy host drivers that didn't
+ * set transfer mode on the device in ->set_pio_mode method...
+ */
+ if (hwif->set_dma_mode == NULL) {
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ }
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ } else {
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->set_dma_mode == NULL)
+ return -1;
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ hwif->set_dma_mode(drive, mode);
+ return 0;
+ } else {
+ hwif->set_dma_mode(drive, mode);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
/**
* ide_set_xfer_rate - set transfer rate
* @drive: drive to set
- * @speed: speed to attempt to set
+ * @rate: speed to attempt to set
*
* General helper for setting the speed of an IDE device. This
* function knows about user enforced limits from the configuration
- * which speedproc() does not. High level drivers should never
- * invoke speedproc() directly.
+ * which ->set_pio_mode/->set_dma_mode does not.
*/
-
+
int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
{
ide_hwif_t *hwif = drive->hwif;
- if (hwif->speedproc == NULL)
+ if (hwif->set_dma_mode == NULL)
return -1;
rate = ide_rate_filter(drive, rate);
- if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) {
- if (hwif->set_pio_mode)
- hwif->set_pio_mode(drive, rate - XFER_PIO_0);
+ if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+ return ide_set_pio_mode(drive, rate);
- /*
- * FIXME: this is incorrect to return zero here but
- * since all users of ide_set_xfer_rate() ignore
- * the return value it is not a problem currently
- */
- return 0;
- }
+ /*
+ * TODO: transfer modes 0x00-0x07 passed from the user-space are
+ * currently handled here which needs fixing (please note that such
+ * case could happen iff the transfer mode has already been set on
+ * the device by ide-proc.c::set_xfer_rate()).
+ */
- return hwif->speedproc(drive, rate);
+ return ide_set_dma_mode(drive, rate);
}
static void ide_dump_opcode(ide_drive_t *drive)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index b4c9f63a385..d1011712601 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -719,9 +719,9 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave);
*/
static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
{
- unsigned int unit;
unsigned long flags;
unsigned int irqd;
+ int unit;
if (hwif->noprobe)
return;
@@ -777,10 +777,9 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
/*
- * Second drive should only exist if first drive was found,
- * but a lot of cdrom drives are configured as single slaves.
+ * Need to probe slave device first to make it release PDIAG-.
*/
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ for (unit = MAX_DRIVES - 1; unit >= 0; unit--) {
ide_drive_t *drive = &hwif->drives[unit];
drive->dn = (hwif->channel ? 2 : 0) + unit;
(void) probe_for_drive(drive);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index e96212ce572..5c0e4078b5c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -397,7 +397,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
#endif
hwif->set_pio_mode = tmp_hwif->set_pio_mode;
- hwif->speedproc = tmp_hwif->speedproc;
+ hwif->set_dma_mode = tmp_hwif->set_dma_mode;
hwif->mdma_filter = tmp_hwif->mdma_filter;
hwif->udma_filter = tmp_hwif->udma_filter;
hwif->selectproc = tmp_hwif->selectproc;
@@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = {
__ATTR_NULL
};
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
{
ide_drive_t *drive = to_ide_device(dev);
- int i = 0;
- int length = 0;
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MEDIA=%s", media_string(drive));
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "DRIVENAME=%s", drive->name);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=ide:m-%s", media_string(drive));
- envp[i] = NULL;
+
+ add_uevent_var(env, "MEDIA=%s", media_string(drive));
+ add_uevent_var(env, "DRIVENAME=%s", drive->name);
+ add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
return 0;
}
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
index ccfb9893a46..b992b2b91fe 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/legacy/ide_platform.c
@@ -65,7 +65,7 @@ found:
hwif->hw.irq = hwif->irq = irq;
hwif->hw.dma = NO_DMA;
- hwif->hw.chipset = ide_generic;
+ hwif->chipset = hwif->hw.chipset = ide_generic;
if (mmio) {
hwif->mmio = 1;
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 85819ae2060..aebde49365d 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -101,12 +101,7 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- int mem_sttime;
- int mem_stcfg;
- u8 speed;
-
- mem_sttime = 0;
- mem_stcfg = au_readl(MEM_STCFG2);
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
/* set pio mode! */
switch(pio) {
@@ -164,18 +159,11 @@ static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
-
- speed = pio + XFER_PIO_0;
- ide_config_drive_speed(drive, speed);
}
-static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- int mem_sttime;
- int mem_stcfg;
-
- mem_sttime = 0;
- mem_stcfg = au_readl(MEM_STCFG2);
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -211,16 +199,11 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
break;
#endif
default:
- return 1;
+ return;
}
- if (ide_config_drive_speed(drive, speed))
- return 1;
-
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
-
- return 0;
}
/*
@@ -682,6 +665,7 @@ static int au_ide_probe(struct device *dev)
#endif
hwif->pio_mask = ATA_PIO4;
+ hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
hwif->noprobe = 0;
hwif->drives[0].unmask = 1;
@@ -702,7 +686,7 @@ static int au_ide_probe(struct device *dev)
#endif
hwif->set_pio_mode = &au1xxx_set_pio_mode;
- hwif->speedproc = &auide_tune_chipset;
+ hwif->set_dma_mode = &auide_set_dma_mode;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
hwif->dma_off_quietly = &auide_dma_off_quietly;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 0d5f62c5dfa..d6cb2d5143c 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -87,7 +87,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
return chipset_table->ultra_settings;
}
-static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -111,10 +111,9 @@ static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
pci_write_config_byte(dev, 0x54, tmp2);
local_irq_restore(flags);
- return(ide_config_drive_speed(drive, speed));
}
-static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -135,12 +134,11 @@ static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
local_irq_restore(flags);
- return(ide_config_drive_speed(drive, speed));
}
static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
+ drive->hwif->set_dma_mode(drive, pio + XFER_PIO_0);
}
static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
@@ -205,9 +203,9 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
if(hwif->mate)
hwif->mate->serialized = hwif->serialized = 1;
- hwif->speedproc = &aec6210_tune_chipset;
+ hwif->set_dma_mode = &aec6210_set_mode;
} else
- hwif->speedproc = &aec6260_tune_chipset;
+ hwif->set_dma_mode = &aec6260_set_mode;
if (!hwif->dma_base) {
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index d04b966b434..0b83443bf25 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -283,14 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
/**
- * ali_tune_pio - set host controller for PIO mode
+ * ali_set_pio_mode - set host controller for PIO mode
* @drive: drive
* @pio: PIO mode number
*
* Program the controller for the given PIO mode.
*/
-static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -358,21 +358,6 @@ static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
}
/**
- * ali_set_pio_mode - set up drive for PIO mode
- * @drive: drive to tune
- * @pio: desired mode
- *
- * Program the controller with the desired PIO timing for the given drive.
- * Then set up the drive itself.
- */
-
-static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- ali_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-/**
* ali_udma_filter - compute UDMA mask
* @drive: IDE device
*
@@ -401,15 +386,14 @@ static u8 ali_udma_filter(ide_drive_t *drive)
}
/**
- * ali15x3_tune_chipset - set up chipset/drive for new speed
- * @drive: drive to configure for
- * @speed: desired speed
+ * ali_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
* Configure the hardware for the desired IDE transfer mode.
- * We also do the needed drive configuration through helpers
*/
-static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -419,7 +403,7 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
int m5229_udma = (hwif->channel) ? 0x57 : 0x56;
if (speed < XFER_PIO_0)
- return 1;
+ return;
if (speed == XFER_UDMA_6)
speed1 = 0x47;
@@ -450,7 +434,6 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x4b, tmpbyte);
}
}
- return (ide_config_drive_speed(drive, speed));
}
/**
@@ -699,7 +682,7 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
{
hwif->autodma = 0;
hwif->set_pio_mode = &ali_set_pio_mode;
- hwif->speedproc = &ali15x3_tune_chipset;
+ hwif->set_dma_mode = &ali_set_dma_mode;
hwif->udma_filter = &ali_udma_filter;
/* don't use LBA48 DMA on ALi devices before rev 0xC5 */
@@ -711,6 +694,10 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
return;
}
+ /*
+ * check in ->init_dma guarantees m5229_revision >= 0x20 here
+ */
+
if (m5229_revision > 0x20)
hwif->atapi_dma = 1;
@@ -728,18 +715,15 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
- if (m5229_revision >= 0x20) {
- /*
- * M1543C or newer for DMAing
- */
- hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
- hwif->dma_setup = &ali15x3_dma_setup;
- if (!noautodma)
- hwif->autodma = 1;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_ali15x3(hwif);
- }
+ hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+ hwif->dma_setup = &ali15x3_dma_setup;
+
+ if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ hwif->cbl = ata66_ali15x3(hwif);
+
+ if (!noautodma)
+ hwif->autodma = 1;
+
hwif->drives[0].autodma = hwif->autodma;
hwif->drives[1].autodma = hwif->autodma;
}
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 513205e52ad..6ff4089a237 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -1,5 +1,5 @@
/*
- * Version 2.22
+ * Version 2.23
*
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
* IDE driver for Linux.
@@ -229,20 +229,16 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
}
/*
- * amd_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ * amd_set_drive() computes timing values and configures the chipset
+ * to a desired transfer mode. It also can be called by upper layers.
*/
-static int amd_set_drive(ide_drive_t *drive, const u8 speed)
+static void amd_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct ide_timing t, p;
int T, UT;
- if (speed != XFER_PIO_SLOW)
- ide_config_drive_speed(drive, speed);
-
T = 1000000000 / amd_clock;
UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
@@ -257,12 +253,6 @@ static int amd_set_drive(ide_drive_t *drive, const u8 speed)
if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
- if (!drive->init_speed)
- drive->init_speed = speed;
- drive->current_speed = speed;
-
- return 0;
}
/*
@@ -399,7 +389,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &amd_set_pio_mode;
- hwif->speedproc = &amd_set_drive;
+ hwif->set_dma_mode = &amd_set_drive;
for (i = 0; i < 2; i++) {
hwif->drives[i].io_32bit = 1;
@@ -441,7 +431,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
.bootable = ON_BOARD, \
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
- | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE \
+ | IDE_HFLAG_POST_SET_MODE, \
.pio_mask = ATA_PIO5, \
}
@@ -454,7 +445,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
.bootable = ON_BOARD, \
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
- | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE \
+ | IDE_HFLAG_POST_SET_MODE, \
.pio_mask = ATA_PIO5, \
}
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 178876a3afc..0eb97f021d3 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -122,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
}
/**
- * atiixp_tune_pio - tune a drive attached to a ATIIXP
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * atiixp_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -153,23 +153,16 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&atiixp_lock, flags);
}
-static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- atiixp_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * atiixp_tune_chipset - tune a ATIIXP interface
- * @drive: IDE drive to tune
- * @speed: speed to configure
+ * atiixp_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Set a ATIIXP interface channel to the desired speeds. This involves
- * requires the right timing data into the ATIIXP configuration space
- * then setting the drive parameters appropriately
+ * Set a ATIIXP host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
*/
-static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
+static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -204,9 +197,7 @@ static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
else
pio = speed - XFER_PIO_0;
- atiixp_tune_pio(drive, pio);
-
- return ide_config_drive_speed(drive, speed);
+ atiixp_set_pio_mode(drive, pio);
}
/**
@@ -249,7 +240,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &atiixp_set_pio_mode;
- hwif->speedproc = &atiixp_speedproc;
+ hwif->set_dma_mode = &atiixp_set_dma_mode;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 0b568c60f92..d50f15e34b8 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -280,10 +280,9 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
return;
cmd64x_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -324,13 +323,11 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
program_cycle_times(drive, 480, 215);
break;
default:
- return 1;
+ return;
}
if (speed >= XFER_SW_DMA_0)
(void) pci_write_config_byte(dev, pciU, regU);
-
- return ide_config_drive_speed(drive, speed);
}
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
@@ -524,7 +521,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
hwif->set_pio_mode = &cmd64x_set_pio_mode;
- hwif->speedproc = &cmd64x_tune_chipset;
+ hwif->set_dma_mode = &cmd64x_set_dma_mode;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 1217d2a747f..fbce90048ae 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -96,22 +96,13 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
reg = inb(hwif->dma_base + 0x02 + 8*controller);
reg |= 1<<((drive->dn&1)+5);
outb(reg, hwif->dma_base + 0x02 + 8*controller);
-
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
printk(KERN_ERR "cs55x0: bad ide timing.\n");
cs5520_set_pio_mode(drive, 0);
-
- /*
- * FIXME: this is incorrect to return zero here but
- * since all users of ide_set_xfer_rate() ignore
- * the return value it is not a problem currently
- */
- return 0;
}
static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
@@ -150,26 +141,25 @@ static int cs5520_dma_on(ide_drive_t *drive)
static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
{
hwif->set_pio_mode = &cs5520_set_pio_mode;
- hwif->speedproc = &cs5520_tune_chipset;
- hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
- hwif->ide_dma_on = &cs5520_dma_on;
+ hwif->set_dma_mode = &cs5520_set_dma_mode;
- if(!noautodma)
- hwif->autodma = 1;
-
- if(!hwif->dma_base)
- {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0) {
+ hwif->drives[1].autotune = hwif->drives[0].autotune = 1;
return;
}
+ hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
+ hwif->ide_dma_on = &cs5520_dma_on;
+
/* ATAPI is harder so leave it for now */
hwif->atapi_dma = 0;
hwif->ultra_mask = 0;
hwif->swdma_mask = 0;
hwif->mwdma_mask = 0;
-
+
+ if (!noautodma)
+ hwif->autodma = 1;
+
hwif->drives[0].autodma = hwif->autodma;
hwif->drives[1].autodma = hwif->autodma;
}
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 741507b4cd9..e4121577cef 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -30,22 +30,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-/**
- * cs5530_xfer_set_mode - set a new transfer mode at the drive
- * @drive: drive to tune
- * @mode: new mode
- *
- * Logging wrapper to the IDE driver speed configuration. This can
- * probably go away now.
- */
-
-static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
-{
- printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
- drive->name, ide_xfer_verbose(mode));
- return (ide_config_drive_speed(drive, mode));
-}
-
/*
* Here are the standard PIO mode 0-4 timings for each "format".
* Format-0 uses fast data reg timings, with slower command reg timings.
@@ -62,20 +46,12 @@ static unsigned int cs5530_pio_timings[2][5] = {
#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
-{
- unsigned long basereg = CS5530_BASEREG(drive->hwif);
- unsigned int format = (inl(basereg + 4) >> 31) & 1;
-
- outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
-}
-
/**
- * cs5530_set_pio_mode - set PIO mode
+ * cs5530_set_pio_mode - set host controller for PIO mode
* @drive: drive
* @pio: PIO mode number
*
- * Handles setting of PIO mode for both the chipset and drive.
+ * Handles setting of PIO mode for the chipset.
*
* The init_hwif_cs5530() routine guarantees that all drives
* will have valid default PIO timings set up before we get here.
@@ -83,8 +59,10 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
- cs5530_tunepio(drive, pio);
+ unsigned long basereg = CS5530_BASEREG(drive->hwif);
+ unsigned int format = (inl(basereg + 4) >> 31) & 1;
+
+ outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
}
/**
@@ -142,20 +120,11 @@ static int cs5530_config_dma(ide_drive_t *drive)
return 1;
}
-static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
+static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
unsigned long basereg;
unsigned int reg, timings = 0;
- /*
- * Tell the drive to switch to the new mode; abort on failure.
- */
- if (cs5530_set_xfer_mode(drive, mode))
- return 1; /* failure */
-
- /*
- * Now tune the chipset to match the drive:
- */
switch (mode) {
case XFER_UDMA_0: timings = 0x00921250; break;
case XFER_UDMA_1: timings = 0x00911140; break;
@@ -180,8 +149,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
outl(reg, basereg + 4); /* write drive0 config register */
outl(timings, basereg + 12); /* write drive1 config register */
}
-
- return 0; /* success */
}
/**
@@ -299,7 +266,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
hwif->serialized = hwif->mate->serialized = 1;
hwif->set_pio_mode = &cs5530_set_pio_mode;
- hwif->speedproc = &cs5530_tune_chipset;
+ hwif->set_dma_mode = &cs5530_set_dma_mode;
basereg = CS5530_BASEREG(hwif);
d0_timings = inl(basereg + 0);
@@ -340,6 +307,7 @@ static ide_pci_device_t cs5530_chipset __devinitdata = {
.autodma = AUTODMA,
.bootable = ON_BOARD,
.pio_mask = ATA_PIO4,
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
};
static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 383b7eccbcb..257865778f9 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -131,24 +131,21 @@ static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
}
}
-/****
- * cs5535_set_drive - Configure the drive to the new speed
- * @drive: Drive to set up
- * @speed: desired speed
+/**
+ * cs5535_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * cs5535_set_drive() configures the drive and the chipset to a
- * new speed. It also can be called by upper layers.
+ * Programs the chipset for DMA mode.
*/
-static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+
+static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- ide_config_drive_speed(drive, speed);
cs5535_set_speed(drive, speed);
-
- return 0;
}
/**
- * cs5535_set_pio_mode - PIO setup
+ * cs5535_set_pio_mode - set host controller for PIO mode
* @drive: drive
* @pio: PIO mode number
*
@@ -157,7 +154,6 @@ static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
cs5535_set_speed(drive, XFER_PIO_0 + pio);
}
@@ -194,12 +190,16 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
*/
static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
{
- int i;
-
hwif->autodma = 0;
hwif->set_pio_mode = &cs5535_set_pio_mode;
- hwif->speedproc = &cs5535_set_drive;
+ hwif->set_dma_mode = &cs5535_set_dma_mode;
+
+ hwif->drives[1].autotune = hwif->drives[0].autotune = 1;
+
+ if (hwif->dma_base == 0)
+ return;
+
hwif->ide_dma_check = &cs5535_dma_check;
hwif->atapi_dma = 1;
@@ -211,11 +211,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
if (!noautodma)
hwif->autodma = 1;
- /* just setting autotune and not worrying about bios timings */
- for (i = 0; i < 2; i++) {
- hwif->drives[i].autotune = 1;
- hwif->drives[i].autodma = hwif->autodma;
- }
+ hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma;
}
static ide_pci_device_t cs5535_chipset __devinitdata = {
@@ -223,7 +219,7 @@ static ide_pci_device_t cs5535_chipset __devinitdata = {
.init_hwif = init_hwif_cs5535,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
.pio_mask = ATA_PIO4,
};
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index a1bb10188fe..218852aaf22 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -43,7 +43,7 @@
#define HPT343_DEBUG_DRIVE_INFO 0
-static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
@@ -73,13 +73,11 @@ static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
drive->dn, reg1, tmp1, reg2, tmp2,
hi_speed, lo_speed);
#endif /* HPT343_DEBUG_DRIVE_INFO */
-
- return(ide_config_drive_speed(drive, speed));
}
static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+ hpt34x_set_mode(drive, XFER_PIO_0 + pio);
}
static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
@@ -145,7 +143,8 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &hpt34x_set_pio_mode;
- hwif->speedproc = &hpt34x_tune_chipset;
+ hwif->set_dma_mode = &hpt34x_set_mode;
+
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 0e7d3b60d43..8812a9bb032 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -600,7 +600,7 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
return (*info->settings)[i];
}
-static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -623,11 +623,9 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
new_itr &= ~0xc0000000;
pci_write_config_dword(dev, itr_addr, new_itr);
-
- return ide_config_drive_speed(drive, speed);
}
-static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -647,24 +645,22 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
if (speed < XFER_MW_DMA_0)
new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
pci_write_config_dword(dev, itr_addr, new_itr);
-
- return ide_config_drive_speed(drive, speed);
}
-static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
if (info->chip_type >= HPT370)
- return hpt37x_tune_chipset(drive, speed);
+ hpt37x_set_mode(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
- return hpt36x_tune_chipset(drive, speed);
+ hpt36x_set_mode(drive, speed);
}
static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
+ hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
}
static int hpt3xx_quirkproc(ide_drive_t *drive)
@@ -1257,7 +1253,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->select_data = hwif->channel ? 0x54 : 0x50;
hwif->set_pio_mode = &hpt3xx_set_pio_mode;
- hwif->speedproc = &hpt3xx_tune_chipset;
+ hwif->set_dma_mode = &hpt3xx_set_mode;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 76e91ff9420..ecf4ce078dc 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -48,15 +48,15 @@ static u8 it8213_dma_2_pio (u8 xfer_rate) {
}
}
-/*
- * it8213_tune_pio - tune a drive
- * @drive: drive to tune
- * @pio: desired PIO mode
+/**
+ * it8213_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -105,21 +105,15 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
spin_unlock_irqrestore(&tune_lock, flags);
}
-static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- it8213_tune_pio(drive, pio);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * it8213_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @speed: speed we want to achieve
+ * it8213_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Tune the ITE chipset for the desired mode.
+ * Tune the ITE chipset for the DMA mode.
*/
-static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -152,7 +146,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
case XFER_SW_DMA_2:
break;
default:
- return -1;
+ return;
}
if (speed >= XFER_UDMA_0) {
@@ -182,9 +176,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- it8213_tune_pio(drive, it8213_dma_2_pio(speed));
-
- return ide_config_drive_speed(drive, speed);
+ it8213_set_pio_mode(drive, it8213_dma_2_pio(speed));
}
/**
@@ -220,7 +212,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{
u8 reg42h = 0;
- hwif->speedproc = &it8213_tune_chipset;
+ hwif->set_dma_mode = &it8213_set_dma_mode;
hwif->set_pio_mode = &it8213_set_pio_mode;
hwif->autodma = 0;
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 758a98230cc..1b69d82478c 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -229,24 +229,24 @@ static void it821x_clock_strategy(ide_drive_t *drive)
}
/**
- * it821x_tunepio - tune a drive
- * @drive: drive to tune
- * @pio: the desired PIO mode
+ * it821x_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * Try to tune the drive/host to the desired PIO mode taking into
- * the consideration the maximum PIO mode supported by the other
- * device on the cable.
+ * Tune the host to the desired PIO mode taking into the consideration
+ * the maximum PIO mode supported by the other device on the cable.
*/
-static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
int unit = drive->select.b.unit;
ide_drive_t *pair = &hwif->drives[1 - unit];
+ u8 set_pio = pio;
/* Spec says 89 ref driver uses 88 */
- static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
/*
@@ -261,22 +261,12 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
set_pio = pair_pio;
}
- if (itdev->smart)
- return 0;
-
/* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
itdev->want[unit][1] = pio_want[set_pio];
itdev->want[unit][0] = 1; /* PIO is lowest priority */
- itdev->pio[unit] = pio[set_pio];
+ itdev->pio[unit] = pio_timings[set_pio];
it821x_clock_strategy(drive);
it821x_program(drive, itdev->pio[unit]);
-
- return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
-}
-
-static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- (void)it821x_tunepio(drive, pio);
}
/**
@@ -405,47 +395,24 @@ static int it821x_dma_end(ide_drive_t *drive)
}
/**
- * it821x_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @speed: speed we want to achieve
+ * it821x_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Tune the ITE chipset for the desired mode.
+ * Tune the ITE chipset for the desired DMA mode.
*/
-static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
-
- ide_hwif_t *hwif = drive->hwif;
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-
- if (itdev->smart == 0) {
- switch (speed) {
- /* MWDMA tuning is really hard because our MWDMA and PIO
- timings are kept in the same place. We can switch in the
- host dma on/off callbacks */
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1:
- case XFER_MW_DMA_0:
- it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
- break;
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- it821x_tune_udma(drive, (speed - XFER_UDMA_0));
- break;
- default:
- return 1;
- }
-
- return ide_config_drive_speed(drive, speed);
- }
-
- /* don't touch anything in the smart mode */
- return 0;
+ /*
+ * MWDMA tuning is really hard because our MWDMA and PIO
+ * timings are kept in the same place. We can switch in the
+ * host dma on/off callbacks.
+ */
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
+ it821x_tune_udma(drive, speed - XFER_UDMA_0);
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
}
/**
@@ -629,14 +596,15 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
}
- hwif->speedproc = &it821x_tune_chipset;
- hwif->set_pio_mode = &it821x_set_pio_mode;
+ if (idev->smart == 0) {
+ hwif->set_pio_mode = &it821x_set_pio_mode;
+ hwif->set_dma_mode = &it821x_set_dma_mode;
- /* MWDMA/PIO clock switching for pass through mode */
- if(!idev->smart) {
+ /* MWDMA/PIO clock switching for pass through mode */
hwif->dma_start = &it821x_dma_start;
hwif->ide_dma_end = &it821x_dma_end;
- }
+ } else
+ hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index d379fbaf674..582b4cae2b5 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -85,21 +85,18 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
- * jmicron_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @speed: speed we want to achieve
+ * jmicron_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @mode: DMA mode
*
- * As the JMicron snoops for timings all we actually need to do is
- * set the transfer mode on the device.
+ * As the JMicron snoops for timings we don't need to do anything here.
*/
-static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
- return ide_config_drive_speed(drive, speed);
}
/**
@@ -129,8 +126,8 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive)
static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
{
- hwif->speedproc = &jmicron_tune_chipset;
hwif->set_pio_mode = &jmicron_set_pio_mode;
+ hwif->set_dma_mode = &jmicron_set_dma_mode;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 5fb1eedc819..ad0bdcb0c02 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -146,19 +146,16 @@ static struct udma_timing {
{ 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
};
-static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
- int err;
/*
- * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
+ * IDE core issues SETFEATURES_XFER to the drive first (thanks to
+ * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will
* automatically set the timing registers based on 100 MHz PLL output.
- */
- err = ide_config_drive_speed(drive, speed);
-
- /*
+ *
* As we set up the PLL to output 133 MHz for UltraDMA/133 capable
* chips, we must override the default register settings...
*/
@@ -211,13 +208,11 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
}
-
- return err;
}
static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
+ pdcnew_set_mode(drive, XFER_PIO_0 + pio);
}
static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
@@ -490,9 +485,9 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &pdcnew_set_pio_mode;
+ hwif->set_dma_mode = &pdcnew_set_mode;
hwif->quirkproc = &pdcnew_quirkproc;
- hwif->speedproc = &pdcnew_tune_chipset;
hwif->resetproc = &pdcnew_reset;
hwif->err_stops_fifo = 1;
@@ -583,6 +578,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 1 */
.name = "PDC20269",
.init_setup = init_setup_pdcnew,
@@ -592,6 +588,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 2 */
.name = "PDC20270",
.init_setup = init_setup_pdc20270,
@@ -601,6 +598,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 3 */
.name = "PDC20271",
.init_setup = init_setup_pdcnew,
@@ -610,6 +608,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 4 */
.name = "PDC20275",
.init_setup = init_setup_pdcnew,
@@ -619,6 +618,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 5 */
.name = "PDC20276",
.init_setup = init_setup_pdc20276,
@@ -628,6 +628,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
},{ /* 6 */
.name = "PDC20277",
.init_setup = init_setup_pdcnew,
@@ -637,6 +638,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.bootable = OFF_BOARD,
.pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
+ .host_flags = IDE_HFLAG_POST_SET_MODE,
}
};
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index b578307fad5..8c3e8cf36ec 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -63,7 +63,7 @@ static const char *pdc_quirk_drives[] = {
static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
-static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -138,13 +138,11 @@ static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_read_config_dword(dev, drive_pci, &drive_conf);
printk("0x%08x\n", drive_conf);
#endif
-
- return ide_config_drive_speed(drive, speed);
}
static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
+ pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
}
static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
@@ -330,14 +328,13 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+ hwif->set_dma_mode = &pdc202xx_set_mode;
hwif->quirkproc = &pdc202xx_quirkproc;
if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
hwif->resetproc = &pdc202xx_reset;
- hwif->speedproc = &pdc202xx_tune_chipset;
-
hwif->err_stops_fifo = 1;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index fd8214a7ab9..38c91ba6497 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -137,13 +137,14 @@ static u8 piix_dma_2_pio (u8 xfer_rate) {
}
/**
- * piix_tune_pio - tune PIIX for PIO mode
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * piix_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode based upon the settings done by AMI BIOS.
*/
-static void piix_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -204,31 +205,15 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
}
/**
- * piix_set_pio_mode - set PIO mode
- * @drive: drive to tune
- * @pio: desired PIO mode
- *
- * Set the drive's PIO mode (might be useful if drive is not registered
- * in CMOS for any reason).
- */
-
-static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- piix_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-/**
- * piix_tune_chipset - tune a PIIX interface
- * @drive: IDE drive to tune
- * @speed: speed to configure
+ * piix_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Set a PIIX interface channel to the desired speeds. This involves
- * requires the right timing data into the PIIX configuration space
- * then setting the drive parameters appropriately
+ * Set a PIIX host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
*/
-static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -259,7 +244,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- default: return -1;
+ default: return;
}
if (speed >= XFER_UDMA_0) {
@@ -288,9 +273,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- piix_tune_pio(drive, piix_dma_2_pio(speed));
-
- return ide_config_drive_speed(drive, speed);
+ piix_set_pio_mode(drive, piix_dma_2_pio(speed));
}
/**
@@ -448,7 +431,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &piix_set_pio_mode;
- hwif->speedproc = &piix_tune_chipset;
+ hwif->set_dma_mode = &piix_set_dma_mode;
+
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 79ecab68948..ee0e3f554d9 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -68,17 +68,6 @@ static unsigned short sc1200_get_pci_clock (void)
return pci_clock;
}
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
- printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
- return ide_config_drive_speed(drive, mode);
-}
-
/*
* Here are the standard PIO mode 0-4 timings for each "format".
* Format-0 uses fast data reg timings, with slower command reg timings.
@@ -138,7 +127,7 @@ out:
return mask;
}
-static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
+static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
ide_hwif_t *hwif = HWIF(drive);
int unit = drive->select.b.unit;
@@ -146,17 +135,9 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
unsigned short pci_clock;
unsigned int basereg = hwif->channel ? 0x50 : 0x40;
- /*
- * Tell the drive to switch to the new mode; abort on failure.
- */
- if (sc1200_set_xfer_mode(drive, mode))
- return 1; /* failure */
-
pci_clock = sc1200_get_pci_clock();
/*
- * Now tune the chipset to match the drive:
- *
* Note that each DMA mode has several timings associated with it.
* The correct timing depends on the fast PCI clock freq.
*/
@@ -216,8 +197,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
} else {
pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
}
-
- return 0; /* success */
}
/*
@@ -286,13 +265,12 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
if (mode != -1) {
printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
hwif->dma_off_quietly(drive);
- if (sc1200_tune_chipset(drive, mode) == 0)
+ if (ide_set_dma_mode(drive, mode) == 0)
hwif->dma_host_on(drive);
return;
}
- if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
- sc1200_tunepio(drive, pio);
+ sc1200_tunepio(drive, pio);
}
#ifdef CONFIG_PM
@@ -400,16 +378,20 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
hwif->autodma = 0;
- if (hwif->dma_base) {
- hwif->udma_filter = sc1200_udma_filter;
- hwif->ide_dma_check = &sc1200_config_dma;
- hwif->ide_dma_end = &sc1200_ide_dma_end;
- if (!noautodma)
- hwif->autodma = 1;
-
- hwif->set_pio_mode = &sc1200_set_pio_mode;
- hwif->speedproc = &sc1200_tune_chipset;
- }
+
+ hwif->set_pio_mode = &sc1200_set_pio_mode;
+ hwif->set_dma_mode = &sc1200_set_dma_mode;
+
+ if (hwif->dma_base == 0)
+ return;
+
+ hwif->udma_filter = sc1200_udma_filter;
+ hwif->ide_dma_check = &sc1200_config_dma;
+ hwif->ide_dma_end = &sc1200_ide_dma_end;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x07;
hwif->mwdma_mask = 0x07;
@@ -423,7 +405,7 @@ static ide_pci_device_t sc1200_chipset __devinitdata = {
.init_hwif = init_hwif_sc1200,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_ABUSE_DMA_MODES,
+ .host_flags = IDE_HFLAG_ABUSE_DMA_MODES | IDE_HFLAG_POST_SET_MODE,
.pio_mask = ATA_PIO4,
};
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 66a526e0ece..67f06dd11b3 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -190,15 +190,15 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
}
/**
- * scc_tune_pio - tune a drive PIO mode
- * @drive: drive to tune
- * @mode_wanted: the target operating mode
+ * scc_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller.
*/
-static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -221,22 +221,16 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
out_be32((void __iomem *)pioct_port, reg);
}
-static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- scc_tune_pio(drive, pio);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * scc_tune_chipset - tune a drive DMA mode
- * @drive: Drive to set up
- * @speed: speed we want to achieve
+ * scc_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
* Load the timing settings for this device mode into the
* controller.
*/
-static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -271,7 +265,7 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
idx = speed - XFER_UDMA_0;
break;
default:
- return 1;
+ return;
}
jcactsel = JCACTSELtbl[offset][idx];
@@ -287,8 +281,6 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
}
reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
out_be32((void __iomem *)udenvt_port, reg);
-
- return ide_config_drive_speed(drive, speed);
}
/**
@@ -708,8 +700,8 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
hwif->dma_setup = scc_dma_setup;
hwif->ide_dma_end = scc_ide_dma_end;
- hwif->speedproc = scc_tune_chipset;
hwif->set_pio_mode = scc_set_pio_mode;
+ hwif->set_dma_mode = scc_set_dma_mode;
hwif->ide_dma_check = scc_config_drive_for_dma;
hwif->ide_dma_test_irq = scc_dma_test_irq;
hwif->udma_filter = scc_udma_filter;
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 0351cf21042..49ec0ac64a4 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -124,7 +124,7 @@ static u8 svwks_csb_check (struct pci_dev *dev)
return 0;
}
-static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
@@ -145,7 +145,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
}
}
-static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
@@ -193,14 +193,6 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);
-
- return (ide_config_drive_speed(drive, speed));
-}
-
-static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- svwks_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -384,7 +376,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->set_pio_mode = &svwks_set_pio_mode;
- hwif->speedproc = &svwks_tune_chipset;
+ hwif->set_dma_mode = &svwks_set_dma_mode;
hwif->udma_filter = &svwks_udma_filter;
hwif->atapi_dma = 1;
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index c292e1de1d5..85ffaaa39b1 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -291,12 +291,8 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
drive->hwif->dma_host_off(drive);
}
-static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed)
+static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- if (speed != XFER_MW_DMA_2)
- return 1;
-
- return ide_config_drive_speed(drive, speed);
}
static int sgiioc4_ide_dma_check(ide_drive_t *drive)
@@ -591,11 +587,9 @@ static void __devinit
ide_init_sgiioc4(ide_hwif_t * hwif)
{
hwif->mmio = 1;
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x04;
hwif->pio_mask = 0x00;
hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
- hwif->speedproc = &sgiioc4_speedproc;
+ hwif->set_dma_mode = &sgiioc4_set_dma_mode;
hwif->selectproc = NULL;/* Use the default routine to select drive */
hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
@@ -606,6 +600,14 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->quirkproc = NULL;
hwif->busproc = NULL;
+ hwif->INB = &sgiioc4_INB;
+
+ if (hwif->dma_base == 0)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x04;
+
hwif->dma_setup = &sgiioc4_ide_dma_setup;
hwif->dma_start = &sgiioc4_ide_dma_start;
hwif->ide_dma_end = &sgiioc4_ide_dma_end;
@@ -617,8 +619,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->dma_host_off = &sgiioc4_dma_host_off;
hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
hwif->dma_timeout = &ide_dma_timeout;
-
- hwif->INB = &sgiioc4_INB;
}
static int __devinit
@@ -688,8 +688,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
/* Initializing chipset IRQ Registers */
writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
- ide_init_sgiioc4(hwif);
-
hwif->autodma = 0;
if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) {
@@ -699,6 +697,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
hwif->name, DRV_NAME);
+ ide_init_sgiioc4(hwif);
+
if (probe_hwif_init(hwif))
return -EIO;
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 5d1e5e52a04..ce7784996d1 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -165,16 +165,16 @@ out:
}
/**
- * sil_tune_pio - tune a drive
- * @drive: drive to tune
- * @pio: the desired PIO mode
+ * sil_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller. If we are in PIO mode 3 or 4 turn on IORDY
* monitoring (bit 9). The TF timing is bits 31:16
*/
-static void sil_tune_pio(ide_drive_t *drive, u8 pio)
+static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
{
const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
@@ -234,21 +234,15 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio)
}
}
-static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- sil_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * siimage_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @speed: speed we want to achieve
+ * sil_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Tune the SII chipset for the desired mode.
+ * Tune the SiI chipset for the desired DMA mode.
*/
-static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
@@ -303,7 +297,7 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
mode |= ((unit) ? 0x30 : 0x03);
break;
default:
- return 1;
+ return;
}
if (hwif->mmio) {
@@ -315,7 +309,6 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_word(hwif->pci_dev, ma, multi);
pci_write_config_word(hwif->pci_dev, ua, ultra);
}
- return (ide_config_drive_speed(drive, speed));
}
/**
@@ -904,8 +897,8 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->resetproc = &siimage_reset;
- hwif->speedproc = &siimage_tune_chipset;
hwif->set_pio_mode = &sil_set_pio_mode;
+ hwif->set_dma_mode = &sil_set_dma_mode;
hwif->reset_poll = &siimage_reset_poll;
hwif->pre_reset = &siimage_pre_reset;
hwif->udma_filter = &sil_udma_filter;
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 3e18899de63..b375ee53d66 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -451,7 +451,7 @@ static void config_drive_art_rwp (ide_drive_t *drive)
}
/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -519,20 +519,14 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
}
}
-static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- config_art_rwp_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u32 regdw;
u8 drive_pci, reg;
- /* See config_art_rwp_pio for drive pci config registers */
+ /* See sis_set_pio_mode() for drive PCI config registers */
drive_pci = 0x40;
if (chipset_family >= ATA_133) {
u32 reg54h;
@@ -600,8 +594,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
BUG();
break;
}
-
- return ide_config_drive_speed(drive, speed);
}
static int sis5513_config_xfer_rate(ide_drive_t *drive)
@@ -841,7 +833,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->set_pio_mode = &sis_set_pio_mode;
- hwif->speedproc = &sis5513_tune_chipset;
+ hwif->set_dma_mode = &sis_set_dma_mode;
if (chipset_family >= ATA_133)
hwif->udma_filter = sis5513_ata133_udma_filter;
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index f492318ba79..2ef26e3f7be 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -75,7 +75,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
/*
* Configure the chipset for PIO mode.
*/
-static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
int reg = 0x44 + drive->dn * 4;
@@ -105,9 +105,9 @@ static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
}
/*
- * Configure the drive and chipset for a new transfer speed.
+ * Configure the chipset for DMA mode.
*/
-static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
u16 drv_ctrl;
@@ -140,10 +140,8 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
}
break;
default:
- return -1;
+ return;
}
-
- return ide_config_drive_speed(drive, speed);
}
/*
@@ -306,17 +304,6 @@ static void sl82c105_resetproc(ide_drive_t *drive)
pci_read_config_dword(dev, 0x40, &val);
pci_set_drvdata(dev, (void *)val);
}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- sl82c105_tune_pio(drive, pio);
-
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
/*
* Return the revision of the Winbond bridge
@@ -383,7 +370,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
hwif->set_pio_mode = &sl82c105_set_pio_mode;
- hwif->speedproc = &sl82c105_tune_chipset;
+ hwif->set_dma_mode = &sl82c105_set_dma_mode;
hwif->selectproc = &sl82c105_selectproc;
hwif->resetproc = &sl82c105_resetproc;
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index ae8e9132457..ebac87f7200 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -42,7 +42,7 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
}
}
-static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -95,13 +95,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&ide_lock, flags);
}
-static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- slc90e66_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -125,7 +119,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- default: return -1;
+ default: return;
}
if (speed >= XFER_UDMA_0) {
@@ -144,9 +138,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
}
- slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
-
- return ide_config_drive_speed(drive, speed);
+ slc90e66_set_pio_mode(drive, slc90e66_dma_2_pio(speed));
}
static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
@@ -172,8 +164,8 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
- hwif->speedproc = &slc90e66_tune_chipset;
hwif->set_pio_mode = &slc90e66_set_pio_mode;
+ hwif->set_dma_mode = &slc90e66_set_dma_mode;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index e23b9cfb6eb..840415d68d3 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -13,7 +13,7 @@
#include <linux/pci.h>
#include <linux/ide.h>
-static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
@@ -39,13 +39,11 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
scr |= mode;
outw(scr, scr_port);
-
- return ide_config_drive_speed(drive, speed);
}
static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+ tc86c001_set_mode(drive, XFER_PIO_0 + pio);
}
/*
@@ -193,7 +191,8 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
hwif->config_data = sc_base;
hwif->set_pio_mode = &tc86c001_set_pio_mode;
- hwif->speedproc = &tc86c001_tune_chipset;
+ hwif->set_dma_mode = &tc86c001_set_mode;
+
hwif->busproc = &tc86c001_busproc;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index c3ff066eea5..54e411d4e56 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -40,7 +40,7 @@
#include <linux/ide.h>
#include <linux/init.h>
-static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -82,20 +82,18 @@ static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
timing = 0x0808;
break;
default:
- return -1;
+ return;
}
triflex_timings &= ~(0xFFFF << (16 * unit));
triflex_timings |= (timing << (16 * unit));
pci_write_config_dword(dev, channel_offset, triflex_timings);
-
- return (ide_config_drive_speed(drive, speed));
}
static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio);
+ triflex_set_mode(drive, XFER_PIO_0 + pio);
}
static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
@@ -111,7 +109,7 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
{
hwif->set_pio_mode = &triflex_set_pio_mode;
- hwif->speedproc = &triflex_tune_chipset;
+ hwif->set_dma_mode = &triflex_set_mode;
if (hwif->dma_base == 0)
return;
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 378feb491ec..479e4966103 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -1,6 +1,6 @@
/*
*
- * Version 3.48
+ * Version 3.49
*
* VIA IDE driver for Linux. Supported southbridges:
*
@@ -153,21 +153,17 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
* @drive: Drive to set up
* @speed: desired speed
*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ * via_set_drive() computes timing values configures the chipset to
+ * a desired transfer mode. It also can be called by upper layers.
*/
-static int via_set_drive(ide_drive_t *drive, const u8 speed)
+static void via_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
struct ide_timing t, p;
unsigned int T, UT;
- if (speed != XFER_PIO_SLOW)
- ide_config_drive_speed(drive, speed);
-
T = 1000000000 / via_clock;
switch (vdev->via_config->udma_mask) {
@@ -186,16 +182,10 @@ static int via_set_drive(ide_drive_t *drive, const u8 speed)
}
via_set_speed(HWIF(drive), drive->dn, &t);
-
- if (!drive->init_speed)
- drive->init_speed = speed;
- drive->current_speed = speed;
-
- return 0;
}
/**
- * via_set_pio_mode - PIO setup
+ * via_set_pio_mode - set host controller for PIO mode
* @drive: drive
* @pio: PIO mode number
*
@@ -456,8 +446,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->set_pio_mode = &via_set_pio_mode;
- hwif->speedproc = &via_set_drive;
-
+ hwif->set_dma_mode = &via_set_drive;
#ifdef CONFIG_PPC_CHRP
if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
@@ -500,7 +489,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
.bootable = ON_BOARD,
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
- | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ | IDE_HFLAG_PIO_NO_DOWNGRADE
+ | IDE_HFLAG_POST_SET_MODE,
.pio_mask = ATA_PIO5,
},{ /* 1 */
.name = "VP_IDE",
@@ -510,7 +500,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
.enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
.bootable = ON_BOARD,
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
- | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ | IDE_HFLAG_PIO_NO_DOWNGRADE
+ | IDE_HFLAG_POST_SET_MODE,
.pio_mask = ATA_PIO5,
}
};
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index f759a539786..7d8873839e2 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -392,6 +392,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
for (i=0; table[i].cycle_time; i++)
if (cycle_time > table[i+1].cycle_time)
return table[i].timing_reg;
+ BUG();
return 0;
}
@@ -529,97 +530,12 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
}
/*
- * Send the SET_FEATURE IDE command to the drive and update drive->id with
- * the new state. We currently don't use the generic routine as it used to
- * cause various trouble, especially with older mediabays.
- * This code is sometimes triggering a spurrious interrupt though, I need
- * to sort that out sooner or later and see if I can finally get the
- * common version to work properly in all cases
- */
-static int
-pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
-{
- ide_hwif_t *hwif = HWIF(drive);
- int result = 1;
-
- disable_irq_nosync(hwif->irq);
- udelay(1);
- SELECT_DRIVE(drive);
- SELECT_MASK(drive, 0);
- udelay(1);
- /* Get rid of pending error state */
- (void) hwif->INB(IDE_STATUS_REG);
- /* Timeout bumped for some powerbooks */
- if (wait_for_ready(drive, 2000)) {
- /* Timeout bumped for some powerbooks */
- printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
- "before SET_FEATURE!\n", drive->name);
- goto out;
- }
- udelay(10);
- hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
- hwif->OUTB(command, IDE_NSECTOR_REG);
- hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
- hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
- udelay(1);
- /* Timeout bumped for some powerbooks */
- result = wait_for_ready(drive, 2000);
- hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
- if (result)
- printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
- "after SET_FEATURE !\n", drive->name);
-out:
- SELECT_MASK(drive, 0);
- if (result == 0) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- switch(command) {
- case XFER_UDMA_7:
- drive->id->dma_ultra |= 0x8080; break;
- case XFER_UDMA_6:
- drive->id->dma_ultra |= 0x4040; break;
- case XFER_UDMA_5:
- drive->id->dma_ultra |= 0x2020; break;
- case XFER_UDMA_4:
- drive->id->dma_ultra |= 0x1010; break;
- case XFER_UDMA_3:
- drive->id->dma_ultra |= 0x0808; break;
- case XFER_UDMA_2:
- drive->id->dma_ultra |= 0x0404; break;
- case XFER_UDMA_1:
- drive->id->dma_ultra |= 0x0202; break;
- case XFER_UDMA_0:
- drive->id->dma_ultra |= 0x0101; break;
- case XFER_MW_DMA_2:
- drive->id->dma_mword |= 0x0404; break;
- case XFER_MW_DMA_1:
- drive->id->dma_mword |= 0x0202; break;
- case XFER_MW_DMA_0:
- drive->id->dma_mword |= 0x0101; break;
- case XFER_SW_DMA_2:
- drive->id->dma_1word |= 0x0404; break;
- case XFER_SW_DMA_1:
- drive->id->dma_1word |= 0x0202; break;
- case XFER_SW_DMA_0:
- drive->id->dma_1word |= 0x0101; break;
- default: break;
- }
- if (!drive->init_speed)
- drive->init_speed = command;
- drive->current_speed = command;
- }
- enable_irq(hwif->irq);
- return result;
-}
-
-/*
* Old tuning functions (called on hdparm -p), sets up drive PIO timings
*/
static void
pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- u32 *timings;
+ u32 *timings, t;
unsigned accessTicks, recTicks;
unsigned accessTime, recTime;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
@@ -630,6 +546,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
/* which drive is it ? */
timings = &pmif->timings[drive->select.b.unit & 0x01];
+ t = *timings;
cycle_time = ide_pio_cycle_time(drive, pio);
@@ -637,18 +554,14 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
case controller_sh_ata6: {
/* 133Mhz cell */
u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
- if (tr == 0)
- return;
- *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
+ t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
break;
}
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
- if (tr == 0)
- return;
- *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
+ t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
break;
}
case controller_kl_ata4:
@@ -662,9 +575,9 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
accessTicks = min(accessTicks, 0x1fU);
recTicks = SYSCLK_TICKS_66(recTime);
recTicks = min(recTicks, 0x1fU);
- *timings = ((*timings) & ~TR_66_PIO_MASK) |
- (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
- (recTicks << TR_66_PIO_RECOVERY_SHIFT);
+ t = (t & ~TR_66_PIO_MASK) |
+ (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_66_PIO_RECOVERY_SHIFT);
break;
default: {
/* 33Mhz cell */
@@ -684,11 +597,11 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
recTicks--; /* guess, but it's only for PIO0, so... */
ebit = 1;
}
- *timings = ((*timings) & ~TR_33_PIO_MASK) |
+ t = (t & ~TR_33_PIO_MASK) |
(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
(recTicks << TR_33_PIO_RECOVERY_SHIFT);
if (ebit)
- *timings |= TR_33_PIO_E;
+ t |= TR_33_PIO_E;
break;
}
}
@@ -698,9 +611,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
drive->name, pio, *timings);
#endif
- if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio))
- return;
-
+ *timings = t;
pmac_ide_do_update_timings(drive);
}
@@ -746,8 +657,6 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
if (speed > XFER_UDMA_5 || t == NULL)
return 1;
tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
- if (tr == 0)
- return 1;
*ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
*ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
@@ -766,8 +675,6 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
if (speed > XFER_UDMA_6 || t == NULL)
return 1;
tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
- if (tr == 0)
- return 1;
*ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
*ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
@@ -777,12 +684,13 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
/*
* Calculate MDMA timings for all cells
*/
-static int
+static void
set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
- u8 speed, int drive_cycle_time)
+ u8 speed)
{
int cycleTime, accessTime = 0, recTime = 0;
unsigned accessTicks, recTicks;
+ struct hd_driveid *id = drive->id;
struct mdma_timings_t* tm = NULL;
int i;
@@ -792,11 +700,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case 1: cycleTime = 150; break;
case 2: cycleTime = 120; break;
default:
- return 1;
+ BUG();
+ break;
}
- /* Adjust for drive */
- if (drive_cycle_time && drive_cycle_time > cycleTime)
- cycleTime = drive_cycle_time;
+
+ /* Check if drive provides explicit DMA cycle time */
+ if ((id->field_valid & 2) && id->eide_dma_time)
+ cycleTime = max_t(int, id->eide_dma_time, cycleTime);
+
/* OHare limits according to some old Apple sources */
if ((intf_type == controller_ohare) && (cycleTime < 150))
cycleTime = 150;
@@ -824,8 +735,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
break;
i++;
}
- if (i < 0)
- return 1;
cycleTime = tm[i].cycleTime;
accessTime = tm[i].accessTime;
recTime = tm[i].recoveryTime;
@@ -839,8 +748,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case controller_sh_ata6: {
/* 133Mhz cell */
u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
- if (tr == 0)
- return 1;
*timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
*timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
}
@@ -848,8 +755,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case controller_k2_ata6: {
/* 100Mhz cell */
u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
- if (tr == 0)
- return 1;
*timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
*timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
}
@@ -911,30 +816,23 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
drive->name, speed & 0xf, *timings);
#endif
- return 0;
}
#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-/*
- * Speedproc. This function is called by the core to set any of the standard
- * DMA timing (MDMA or UDMA) to both the drive and the controller.
- * You may notice we don't use this function on normal "dma check" operation,
- * our dedicated function is more precise as it uses the drive provided
- * cycle time value. We should probably fix this one to deal with that too...
- */
-static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
int unit = (drive->select.b.unit & 0x01);
int ret = 0;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
- u32 *timings, *timings2;
+ u32 *timings, *timings2, tl[2];
- if (pmif == NULL)
- return 1;
-
timings = &pmif->timings[unit];
timings2 = &pmif->timings[unit+2];
-
+
+ /* Copy timings to local image */
+ tl[0] = *timings;
+ tl[1] = *timings2;
+
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
case XFER_UDMA_6:
@@ -945,38 +843,36 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
case XFER_UDMA_1:
case XFER_UDMA_0:
if (pmif->kind == controller_kl_ata4)
- ret = set_timings_udma_ata4(timings, speed);
+ ret = set_timings_udma_ata4(&tl[0], speed);
else if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6)
- ret = set_timings_udma_ata6(timings, timings2, speed);
+ ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
else if (pmif->kind == controller_sh_ata6)
- ret = set_timings_udma_shasta(timings, timings2, speed);
+ ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
else
- ret = 1;
+ ret = 1;
break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
- ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0);
+ set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
break;
case XFER_SW_DMA_2:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- return 1;
+ return;
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
default:
ret = 1;
}
if (ret)
- return ret;
+ return;
- ret = pmac_ide_do_setfeature(drive, speed);
- if (ret)
- return ret;
-
- pmac_ide_do_update_timings(drive);
+ /* Apply timings to controller */
+ *timings = tl[0];
+ *timings2 = tl[1];
- return 0;
+ pmac_ide_do_update_timings(drive);
}
/*
@@ -1236,6 +1132,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
+ hwif->drives[0].autotune = IDE_TUNE_AUTO;
+ hwif->drives[1].autotune = IDE_TUNE_AUTO;
+ hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+ IDE_HFLAG_POST_SET_MODE;
hwif->pio_mask = ATA_PIO4;
hwif->set_pio_mode = pmac_ide_set_pio_mode;
if (pmif->kind == controller_un_ata6
@@ -1244,7 +1144,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->selectproc = pmac_ide_kauai_selectproc;
else
hwif->selectproc = pmac_ide_selectproc;
- hwif->speedproc = pmac_ide_tune_chipset;
+ hwif->set_dma_mode = pmac_ide_set_dma_mode;
printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
@@ -1679,138 +1579,16 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive)
}
/*
- * Pick up best MDMA timing for the drive and apply it
- */
-static int
-pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
-{
- ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
- int drive_cycle_time;
- struct hd_driveid *id = drive->id;
- u32 *timings, *timings2;
- u32 timing_local[2];
- int ret;
-
- /* which drive is it ? */
- timings = &pmif->timings[drive->select.b.unit & 0x01];
- timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
- /* Check if drive provide explicit cycle time */
- if ((id->field_valid & 2) && (id->eide_dma_time))
- drive_cycle_time = id->eide_dma_time;
- else
- drive_cycle_time = 0;
-
- /* Copy timings to local image */
- timing_local[0] = *timings;
- timing_local[1] = *timings2;
-
- /* Calculate controller timings */
- ret = set_timings_mdma( drive, pmif->kind,
- &timing_local[0],
- &timing_local[1],
- mode,
- drive_cycle_time);
- if (ret)
- return 0;
-
- /* Set feature on drive */
- printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf);
- ret = pmac_ide_do_setfeature(drive, mode);
- if (ret) {
- printk(KERN_WARNING "%s: Failed !\n", drive->name);
- return 0;
- }
-
- /* Apply timings to controller */
- *timings = timing_local[0];
- *timings2 = timing_local[1];
-
- return 1;
-}
-
-/*
- * Pick up best UDMA timing for the drive and apply it
- */
-static int
-pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
-{
- ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
- u32 *timings, *timings2;
- u32 timing_local[2];
- int ret;
-
- /* which drive is it ? */
- timings = &pmif->timings[drive->select.b.unit & 0x01];
- timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
- /* Copy timings to local image */
- timing_local[0] = *timings;
- timing_local[1] = *timings2;
-
- /* Calculate timings for interface */
- if (pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6)
- ret = set_timings_udma_ata6( &timing_local[0],
- &timing_local[1],
- mode);
- else if (pmif->kind == controller_sh_ata6)
- ret = set_timings_udma_shasta( &timing_local[0],
- &timing_local[1],
- mode);
- else
- ret = set_timings_udma_ata4(&timing_local[0], mode);
- if (ret)
- return 0;
-
- /* Set feature on drive */
- printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f);
- ret = pmac_ide_do_setfeature(drive, mode);
- if (ret) {
- printk(KERN_WARNING "%s: Failed !\n", drive->name);
- return 0;
- }
-
- /* Apply timings to controller */
- *timings = timing_local[0];
- *timings2 = timing_local[1];
-
- return 1;
-}
-
-/*
* Check what is the best DMA timing setting for the drive and
* call appropriate functions to apply it.
*/
static int
pmac_ide_dma_check(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- int enable = 1;
- drive->using_dma = 0;
-
- if (drive->media == ide_floppy)
- enable = 0;
- if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive))
- enable = 0;
- if (__ide_dma_bad_drive(drive))
- enable = 0;
-
- if (enable) {
- u8 mode = ide_max_dma_mode(drive);
-
- if (mode >= XFER_UDMA_0)
- drive->using_dma = pmac_ide_udma_enable(drive, mode);
- else if (mode >= XFER_MW_DMA_0)
- drive->using_dma = pmac_ide_mdma_enable(drive, mode);
- hwif->OUTB(0, IDE_CONTROL_REG);
- /* Apply settings to controller */
- pmac_ide_do_update_timings(drive);
- }
- return 0;
+ if (ide_tune_dma(drive))
+ return 0;
+
+ return -1;
}
/*
@@ -2044,7 +1822,10 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x00;
break;
- }
+ }
+
+ hwif->autodma = 1;
+ hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma;
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 2ffd53461db..1939fee616e 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -153,8 +153,7 @@ struct host_info {
};
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
static void nodemgr_resume_ne(struct node_entry *ne);
static void nodemgr_remove_ne(struct node_entry *ne);
static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
#ifdef CONFIG_HOTPLUG
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct unit_directory *ud;
- int i = 0;
- int length = 0;
int retval = 0;
/* ieee1394:venNmoNspNverN */
char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
#define PUT_ENVP(fmt,val) \
do { \
- retval = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &length, \
- fmt, val); \
+ retval = add_uevent_var(env, fmt, val); \
if (retval) \
return retval; \
} while (0)
@@ -1201,15 +1195,12 @@ do { \
#undef PUT_ENVP
- envp[i] = NULL;
-
return 0;
}
#else
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 70b77ae6742..3d405068132 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev)
kfree(dev);
}
-static int ib_device_uevent(struct class_device *cdev, char **envp,
- int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+ struct kobj_uevent_env *env)
{
struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
- "NAME=%s", dev->name))
+ if (add_uevent_var(env, "NAME=%s", dev->name))
return -ENOMEM;
/*
* It would be nice to pass the node GUID with the event...
*/
- envp[i] = NULL;
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 6545fa798b1..1b3327ad6bc 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -349,6 +349,7 @@ struct ipoib_neigh {
struct sk_buff_head queue;
struct neighbour *neighbour;
+ struct net_device *dev;
struct list_head list;
};
@@ -365,7 +366,8 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
INFINIBAND_ALEN, sizeof(void *));
}
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh);
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh,
+ struct net_device *dev);
void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh);
extern struct workqueue_struct *ipoib_workqueue;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index e072f3c32ce..362610d870e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
struct ipoib_path *path;
struct ipoib_neigh *neigh;
- neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+ neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
if (!neigh) {
++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
@@ -692,9 +692,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
}
} else if (neigh->ah) {
- if (unlikely(memcmp(&neigh->dgid.raw,
+ if (unlikely((memcmp(&neigh->dgid.raw,
skb->dst->neighbour->ha + 4,
- sizeof(union ib_gid)))) {
+ sizeof(union ib_gid))) ||
+ (neigh->dev != dev))) {
spin_lock(&priv->lock);
/*
* It's safe to call ipoib_put_ah() inside
@@ -817,6 +818,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
unsigned long flags;
struct ipoib_ah *ah = NULL;
+ neigh = *to_ipoib_neigh(n);
+ if (neigh) {
+ priv = netdev_priv(neigh->dev);
+ ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
+ n->dev->name);
+ } else
+ return;
ipoib_dbg(priv,
"neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
IPOIB_QPN(n->ha),
@@ -824,13 +832,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
spin_lock_irqsave(&priv->lock, flags);
- neigh = *to_ipoib_neigh(n);
- if (neigh) {
- if (neigh->ah)
- ah = neigh->ah;
- list_del(&neigh->list);
- ipoib_neigh_free(n->dev, neigh);
- }
+ if (neigh->ah)
+ ah = neigh->ah;
+ list_del(&neigh->list);
+ ipoib_neigh_free(n->dev, neigh);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -838,7 +843,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
ipoib_put_ah(ah);
}
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour,
+ struct net_device *dev)
{
struct ipoib_neigh *neigh;
@@ -847,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
return NULL;
neigh->neighbour = neighbour;
+ neigh->dev = dev;
*to_ipoib_neigh(neighbour) = neigh;
skb_queue_head_init(&neigh->queue);
ipoib_cm_set(neigh, NULL);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 827820ec66d..9bcfc7ad6aa 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -705,7 +705,8 @@ out:
if (skb->dst &&
skb->dst->neighbour &&
!*to_ipoib_neigh(skb->dst->neighbour)) {
- struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+ struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+ skb->dev);
if (neigh) {
kref_get(&mcast->ah->ref);
diff --git a/drivers/infiniband/ulp/srp/Kconfig b/drivers/infiniband/ulp/srp/Kconfig
index 3432dce2952..c74ee963304 100644
--- a/drivers/infiniband/ulp/srp/Kconfig
+++ b/drivers/infiniband/ulp/srp/Kconfig
@@ -1,6 +1,7 @@
config INFINIBAND_SRP
tristate "InfiniBand SCSI RDMA Protocol"
depends on SCSI
+ select SCSI_SRP_ATTRS
---help---
Support for the SCSI RDMA Protocol over InfiniBand. This
allows you to access storage devices that speak SRP over
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 9ccc63886d9..950228fb009 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -47,6 +47,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_dbg.h>
#include <scsi/srp.h>
+#include <scsi/scsi_transport_srp.h>
#include <rdma/ib_cache.h>
@@ -86,6 +87,8 @@ static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
+static struct scsi_transport_template *ib_srp_transport_template;
+
static struct ib_client srp_client = {
.name = "srp",
.add = srp_add_one,
@@ -420,6 +423,7 @@ static void srp_remove_work(struct work_struct *work)
list_del(&target->list);
spin_unlock(&target->srp_host->target_lock);
+ srp_remove_host(target->scsi_host);
scsi_remove_host(target->scsi_host);
ib_destroy_cm_id(target->cm_id);
srp_free_target_ib(target);
@@ -1544,12 +1548,24 @@ static struct scsi_host_template srp_template = {
static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
{
+ struct srp_rport_identifiers ids;
+ struct srp_rport *rport;
+
sprintf(target->target_name, "SRP.T10:%016llX",
(unsigned long long) be64_to_cpu(target->id_ext));
if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device))
return -ENODEV;
+ memcpy(ids.port_id, &target->id_ext, 8);
+ memcpy(ids.port_id + 8, &target->ioc_guid, 8);
+ ids.roles = SRP_RPORT_ROLE_TARGET;
+ rport = srp_rport_add(target->scsi_host, &ids);
+ if (IS_ERR(rport)) {
+ scsi_remove_host(target->scsi_host);
+ return PTR_ERR(rport);
+ }
+
spin_lock(&host->target_lock);
list_add_tail(&target->list, &host->target_list);
spin_unlock(&host->target_lock);
@@ -1775,6 +1791,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
if (!target_host)
return -ENOMEM;
+ target_host->transportt = ib_srp_transport_template;
target_host->max_lun = SRP_MAX_LUN;
target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
@@ -2054,10 +2071,18 @@ static void srp_remove_one(struct ib_device *device)
kfree(srp_dev);
}
+static struct srp_function_template ib_srp_transport_functions = {
+};
+
static int __init srp_init_module(void)
{
int ret;
+ ib_srp_transport_template =
+ srp_attach_transport(&ib_srp_transport_functions);
+ if (!ib_srp_transport_template)
+ return -ENOMEM;
+
srp_template.sg_tablesize = srp_sg_tablesize;
srp_max_iu_len = (sizeof (struct srp_cmd) +
sizeof (struct srp_indirect_buf) +
@@ -2066,6 +2091,7 @@ static int __init srp_init_module(void)
ret = class_register(&srp_class);
if (ret) {
printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
+ srp_release_transport(ib_srp_transport_template);
return ret;
}
@@ -2074,6 +2100,7 @@ static int __init srp_init_module(void)
ret = ib_register_client(&srp_client);
if (ret) {
printk(KERN_ERR PFX "couldn't register IB client\n");
+ srp_release_transport(ib_srp_transport_template);
ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
return ret;
@@ -2087,6 +2114,7 @@ static void __exit srp_cleanup_module(void)
ib_unregister_client(&srp_client);
ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
+ srp_release_transport(ib_srp_transport_template);
}
module_init(srp_init_module);
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 2d87357e2b2..63512d906f0 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -114,28 +114,6 @@ config INPUT_JOYDEV
To compile this driver as a module, choose M here: the
module will be called joydev.
-config INPUT_TSDEV
- tristate "Touchscreen interface"
- ---help---
- Say Y here if you have an application that only can understand the
- Compaq touchscreen protocol for absolute pointer data. This is
- useful namely for embedded configurations.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called tsdev.
-
-config INPUT_TSDEV_SCREEN_X
- int "Horizontal screen resolution"
- depends on INPUT_TSDEV
- default "240"
-
-config INPUT_TSDEV_SCREEN_Y
- int "Vertical screen resolution"
- depends on INPUT_TSDEV
- default "320"
-
config INPUT_EVDEV
tristate "Event interface"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 15eb752697b..99af903bd3c 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f1c3d6cebd5..1d62c8b88e1 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -30,6 +30,8 @@ struct evdev {
wait_queue_head_t wait;
struct evdev_client *grab;
struct list_head client_list;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
};
@@ -37,39 +39,54 @@ struct evdev_client {
struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
+ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
};
static struct evdev *evdev_table[EVDEV_MINORS];
+static DEFINE_MUTEX(evdev_table_mutex);
-static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void evdev_pass_event(struct evdev_client *client,
+ struct input_event *event)
+{
+ /*
+ * Interrupts are disabled, just acquire the lock
+ */
+ spin_lock(&client->buffer_lock);
+ client->buffer[client->head++] = *event;
+ client->head &= EVDEV_BUFFER_SIZE - 1;
+ spin_unlock(&client->buffer_lock);
+
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+}
+
+/*
+ * Pass incoming event to all connected clients.
+ */
+static void evdev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
+ struct input_event event;
- if (evdev->grab) {
- client = evdev->grab;
+ do_gettimeofday(&event.time);
+ event.type = type;
+ event.code = code;
+ event.value = value;
- do_gettimeofday(&client->buffer[client->head].time);
- client->buffer[client->head].type = type;
- client->buffer[client->head].code = code;
- client->buffer[client->head].value = value;
- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+ rcu_read_lock();
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- } else
- list_for_each_entry(client, &evdev->client_list, node) {
+ client = rcu_dereference(evdev->grab);
+ if (client)
+ evdev_pass_event(client, &event);
+ else
+ list_for_each_entry_rcu(client, &evdev->client_list, node)
+ evdev_pass_event(client, &event);
- do_gettimeofday(&client->buffer[client->head].time);
- client->buffer[client->head].type = type;
- client->buffer[client->head].code = code;
- client->buffer[client->head].value = value;
- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
-
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
+ rcu_read_unlock();
wake_up_interruptible(&evdev->wait);
}
@@ -88,38 +105,140 @@ static int evdev_flush(struct file *file, fl_owner_t id)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
if (!evdev->exist)
- return -ENODEV;
+ retval = -ENODEV;
+ else
+ retval = input_flush_device(&evdev->handle, file);
- return input_flush_device(&evdev->handle, file);
+ mutex_unlock(&evdev->mutex);
+ return retval;
}
static void evdev_free(struct device *dev)
{
struct evdev *evdev = container_of(dev, struct evdev, dev);
- evdev_table[evdev->minor] = NULL;
kfree(evdev);
}
+/*
+ * Grabs an event device (along with underlying input device).
+ * This function is called with evdev->mutex taken.
+ */
+static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
+{
+ int error;
+
+ if (evdev->grab)
+ return -EBUSY;
+
+ error = input_grab_device(&evdev->handle);
+ if (error)
+ return error;
+
+ rcu_assign_pointer(evdev->grab, client);
+ synchronize_rcu();
+
+ return 0;
+}
+
+static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
+{
+ if (evdev->grab != client)
+ return -EINVAL;
+
+ rcu_assign_pointer(evdev->grab, NULL);
+ synchronize_rcu();
+ input_release_device(&evdev->handle);
+
+ return 0;
+}
+
+static void evdev_attach_client(struct evdev *evdev,
+ struct evdev_client *client)
+{
+ spin_lock(&evdev->client_lock);
+ list_add_tail_rcu(&client->node, &evdev->client_list);
+ spin_unlock(&evdev->client_lock);
+ synchronize_rcu();
+}
+
+static void evdev_detach_client(struct evdev *evdev,
+ struct evdev_client *client)
+{
+ spin_lock(&evdev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&evdev->client_lock);
+ synchronize_rcu();
+}
+
+static int evdev_open_device(struct evdev *evdev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist)
+ retval = -ENODEV;
+ else if (!evdev->open++) {
+ retval = input_open_device(&evdev->handle);
+ if (retval)
+ evdev->open--;
+ }
+
+ mutex_unlock(&evdev->mutex);
+ return retval;
+}
+
+static void evdev_close_device(struct evdev *evdev)
+{
+ mutex_lock(&evdev->mutex);
+
+ if (evdev->exist && !--evdev->open)
+ input_close_device(&evdev->handle);
+
+ mutex_unlock(&evdev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void evdev_hangup(struct evdev *evdev)
+{
+ struct evdev_client *client;
+
+ spin_lock(&evdev->client_lock);
+ list_for_each_entry(client, &evdev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&evdev->client_lock);
+
+ wake_up_interruptible(&evdev->wait);
+}
+
static int evdev_release(struct inode *inode, struct file *file)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
- if (evdev->grab == client) {
- input_release_device(&evdev->handle);
- evdev->grab = NULL;
- }
+ mutex_lock(&evdev->mutex);
+ if (evdev->grab == client)
+ evdev_ungrab(evdev, client);
+ mutex_unlock(&evdev->mutex);
evdev_fasync(-1, file, 0);
- list_del(&client->node);
+ evdev_detach_client(evdev, client);
kfree(client);
- if (!--evdev->open && evdev->exist)
- input_close_device(&evdev->handle);
-
+ evdev_close_device(evdev);
put_device(&evdev->dev);
return 0;
@@ -127,41 +246,44 @@ static int evdev_release(struct inode *inode, struct file *file)
static int evdev_open(struct inode *inode, struct file *file)
{
- struct evdev_client *client;
struct evdev *evdev;
+ struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&evdev_table_mutex);
+ if (error)
+ return error;
evdev = evdev_table[i];
+ if (evdev)
+ get_device(&evdev->dev);
+ mutex_unlock(&evdev_table_mutex);
- if (!evdev || !evdev->exist)
+ if (!evdev)
return -ENODEV;
- get_device(&evdev->dev);
-
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
+ spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
- list_add_tail(&client->node, &evdev->client_list);
+ evdev_attach_client(evdev, client);
- if (!evdev->open++ && evdev->exist) {
- error = input_open_device(&evdev->handle);
- if (error)
- goto err_free_client;
- }
+ error = evdev_open_device(evdev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
@@ -197,12 +319,14 @@ static inline size_t evdev_event_size(void)
sizeof(struct input_event_compat) : sizeof(struct input_event);
}
-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+static int evdev_event_from_user(const char __user *buffer,
+ struct input_event *event)
{
if (COMPAT_TEST) {
struct input_event_compat compat_event;
- if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
+ if (copy_from_user(&compat_event, buffer,
+ sizeof(struct input_event_compat)))
return -EFAULT;
event->time.tv_sec = compat_event.time.tv_sec;
@@ -219,7 +343,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event *
return 0;
}
-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+static int evdev_event_to_user(char __user *buffer,
+ const struct input_event *event)
{
if (COMPAT_TEST) {
struct input_event_compat compat_event;
@@ -230,7 +355,8 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
compat_event.code = event->code;
compat_event.value = event->value;
- if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
+ if (copy_to_user(buffer, &compat_event,
+ sizeof(struct input_event_compat)))
return -EFAULT;
} else {
@@ -248,7 +374,8 @@ static inline size_t evdev_event_size(void)
return sizeof(struct input_event);
}
-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+static int evdev_event_from_user(const char __user *buffer,
+ struct input_event *event)
{
if (copy_from_user(event, buffer, sizeof(struct input_event)))
return -EFAULT;
@@ -256,7 +383,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event *
return 0;
}
-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+static int evdev_event_to_user(char __user *buffer,
+ const struct input_event *event)
{
if (copy_to_user(buffer, event, sizeof(struct input_event)))
return -EFAULT;
@@ -266,37 +394,71 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
#endif /* CONFIG_COMPAT */
-static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
- int retval = 0;
+ int retval;
- if (!evdev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
while (retval < count) {
- if (evdev_event_from_user(buffer + retval, &event))
- return -EFAULT;
- input_inject_event(&evdev->handle, event.type, event.code, event.value);
+ if (evdev_event_from_user(buffer + retval, &event)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ input_inject_event(&evdev->handle,
+ event.type, event.code, event.value);
retval += evdev_event_size();
}
+ out:
+ mutex_unlock(&evdev->mutex);
return retval;
}
-static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+static int evdev_fetch_next_event(struct evdev_client *client,
+ struct input_event *event)
+{
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->head != client->tail;
+ if (have_event) {
+ *event = client->buffer[client->tail++];
+ client->tail &= EVDEV_BUFFER_SIZE - 1;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+static ssize_t evdev_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
+ struct input_event event;
int retval;
if (count < evdev_event_size())
return -EINVAL;
- if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
+ if (client->head == client->tail && evdev->exist &&
+ (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
@@ -307,14 +469,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count,
if (!evdev->exist)
return -ENODEV;
- while (client->head != client->tail && retval + evdev_event_size() <= count) {
-
- struct input_event *event = (struct input_event *) client->buffer + client->tail;
+ while (retval + evdev_event_size() <= count &&
+ evdev_fetch_next_event(client, &event)) {
- if (evdev_event_to_user(buffer + retval, event))
+ if (evdev_event_to_user(buffer + retval, &event))
return -EFAULT;
- client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += evdev_event_size();
}
@@ -409,8 +569,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
return copy_to_user(p, str, len) ? -EFAULT : len;
}
-static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
- void __user *p, int compat_mode)
+static long evdev_do_ioctl(struct file *file, unsigned int cmd,
+ void __user *p, int compat_mode)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
@@ -421,215 +581,289 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
int i, t, u, v;
int error;
- if (!evdev->exist)
- return -ENODEV;
-
switch (cmd) {
- case EVIOCGVERSION:
- return put_user(EV_VERSION, ip);
+ case EVIOCGVERSION:
+ return put_user(EV_VERSION, ip);
- case EVIOCGID:
- if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
- return -EFAULT;
- return 0;
+ case EVIOCGID:
+ if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+ return -EFAULT;
+ return 0;
- case EVIOCGREP:
- if (!test_bit(EV_REP, dev->evbit))
- return -ENOSYS;
- if (put_user(dev->rep[REP_DELAY], ip))
- return -EFAULT;
- if (put_user(dev->rep[REP_PERIOD], ip + 1))
- return -EFAULT;
- return 0;
+ case EVIOCGREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (put_user(dev->rep[REP_DELAY], ip))
+ return -EFAULT;
+ if (put_user(dev->rep[REP_PERIOD], ip + 1))
+ return -EFAULT;
+ return 0;
- case EVIOCSREP:
- if (!test_bit(EV_REP, dev->evbit))
- return -ENOSYS;
- if (get_user(u, ip))
- return -EFAULT;
- if (get_user(v, ip + 1))
- return -EFAULT;
+ case EVIOCSREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (get_user(u, ip))
+ return -EFAULT;
+ if (get_user(v, ip + 1))
+ return -EFAULT;
- input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
- input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
+ input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+ input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
- return 0;
+ return 0;
- case EVIOCGKEYCODE:
- if (get_user(t, ip))
- return -EFAULT;
+ case EVIOCGKEYCODE:
+ if (get_user(t, ip))
+ return -EFAULT;
- error = dev->getkeycode(dev, t, &v);
- if (error)
- return error;
+ error = dev->getkeycode(dev, t, &v);
+ if (error)
+ return error;
- if (put_user(v, ip + 1))
- return -EFAULT;
+ if (put_user(v, ip + 1))
+ return -EFAULT;
- return 0;
+ return 0;
- case EVIOCSKEYCODE:
- if (get_user(t, ip) || get_user(v, ip + 1))
- return -EFAULT;
+ case EVIOCSKEYCODE:
+ if (get_user(t, ip) || get_user(v, ip + 1))
+ return -EFAULT;
- return dev->setkeycode(dev, t, v);
+ return dev->setkeycode(dev, t, v);
- case EVIOCSFF:
- if (copy_from_user(&effect, p, sizeof(effect)))
- return -EFAULT;
+ case EVIOCSFF:
+ if (copy_from_user(&effect, p, sizeof(effect)))
+ return -EFAULT;
- error = input_ff_upload(dev, &effect, file);
+ error = input_ff_upload(dev, &effect, file);
- if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
- return -EFAULT;
+ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+ return -EFAULT;
- return error;
+ return error;
- case EVIOCRMFF:
- return input_ff_erase(dev, (int)(unsigned long) p, file);
+ case EVIOCRMFF:
+ return input_ff_erase(dev, (int)(unsigned long) p, file);
- case EVIOCGEFFECTS:
- i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
- if (put_user(i, ip))
- return -EFAULT;
- return 0;
-
- case EVIOCGRAB:
- if (p) {
- if (evdev->grab)
- return -EBUSY;
- if (input_grab_device(&evdev->handle))
- return -EBUSY;
- evdev->grab = client;
- return 0;
- } else {
- if (evdev->grab != client)
- return -EINVAL;
- input_release_device(&evdev->handle);
- evdev->grab = NULL;
- return 0;
- }
+ case EVIOCGEFFECTS:
+ i = test_bit(EV_FF, dev->evbit) ?
+ dev->ff->max_effects : 0;
+ if (put_user(i, ip))
+ return -EFAULT;
+ return 0;
+
+ case EVIOCGRAB:
+ if (p)
+ return evdev_grab(evdev, client);
+ else
+ return evdev_ungrab(evdev, client);
- default:
+ default:
- if (_IOC_TYPE(cmd) != 'E')
- return -EINVAL;
+ if (_IOC_TYPE(cmd) != 'E')
+ return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_IOC_DIR(cmd) == _IOC_READ) {
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) {
- unsigned long *bits;
- int len;
+ unsigned long *bits;
+ int len;
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
- case EV_SW: bits = dev->swbit; len = SW_MAX; break;
- default: return -EINVAL;
- }
- return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
- }
+ switch (_IOC_NR(cmd) & EV_MAX) {
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
- return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ case EV_SW: bits = dev->swbit; len = SW_MAX; break;
+ default: return -EINVAL;
+ }
+ return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
- return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+ return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
- return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+ return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
- return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+ return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
- return str_to_user(dev->name, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+ return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
- return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+ return str_to_user(dev->name, _IOC_SIZE(cmd), p);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
- return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
+ return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
+ return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
- t = _IOC_NR(cmd) & ABS_MAX;
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
- abs.value = dev->abs[t];
- abs.minimum = dev->absmin[t];
- abs.maximum = dev->absmax[t];
- abs.fuzz = dev->absfuzz[t];
- abs.flat = dev->absflat[t];
+ t = _IOC_NR(cmd) & ABS_MAX;
- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
- return -EFAULT;
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
- return 0;
- }
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+ return 0;
}
- if (_IOC_DIR(cmd) == _IOC_WRITE) {
+ }
+
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- t = _IOC_NR(cmd) & ABS_MAX;
+ t = _IOC_NR(cmd) & ABS_MAX;
- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
- return -EFAULT;
+ if (copy_from_user(&abs, p,
+ sizeof(struct input_absinfo)))
+ return -EFAULT;
- dev->abs[t] = abs.value;
- dev->absmin[t] = abs.minimum;
- dev->absmax[t] = abs.maximum;
- dev->absfuzz[t] = abs.fuzz;
- dev->absflat[t] = abs.flat;
+ /*
+ * Take event lock to ensure that we are not
+ * changing device parameters in the middle
+ * of event.
+ */
+ spin_lock_irq(&dev->event_lock);
- return 0;
- }
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ spin_unlock_irq(&dev->event_lock);
+
+ return 0;
}
+ }
}
return -EINVAL;
}
+static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+ void __user *p, int compat_mode)
+{
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ retval = evdev_do_ioctl(file, cmd, p, compat_mode);
+
+ out:
+ mutex_unlock(&evdev->mutex);
+ return retval;
+}
+
static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
}
#ifdef CONFIG_COMPAT
-static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl_compat(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
}
#endif
static const struct file_operations evdev_fops = {
- .owner = THIS_MODULE,
- .read = evdev_read,
- .write = evdev_write,
- .poll = evdev_poll,
- .open = evdev_open,
- .release = evdev_release,
- .unlocked_ioctl = evdev_ioctl,
+ .owner = THIS_MODULE,
+ .read = evdev_read,
+ .write = evdev_write,
+ .poll = evdev_poll,
+ .open = evdev_open,
+ .release = evdev_release,
+ .unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = evdev_ioctl_compat,
+ .compat_ioctl = evdev_ioctl_compat,
#endif
- .fasync = evdev_fasync,
- .flush = evdev_flush
+ .fasync = evdev_fasync,
+ .flush = evdev_flush
};
+static int evdev_install_chrdev(struct evdev *evdev)
+{
+ /*
+ * No need to do any locking here as calls to connect and
+ * disconnect are serialized by the input core
+ */
+ evdev_table[evdev->minor] = evdev;
+ return 0;
+}
+
+static void evdev_remove_chrdev(struct evdev *evdev)
+{
+ /*
+ * Lock evdev table to prevent race with evdev_open()
+ */
+ mutex_lock(&evdev_table_mutex);
+ evdev_table[evdev->minor] = NULL;
+ mutex_unlock(&evdev_table_mutex);
+}
+
+/*
+ * Mark device non-existent. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void evdev_mark_dead(struct evdev *evdev)
+{
+ mutex_lock(&evdev->mutex);
+ evdev->exist = 0;
+ mutex_unlock(&evdev->mutex);
+}
+
+static void evdev_cleanup(struct evdev *evdev)
+{
+ struct input_handle *handle = &evdev->handle;
+
+ evdev_mark_dead(evdev);
+ evdev_hangup(evdev);
+ evdev_remove_chrdev(evdev);
+
+ /* evdev is marked dead so no one else accesses evdev->open */
+ if (evdev->open) {
+ input_flush_device(handle, NULL);
+ input_close_device(handle);
+ }
+}
+
+/*
+ * Create new evdev device. Note that input core serializes calls
+ * to connect and disconnect so we don't need to lock evdev_table here.
+ */
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
@@ -637,7 +871,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
int minor;
int error;
- for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+ for (minor = 0; minor < EVDEV_MINORS; minor++)
+ if (!evdev_table[minor])
+ break;
+
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
@@ -648,38 +885,44 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
+ spin_lock_init(&evdev->client_lock);
+ mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
+ snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
evdev->exist = 1;
evdev->minor = minor;
+
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
- snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
- snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
- "event%d", minor);
+ strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id));
+ evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
- evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
- evdev_table[minor] = evdev;
-
- error = device_add(&evdev->dev);
+ error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;
- error = input_register_handle(&evdev->handle);
+ error = evdev_install_chrdev(evdev);
+ if (error)
+ goto err_unregister_handle;
+
+ error = device_add(&evdev->dev);
if (error)
- goto err_delete_evdev;
+ goto err_cleanup_evdev;
return 0;
- err_delete_evdev:
- device_del(&evdev->dev);
+ err_cleanup_evdev:
+ evdev_cleanup(evdev);
+ err_unregister_handle:
+ input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
@@ -688,21 +931,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- struct evdev_client *client;
- input_unregister_handle(handle);
device_del(&evdev->dev);
-
- evdev->exist = 0;
-
- if (evdev->open) {
- input_flush_device(handle, NULL);
- input_close_device(handle);
- list_for_each_entry(client, &evdev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&evdev->wait);
- }
-
+ evdev_cleanup(evdev);
+ input_unregister_handle(handle);
put_device(&evdev->dev);
}
@@ -714,13 +946,13 @@ static const struct input_device_id evdev_ids[] = {
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
- .event = evdev_event,
- .connect = evdev_connect,
- .disconnect = evdev_disconnect,
- .fops = &evdev_fops,
- .minor = EVDEV_MINOR_BASE,
- .name = "evdev",
- .id_table = evdev_ids,
+ .event = evdev_event,
+ .connect = evdev_connect,
+ .disconnect = evdev_disconnect,
+ .fops = &evdev_fops,
+ .minor = EVDEV_MINOR_BASE,
+ .name = "evdev",
+ .id_table = evdev_ids,
};
static int __init evdev_init(void)
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index b773d4c756a..92b359894e8 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -70,6 +70,7 @@ static int input_open_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input->private;
int error;
+ unsigned long ticks;
error = input_polldev_start_workqueue();
if (error)
@@ -78,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input)
if (dev->flush)
dev->flush(dev);
- queue_delayed_work(polldev_wq, &dev->work,
- msecs_to_jiffies(dev->poll_interval));
+ ticks = msecs_to_jiffies(dev->poll_interval);
+ if (ticks >= HZ)
+ ticks = round_jiffies(ticks);
+ queue_delayed_work(polldev_wq, &dev->work, ticks);
return 0;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 5fe75558662..2f2b020cd62 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -17,10 +17,10 @@
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/mutex.h>
+#include <linux/rcupdate.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -31,167 +31,245 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
+/*
+ * input_mutex protects access to both input_dev_list and input_handler_list.
+ * This also causes input_[un]register_device and input_[un]register_handler
+ * be mutually exclusive which simplifies locking in drivers implementing
+ * input handlers.
+ */
+static DEFINE_MUTEX(input_mutex);
+
static struct input_handler *input_table[8];
-/**
- * input_event() - report new input event
- * @dev: device that generated the event
- * @type: type of the event
- * @code: event code
- * @value: value of the event
- *
- * This function should be used by drivers implementing various input devices
- * See also input_inject_event()
- */
-void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static inline int is_event_supported(unsigned int code,
+ unsigned long *bm, unsigned int max)
{
- struct input_handle *handle;
-
- if (type > EV_MAX || !test_bit(type, dev->evbit))
- return;
+ return code <= max && test_bit(code, bm);
+}
- add_input_randomness(type, code, value);
+static int input_defuzz_abs_event(int value, int old_val, int fuzz)
+{
+ if (fuzz) {
+ if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
+ return old_val;
- switch (type) {
+ if (value > old_val - fuzz && value < old_val + fuzz)
+ return (old_val * 3 + value) / 4;
- case EV_SYN:
- switch (code) {
- case SYN_CONFIG:
- if (dev->event)
- dev->event(dev, type, code, value);
- break;
-
- case SYN_REPORT:
- if (dev->sync)
- return;
- dev->sync = 1;
- break;
- }
- break;
+ if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
+ return (old_val + value) / 2;
+ }
- case EV_KEY:
+ return value;
+}
- if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
- return;
+/*
+ * Pass event through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ struct input_handle *handle;
- if (value == 2)
- break;
+ rcu_read_lock();
- change_bit(code, dev->key);
+ handle = rcu_dereference(dev->grab);
+ if (handle)
+ handle->handler->event(handle, type, code, value);
+ else
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+ if (handle->open)
+ handle->handler->event(handle,
+ type, code, value);
+ rcu_read_unlock();
+}
- if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
- dev->repeat_key = code;
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
- }
+/*
+ * Generate software autorepeat event. Note that we take
+ * dev->event_lock here to avoid racing with input_event
+ * which may cause keys get "stuck".
+ */
+static void input_repeat_key(unsigned long data)
+{
+ struct input_dev *dev = (void *) data;
+ unsigned long flags;
- break;
+ spin_lock_irqsave(&dev->event_lock, flags);
- case EV_SW:
+ if (test_bit(dev->repeat_key, dev->key) &&
+ is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
- if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
- return;
+ input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
- change_bit(code, dev->sw);
+ if (dev->sync) {
+ /*
+ * Only send SYN_REPORT if we are not in a middle
+ * of driver parsing a new hardware packet.
+ * Otherwise assume that the driver will send
+ * SYN_REPORT once it's done.
+ */
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
- break;
+ if (dev->rep[REP_PERIOD])
+ mod_timer(&dev->timer, jiffies +
+ msecs_to_jiffies(dev->rep[REP_PERIOD]));
+ }
- case EV_ABS:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
- if (code > ABS_MAX || !test_bit(code, dev->absbit))
- return;
+static void input_start_autorepeat(struct input_dev *dev, int code)
+{
+ if (test_bit(EV_REP, dev->evbit) &&
+ dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
+ dev->timer.data) {
+ dev->repeat_key = code;
+ mod_timer(&dev->timer,
+ jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+ }
+}
- if (dev->absfuzz[code]) {
- if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
- return;
+#define INPUT_IGNORE_EVENT 0
+#define INPUT_PASS_TO_HANDLERS 1
+#define INPUT_PASS_TO_DEVICE 2
+#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
- if ((value > dev->abs[code] - dev->absfuzz[code]) &&
- (value < dev->abs[code] + dev->absfuzz[code]))
- value = (dev->abs[code] * 3 + value) >> 2;
+static void input_handle_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ int disposition = INPUT_IGNORE_EVENT;
- if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
- value = (dev->abs[code] + value) >> 1;
- }
+ switch (type) {
- if (dev->abs[code] == value)
- return;
+ case EV_SYN:
+ switch (code) {
+ case SYN_CONFIG:
+ disposition = INPUT_PASS_TO_ALL;
+ break;
- dev->abs[code] = value;
+ case SYN_REPORT:
+ if (!dev->sync) {
+ dev->sync = 1;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
break;
+ }
+ break;
- case EV_REL:
+ case EV_KEY:
+ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+ !!test_bit(code, dev->key) != value) {
- if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
- return;
+ if (value != 2) {
+ __change_bit(code, dev->key);
+ if (value)
+ input_start_autorepeat(dev, code);
+ }
- break;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ break;
- case EV_MSC:
+ case EV_SW:
+ if (is_event_supported(code, dev->swbit, SW_MAX) &&
+ !!test_bit(code, dev->sw) != value) {
- if (code > MSC_MAX || !test_bit(code, dev->mscbit))
- return;
+ __change_bit(code, dev->sw);
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ break;
+
+ case EV_ABS:
+ if (is_event_supported(code, dev->absbit, ABS_MAX)) {
- if (dev->event)
- dev->event(dev, type, code, value);
+ value = input_defuzz_abs_event(value,
+ dev->abs[code], dev->absfuzz[code]);
- break;
+ if (dev->abs[code] != value) {
+ dev->abs[code] = value;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ }
+ break;
- case EV_LED:
+ case EV_REL:
+ if (is_event_supported(code, dev->relbit, REL_MAX) && value)
+ disposition = INPUT_PASS_TO_HANDLERS;
- if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
- return;
+ break;
- change_bit(code, dev->led);
+ case EV_MSC:
+ if (is_event_supported(code, dev->mscbit, MSC_MAX))
+ disposition = INPUT_PASS_TO_ALL;
- if (dev->event)
- dev->event(dev, type, code, value);
+ break;
- break;
+ case EV_LED:
+ if (is_event_supported(code, dev->ledbit, LED_MAX) &&
+ !!test_bit(code, dev->led) != value) {
- case EV_SND:
+ __change_bit(code, dev->led);
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- if (code > SND_MAX || !test_bit(code, dev->sndbit))
- return;
+ case EV_SND:
+ if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
- change_bit(code, dev->snd);
+ __change_bit(code, dev->snd);
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- if (dev->event)
- dev->event(dev, type, code, value);
+ case EV_REP:
+ if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
+ dev->rep[code] = value;
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- break;
+ case EV_FF:
+ if (value >= 0)
+ disposition = INPUT_PASS_TO_ALL;
+ break;
+ }
- case EV_REP:
+ if (type != EV_SYN)
+ dev->sync = 0;
- if (code > REP_MAX || value < 0 || dev->rep[code] == value)
- return;
+ if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
+ dev->event(dev, type, code, value);
- dev->rep[code] = value;
- if (dev->event)
- dev->event(dev, type, code, value);
+ if (disposition & INPUT_PASS_TO_HANDLERS)
+ input_pass_event(dev, type, code, value);
+}
- break;
+/**
+ * input_event() - report new input event
+ * @dev: device that generated the event
+ * @type: type of the event
+ * @code: event code
+ * @value: value of the event
+ *
+ * This function should be used by drivers implementing various input
+ * devices. See also input_inject_event().
+ */
- case EV_FF:
+void input_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ unsigned long flags;
- if (value < 0)
- return;
+ if (is_event_supported(type, dev->evbit, EV_MAX)) {
- if (dev->event)
- dev->event(dev, type, code, value);
- break;
+ spin_lock_irqsave(&dev->event_lock, flags);
+ add_input_randomness(type, code, value);
+ input_handle_event(dev, type, code, value);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
-
- if (type != EV_SYN)
- dev->sync = 0;
-
- if (dev->grab)
- dev->grab->handler->event(dev->grab, type, code, value);
- else
- list_for_each_entry(handle, &dev->h_list, d_node)
- if (handle->open)
- handle->handler->event(handle, type, code, value);
}
EXPORT_SYMBOL(input_event);
@@ -202,102 +280,228 @@ EXPORT_SYMBOL(input_event);
* @code: event code
* @value: value of the event
*
- * Similar to input_event() but will ignore event if device is "grabbed" and handle
- * injecting event is not the one that owns the device.
+ * Similar to input_event() but will ignore event if device is
+ * "grabbed" and handle injecting event is not the one that owns
+ * the device.
*/
-void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+void input_inject_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
- if (!handle->dev->grab || handle->dev->grab == handle)
- input_event(handle->dev, type, code, value);
-}
-EXPORT_SYMBOL(input_inject_event);
-
-static void input_repeat_key(unsigned long data)
-{
- struct input_dev *dev = (void *) data;
+ struct input_dev *dev = handle->dev;
+ struct input_handle *grab;
+ unsigned long flags;
- if (!test_bit(dev->repeat_key, dev->key))
- return;
+ if (is_event_supported(type, dev->evbit, EV_MAX)) {
+ spin_lock_irqsave(&dev->event_lock, flags);
- input_event(dev, EV_KEY, dev->repeat_key, 2);
- input_sync(dev);
+ rcu_read_lock();
+ grab = rcu_dereference(dev->grab);
+ if (!grab || grab == handle)
+ input_handle_event(dev, type, code, value);
+ rcu_read_unlock();
- if (dev->rep[REP_PERIOD])
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
}
+EXPORT_SYMBOL(input_inject_event);
+/**
+ * input_grab_device - grabs device for exclusive use
+ * @handle: input handle that wants to own the device
+ *
+ * When a device is grabbed by an input handle all events generated by
+ * the device are delivered only to this handle. Also events injected
+ * by other input handles are ignored while device is grabbed.
+ */
int input_grab_device(struct input_handle *handle)
{
- if (handle->dev->grab)
- return -EBUSY;
+ struct input_dev *dev = handle->dev;
+ int retval;
- handle->dev->grab = handle;
- return 0;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->grab) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ rcu_assign_pointer(dev->grab, handle);
+ synchronize_rcu();
+
+ out:
+ mutex_unlock(&dev->mutex);
+ return retval;
}
EXPORT_SYMBOL(input_grab_device);
-void input_release_device(struct input_handle *handle)
+static void __input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
if (dev->grab == handle) {
- dev->grab = NULL;
+ rcu_assign_pointer(dev->grab, NULL);
+ /* Make sure input_pass_event() notices that grab is gone */
+ synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node)
- if (handle->handler->start)
+ if (handle->open && handle->handler->start)
handle->handler->start(handle);
}
}
+
+/**
+ * input_release_device - release previously grabbed device
+ * @handle: input handle that owns the device
+ *
+ * Releases previously grabbed device so that other input handles can
+ * start receiving input events. Upon release all handlers attached
+ * to the device have their start() method called so they have a change
+ * to synchronize device state with the rest of the system.
+ */
+void input_release_device(struct input_handle *handle)
+{
+ struct input_dev *dev = handle->dev;
+
+ mutex_lock(&dev->mutex);
+ __input_release_device(handle);
+ mutex_unlock(&dev->mutex);
+}
EXPORT_SYMBOL(input_release_device);
+/**
+ * input_open_device - open input device
+ * @handle: handle through which device is being accessed
+ *
+ * This function should be called by input handlers when they
+ * want to start receive events from given input device.
+ */
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int err;
+ int retval;
- err = mutex_lock_interruptible(&dev->mutex);
- if (err)
- return err;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->going_away) {
+ retval = -ENODEV;
+ goto out;
+ }
handle->open++;
if (!dev->users++ && dev->open)
- err = dev->open(dev);
-
- if (err)
- handle->open--;
+ retval = dev->open(dev);
+
+ if (retval) {
+ dev->users--;
+ if (!--handle->open) {
+ /*
+ * Make sure we are not delivering any more events
+ * through this handle
+ */
+ synchronize_rcu();
+ }
+ }
+ out:
mutex_unlock(&dev->mutex);
-
- return err;
+ return retval;
}
EXPORT_SYMBOL(input_open_device);
-int input_flush_device(struct input_handle* handle, struct file* file)
+int input_flush_device(struct input_handle *handle, struct file *file)
{
- if (handle->dev->flush)
- return handle->dev->flush(handle->dev, file);
+ struct input_dev *dev = handle->dev;
+ int retval;
- return 0;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->flush)
+ retval = dev->flush(dev, file);
+
+ mutex_unlock(&dev->mutex);
+ return retval;
}
EXPORT_SYMBOL(input_flush_device);
+/**
+ * input_close_device - close input device
+ * @handle: handle through which device is being accessed
+ *
+ * This function should be called by input handlers when they
+ * want to stop receive events from given input device.
+ */
void input_close_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- input_release_device(handle);
-
mutex_lock(&dev->mutex);
+ __input_release_device(handle);
+
if (!--dev->users && dev->close)
dev->close(dev);
- handle->open--;
+
+ if (!--handle->open) {
+ /*
+ * synchronize_rcu() makes sure that input_pass_event()
+ * completed and that no more input events are delivered
+ * through this handle
+ */
+ synchronize_rcu();
+ }
mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_close_device);
+/*
+ * Prepare device for unregistering
+ */
+static void input_disconnect_device(struct input_dev *dev)
+{
+ struct input_handle *handle;
+ int code;
+
+ /*
+ * Mark device as going away. Note that we take dev->mutex here
+ * not to protect access to dev->going_away but rather to ensure
+ * that there are no threads in the middle of input_open_device()
+ */
+ mutex_lock(&dev->mutex);
+ dev->going_away = 1;
+ mutex_unlock(&dev->mutex);
+
+ spin_lock_irq(&dev->event_lock);
+
+ /*
+ * Simulate keyup events for all pressed keys so that handlers
+ * are not left with "stuck" keys. The driver may continue
+ * generate events even after we done here but they will not
+ * reach any handlers.
+ */
+ if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+ for (code = 0; code <= KEY_MAX; code++) {
+ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+ test_bit(code, dev->key)) {
+ input_pass_event(dev, EV_KEY, code, 0);
+ }
+ }
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
+
+ list_for_each_entry(handle, &dev->h_list, d_node)
+ handle->open = 0;
+
+ spin_unlock_irq(&dev->event_lock);
+}
+
static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
switch (dev->keycodesize) {
@@ -473,7 +677,8 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
+ if (mutex_lock_interruptible(&input_mutex))
+ return NULL;
return seq_list_start(&input_dev_list, *pos);
}
@@ -485,7 +690,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_devices_seq_stop(struct seq_file *seq, void *v)
{
- /* release lock here */
+ mutex_unlock(&input_mutex);
}
static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
@@ -569,7 +774,9 @@ static const struct file_operations input_devices_fileops = {
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
+ if (mutex_lock_interruptible(&input_mutex))
+ return NULL;
+
seq->private = (void *)(unsigned long)*pos;
return seq_list_start(&input_handler_list, *pos);
}
@@ -582,7 +789,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
{
- /* release lock here */
+ mutex_unlock(&input_mutex);
}
static int input_handlers_seq_show(struct seq_file *seq, void *v)
@@ -859,87 +1066,66 @@ static void input_dev_release(struct device *device)
* Input uevent interface - loading event handlers based on
* device bitfields.
*/
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
const char *name, unsigned long *bitmap, int max)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "%s=", name))
return -ENOMEM;
- *cur_len += input_print_bitmap(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- bitmap, max, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_bitmap(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ bitmap, max, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
struct input_dev *dev)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
- "MODALIAS=");
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- *cur_len += input_print_modalias(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- dev, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ dev, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \
do { \
- int err = input_add_uevent_bm_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- name, bm, max); \
+ int err = input_add_uevent_bm_var(env, name, bm, max); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \
do { \
- int err = input_add_uevent_modalias_var(envp, \
- num_envp, &i, \
- buffer, buffer_size, &len, \
- dev); \
+ int err = input_add_uevent_modalias_var(env, dev); \
if (err) \
return err; \
} while (0)
-static int input_dev_uevent(struct device *device, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct input_dev *dev = to_input_dev(device);
- int i = 0;
- int len = 0;
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
@@ -971,7 +1157,6 @@ static int input_dev_uevent(struct device *device, char **envp,
INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
- envp[i] = NULL;
return 0;
}
@@ -1005,6 +1190,7 @@ struct input_dev *input_allocate_device(void)
dev->dev.class = &input_class;
device_initialize(&dev->dev);
mutex_init(&dev->mutex);
+ spin_lock_init(&dev->event_lock);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
@@ -1022,7 +1208,7 @@ EXPORT_SYMBOL(input_allocate_device);
* This function should only be used if input_register_device()
* was not called yet or if it failed. Once device was registered
* use input_unregister_device() and memory will be freed once last
- * refrence to the device is dropped.
+ * reference to the device is dropped.
*
* Device should be allocated by input_allocate_device().
*
@@ -1092,6 +1278,18 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
}
EXPORT_SYMBOL(input_set_capability);
+/**
+ * input_register_device - register device with input core
+ * @dev: device to be registered
+ *
+ * This function registers device with input core. The device must be
+ * allocated with input_allocate_device() and all it's capabilities
+ * set up before registering.
+ * If function fails the device must be freed with input_free_device().
+ * Once device has been successfully registered it can be unregistered
+ * with input_unregister_device(); input_free_device() should not be
+ * called in this case.
+ */
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
@@ -1099,7 +1297,7 @@ int input_register_device(struct input_dev *dev)
const char *path;
int error;
- set_bit(EV_SYN, dev->evbit);
+ __set_bit(EV_SYN, dev->evbit);
/*
* If delay and period are pre-set by the driver, then autorepeating
@@ -1120,8 +1318,6 @@ int input_register_device(struct input_dev *dev)
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
- list_add_tail(&dev->node, &input_dev_list);
-
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
@@ -1137,49 +1333,79 @@ int input_register_device(struct input_dev *dev)
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
+ error = mutex_lock_interruptible(&input_mutex);
+ if (error) {
+ device_del(&dev->dev);
+ return error;
+ }
+
+ list_add_tail(&dev->node, &input_dev_list);
+
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
+ mutex_unlock(&input_mutex);
+
return 0;
}
EXPORT_SYMBOL(input_register_device);
+/**
+ * input_unregister_device - unregister previously registered device
+ * @dev: device to be unregistered
+ *
+ * This function unregisters an input device. Once device is unregistered
+ * the caller should not try to access it as it may get freed at any moment.
+ */
void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;
- int code;
- for (code = 0; code <= KEY_MAX; code++)
- if (test_bit(code, dev->key))
- input_report_key(dev, code, 0);
- input_sync(dev);
+ input_disconnect_device(dev);
- del_timer_sync(&dev->timer);
+ mutex_lock(&input_mutex);
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
handle->handler->disconnect(handle);
WARN_ON(!list_empty(&dev->h_list));
+ del_timer_sync(&dev->timer);
list_del_init(&dev->node);
- device_unregister(&dev->dev);
-
input_wakeup_procfs_readers();
+
+ mutex_unlock(&input_mutex);
+
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL(input_unregister_device);
+/**
+ * input_register_handler - register a new input handler
+ * @handler: handler to be registered
+ *
+ * This function registers a new input handler (interface) for input
+ * devices in the system and attaches it to all input devices that
+ * are compatible with the handler.
+ */
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&input_mutex);
+ if (retval)
+ return retval;
INIT_LIST_HEAD(&handler->h_list);
if (handler->fops != NULL) {
- if (input_table[handler->minor >> 5])
- return -EBUSY;
-
+ if (input_table[handler->minor >> 5]) {
+ retval = -EBUSY;
+ goto out;
+ }
input_table[handler->minor >> 5] = handler;
}
@@ -1189,14 +1415,26 @@ int input_register_handler(struct input_handler *handler)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
- return 0;
+
+ out:
+ mutex_unlock(&input_mutex);
+ return retval;
}
EXPORT_SYMBOL(input_register_handler);
+/**
+ * input_unregister_handler - unregisters an input handler
+ * @handler: handler to be unregistered
+ *
+ * This function disconnects a handler from its input devices and
+ * removes it from lists of known handlers.
+ */
void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
+ mutex_lock(&input_mutex);
+
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
WARN_ON(!list_empty(&handler->h_list));
@@ -1207,14 +1445,45 @@ void input_unregister_handler(struct input_handler *handler)
input_table[handler->minor >> 5] = NULL;
input_wakeup_procfs_readers();
+
+ mutex_unlock(&input_mutex);
}
EXPORT_SYMBOL(input_unregister_handler);
+/**
+ * input_register_handle - register a new input handle
+ * @handle: handle to register
+ *
+ * This function puts a new input handle onto device's
+ * and handler's lists so that events can flow through
+ * it once it is opened using input_open_device().
+ *
+ * This function is supposed to be called from handler's
+ * connect() method.
+ */
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
+ struct input_dev *dev = handle->dev;
+ int error;
- list_add_tail(&handle->d_node, &handle->dev->h_list);
+ /*
+ * We take dev->mutex here to prevent race with
+ * input_release_device().
+ */
+ error = mutex_lock_interruptible(&dev->mutex);
+ if (error)
+ return error;
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+ mutex_unlock(&dev->mutex);
+ synchronize_rcu();
+
+ /*
+ * Since we are supposed to be called from ->connect()
+ * which is mutually exclusive with ->disconnect()
+ * we can't be racing with input_unregister_handle()
+ * and so separate lock is not needed here.
+ */
list_add_tail(&handle->h_node, &handler->h_list);
if (handler->start)
@@ -1224,10 +1493,29 @@ int input_register_handle(struct input_handle *handle)
}
EXPORT_SYMBOL(input_register_handle);
+/**
+ * input_unregister_handle - unregister an input handle
+ * @handle: handle to unregister
+ *
+ * This function removes input handle from device's
+ * and handler's lists.
+ *
+ * This function is supposed to be called from handler's
+ * disconnect() method.
+ */
void input_unregister_handle(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+
list_del_init(&handle->h_node);
- list_del_init(&handle->d_node);
+
+ /*
+ * Take dev->mutex to prevent race with input_release_device().
+ */
+ mutex_lock(&dev->mutex);
+ list_del_rcu(&handle->d_node);
+ mutex_unlock(&dev->mutex);
+ synchronize_rcu();
}
EXPORT_SYMBOL(input_unregister_handle);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index a9a0180bfd4..2b201f9aa02 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -43,6 +43,8 @@ struct joydev {
struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
struct js_corr corr[ABS_MAX + 1];
@@ -61,31 +63,61 @@ struct joydev_client {
int head;
int tail;
int startup;
+ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct joydev *joydev;
struct list_head node;
};
static struct joydev *joydev_table[JOYDEV_MINORS];
+static DEFINE_MUTEX(joydev_table_mutex);
static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
- default:
- return 0;
+
+ case JS_CORR_NONE:
+ break;
+
+ case JS_CORR_BROKEN:
+ value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+ ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+ ((corr->coef[2] * (value - corr->coef[0])) >> 14);
+ break;
+
+ default:
+ return 0;
}
return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
}
-static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void joydev_pass_event(struct joydev_client *client,
+ struct js_event *event)
+{
+ struct joydev *joydev = client->joydev;
+
+ /*
+ * IRQs already disabled, just acquire the lock
+ */
+ spin_lock(&client->buffer_lock);
+
+ client->buffer[client->head] = *event;
+
+ if (client->startup == joydev->nabs + joydev->nkey) {
+ client->head++;
+ client->head &= JOYDEV_BUFFER_SIZE - 1;
+ if (client->tail == client->head)
+ client->startup = 0;
+ }
+
+ spin_unlock(&client->buffer_lock);
+
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+}
+
+static void joydev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct joydev *joydev = handle->private;
struct joydev_client *client;
@@ -93,39 +125,34 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
switch (type) {
- case EV_KEY:
- if (code < BTN_MISC || value == 2)
- return;
- event.type = JS_EVENT_BUTTON;
- event.number = joydev->keymap[code - BTN_MISC];
- event.value = value;
- break;
-
- case EV_ABS:
- event.type = JS_EVENT_AXIS;
- event.number = joydev->absmap[code];
- event.value = joydev_correct(value, joydev->corr + event.number);
- if (event.value == joydev->abs[event.number])
- return;
- joydev->abs[event.number] = event.value;
- break;
+ case EV_KEY:
+ if (code < BTN_MISC || value == 2)
+ return;
+ event.type = JS_EVENT_BUTTON;
+ event.number = joydev->keymap[code - BTN_MISC];
+ event.value = value;
+ break;
- default:
+ case EV_ABS:
+ event.type = JS_EVENT_AXIS;
+ event.number = joydev->absmap[code];
+ event.value = joydev_correct(value,
+ &joydev->corr[event.number]);
+ if (event.value == joydev->abs[event.number])
return;
+ joydev->abs[event.number] = event.value;
+ break;
+
+ default:
+ return;
}
event.time = jiffies_to_msecs(jiffies);
- list_for_each_entry(client, &joydev->client_list, node) {
-
- memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
-
- if (client->startup == joydev->nabs + joydev->nkey)
- if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
- client->startup = 0;
-
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
+ rcu_read_lock();
+ list_for_each_entry_rcu(client, &joydev->client_list, node)
+ joydev_pass_event(client, &event);
+ rcu_read_unlock();
wake_up_interruptible(&joydev->wait);
}
@@ -144,23 +171,83 @@ static void joydev_free(struct device *dev)
{
struct joydev *joydev = container_of(dev, struct joydev, dev);
- joydev_table[joydev->minor] = NULL;
kfree(joydev);
}
+static void joydev_attach_client(struct joydev *joydev,
+ struct joydev_client *client)
+{
+ spin_lock(&joydev->client_lock);
+ list_add_tail_rcu(&client->node, &joydev->client_list);
+ spin_unlock(&joydev->client_lock);
+ synchronize_rcu();
+}
+
+static void joydev_detach_client(struct joydev *joydev,
+ struct joydev_client *client)
+{
+ spin_lock(&joydev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&joydev->client_lock);
+ synchronize_rcu();
+}
+
+static int joydev_open_device(struct joydev *joydev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist)
+ retval = -ENODEV;
+ else if (!joydev->open++) {
+ retval = input_open_device(&joydev->handle);
+ if (retval)
+ joydev->open--;
+ }
+
+ mutex_unlock(&joydev->mutex);
+ return retval;
+}
+
+static void joydev_close_device(struct joydev *joydev)
+{
+ mutex_lock(&joydev->mutex);
+
+ if (joydev->exist && !--joydev->open)
+ input_close_device(&joydev->handle);
+
+ mutex_unlock(&joydev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void joydev_hangup(struct joydev *joydev)
+{
+ struct joydev_client *client;
+
+ spin_lock(&joydev->client_lock);
+ list_for_each_entry(client, &joydev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&joydev->client_lock);
+
+ wake_up_interruptible(&joydev->wait);
+}
+
static int joydev_release(struct inode *inode, struct file *file)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
joydev_fasync(-1, file, 0);
-
- list_del(&client->node);
+ joydev_detach_client(joydev, client);
kfree(client);
- if (!--joydev->open && joydev->exist)
- input_close_device(&joydev->handle);
-
+ joydev_close_device(joydev);
put_device(&joydev->dev);
return 0;
@@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file)
if (i >= JOYDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&joydev_table_mutex);
+ if (error)
+ return error;
joydev = joydev_table[i];
- if (!joydev || !joydev->exist)
- return -ENODEV;
+ if (joydev)
+ get_device(&joydev->dev);
+ mutex_unlock(&joydev_table_mutex);
- get_device(&joydev->dev);
+ if (!joydev)
+ return -ENODEV;
client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
if (!client) {
@@ -188,37 +280,129 @@ static int joydev_open(struct inode *inode, struct file *file)
goto err_put_joydev;
}
+ spin_lock_init(&client->buffer_lock);
client->joydev = joydev;
- list_add_tail(&client->node, &joydev->client_list);
+ joydev_attach_client(joydev, client);
- if (!joydev->open++ && joydev->exist) {
- error = input_open_device(&joydev->handle);
- if (error)
- goto err_free_client;
- }
+ error = joydev_open_device(joydev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ joydev_detach_client(joydev, client);
kfree(client);
err_put_joydev:
put_device(&joydev->dev);
return error;
}
-static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+static int joydev_generate_startup_event(struct joydev_client *client,
+ struct input_dev *input,
+ struct js_event *event)
{
- return -EINVAL;
+ struct joydev *joydev = client->joydev;
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->startup < joydev->nabs + joydev->nkey;
+
+ if (have_event) {
+
+ event->time = jiffies_to_msecs(jiffies);
+ if (client->startup < joydev->nkey) {
+ event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
+ event->number = client->startup;
+ event->value = !!test_bit(joydev->keypam[event->number],
+ input->key);
+ } else {
+ event->type = JS_EVENT_AXIS | JS_EVENT_INIT;
+ event->number = client->startup - joydev->nkey;
+ event->value = joydev->abs[event->number];
+ }
+ client->startup++;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+static int joydev_fetch_next_event(struct joydev_client *client,
+ struct js_event *event)
+{
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->head != client->tail;
+ if (have_event) {
+ *event = client->buffer[client->tail++];
+ client->tail &= JOYDEV_BUFFER_SIZE - 1;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+/*
+ * Old joystick interface
+ */
+static ssize_t joydev_0x_read(struct joydev_client *client,
+ struct input_dev *input,
+ char __user *buf)
+{
+ struct joydev *joydev = client->joydev;
+ struct JS_DATA_TYPE data;
+ int i;
+
+ spin_lock_irq(&input->event_lock);
+
+ /*
+ * Get device state
+ */
+ for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
+ data.buttons |=
+ test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
+ data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
+ data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
+
+ /*
+ * Reset reader's event queue
+ */
+ spin_lock(&client->buffer_lock);
+ client->startup = 0;
+ client->tail = client->head;
+ spin_unlock(&client->buffer_lock);
+
+ spin_unlock_irq(&input->event_lock);
+
+ if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
+ return -EFAULT;
+
+ return sizeof(struct JS_DATA_TYPE);
+}
+
+static inline int joydev_data_pending(struct joydev_client *client)
+{
+ struct joydev *joydev = client->joydev;
+
+ return client->startup < joydev->nabs + joydev->nkey ||
+ client->head != client->tail;
}
-static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t joydev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
struct input_dev *input = joydev->handle.dev;
- int retval = 0;
+ struct js_event event;
+ int retval;
if (!joydev->exist)
return -ENODEV;
@@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
if (count < sizeof(struct js_event))
return -EINVAL;
- if (count == sizeof(struct JS_DATA_TYPE)) {
-
- struct JS_DATA_TYPE data;
- int i;
-
- for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
- data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
- data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
- data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
-
- if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
- return -EFAULT;
-
- client->startup = 0;
- client->tail = client->head;
+ if (count == sizeof(struct JS_DATA_TYPE))
+ return joydev_0x_read(client, input, buf);
- return sizeof(struct JS_DATA_TYPE);
- }
-
- if (client->startup == joydev->nabs + joydev->nkey &&
- client->head == client->tail && (file->f_flags & O_NONBLOCK))
+ if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(joydev->wait,
- !joydev->exist ||
- client->startup < joydev->nabs + joydev->nkey ||
- client->head != client->tail);
+ !joydev->exist || joydev_data_pending(client));
if (retval)
return retval;
if (!joydev->exist)
return -ENODEV;
- while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
-
- struct js_event event;
-
- event.time = jiffies_to_msecs(jiffies);
-
- if (client->startup < joydev->nkey) {
- event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.number = client->startup;
- event.value = !!test_bit(joydev->keypam[event.number], input->key);
- } else {
- event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.number = client->startup - joydev->nkey;
- event.value = joydev->abs[event.number];
- }
+ while (retval + sizeof(struct js_event) <= count &&
+ joydev_generate_startup_event(client, input, &event)) {
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
- client->startup++;
retval += sizeof(struct js_event);
}
- while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
+ while (retval + sizeof(struct js_event) <= count &&
+ joydev_fetch_next_event(client, &event)) {
- if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
+ if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
- client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
retval += sizeof(struct js_event);
}
@@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
struct joydev *joydev = client->joydev;
poll_wait(file, &joydev->wait, wait);
- return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
- (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
+ return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
+ (joydev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
+static int joydev_ioctl_common(struct joydev *joydev,
+ unsigned int cmd, void __user *argp)
{
struct input_dev *dev = joydev->handle.dev;
int i, j;
switch (cmd) {
- case JS_SET_CAL:
- return copy_from_user(&joydev->glue.JS_CORR, argp,
+ case JS_SET_CAL:
+ return copy_from_user(&joydev->glue.JS_CORR, argp,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user(argp, &joydev->glue.JS_CORR,
+ case JS_GET_CAL:
+ return copy_to_user(argp, &joydev->glue.JS_CORR,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+ case JS_SET_TIMEOUT:
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
- case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+ case JS_GET_TIMEOUT:
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) argp);
+ case JSIOCGVERSION:
+ return put_user(JS_VERSION, (__u32 __user *) argp);
- case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) argp);
+ case JSIOCGAXES:
+ return put_user(joydev->nabs, (__u8 __user *) argp);
- case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) argp);
+ case JSIOCGBUTTONS:
+ return put_user(joydev->nkey, (__u8 __user *) argp);
- case JSIOCSCORR:
- if (copy_from_user(joydev->corr, argp,
- sizeof(joydev->corr[0]) * joydev->nabs))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- j = joydev->abspam[i];
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
- }
- return 0;
+ case JSIOCSCORR:
+ if (copy_from_user(joydev->corr, argp,
+ sizeof(joydev->corr[0]) * joydev->nabs))
+ return -EFAULT;
- case JSIOCGCORR:
- return copy_to_user(argp, joydev->corr,
- sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+ for (i = 0; i < joydev->nabs; i++) {
+ j = joydev->abspam[i];
+ joydev->abs[i] = joydev_correct(dev->abs[j],
+ &joydev->corr[i]);
+ }
+ return 0;
- case JSIOCSAXMAP:
- if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- if (joydev->abspam[i] > ABS_MAX)
- return -EINVAL;
- joydev->absmap[joydev->abspam[i]] = i;
- }
- return 0;
-
- case JSIOCGAXMAP:
- return copy_to_user(argp, joydev->abspam,
- sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
-
- case JSIOCSBTNMAP:
- if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
+ case JSIOCGCORR:
+ return copy_to_user(argp, joydev->corr,
+ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+
+ case JSIOCSAXMAP:
+ if (copy_from_user(joydev->abspam, argp,
+ sizeof(__u8) * (ABS_MAX + 1)))
+ return -EFAULT;
+
+ for (i = 0; i < joydev->nabs; i++) {
+ if (joydev->abspam[i] > ABS_MAX)
+ return -EINVAL;
+ joydev->absmap[joydev->abspam[i]] = i;
+ }
+ return 0;
+
+ case JSIOCGAXMAP:
+ return copy_to_user(argp, joydev->abspam,
+ sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
+
+ case JSIOCSBTNMAP:
+ if (copy_from_user(joydev->keypam, argp,
+ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
+ return -EFAULT;
+
+ for (i = 0; i < joydev->nkey; i++) {
+ if (joydev->keypam[i] > KEY_MAX ||
+ joydev->keypam[i] < BTN_MISC)
+ return -EINVAL;
+ joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
+ }
+
+ return 0;
+
+ case JSIOCGBTNMAP:
+ return copy_to_user(argp, joydev->keypam,
+ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+
+ default:
+ if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
+ int len;
+ if (!dev->name)
+ return 0;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd))
+ len = _IOC_SIZE(cmd);
+ if (copy_to_user(argp, dev->name, len))
return -EFAULT;
- for (i = 0; i < joydev->nkey; i++) {
- if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
- return -EINVAL;
- joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
- }
- return 0;
-
- case JSIOCGBTNMAP:
- return copy_to_user(argp, joydev->keypam,
- sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
-
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- int len;
- if (!dev->name)
- return 0;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd))
- len = _IOC_SIZE(cmd);
- if (copy_to_user(argp, dev->name, len))
- return -EFAULT;
- return len;
- }
+ return len;
+ }
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
-static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long joydev_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
s32 tmp32;
struct JS_DATA_SAVE_TYPE_32 ds32;
- int err;
+ int retval;
- if (!joydev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
- switch(cmd) {
case JS_SET_TIMELIMIT:
- err = get_user(tmp32, (s32 __user *) arg);
- if (err == 0)
+ retval = get_user(tmp32, (s32 __user *) arg);
+ if (retval == 0)
joydev->glue.JS_TIMELIMIT = tmp32;
break;
+
case JS_GET_TIMELIMIT:
tmp32 = joydev->glue.JS_TIMELIMIT;
- err = put_user(tmp32, (s32 __user *) arg);
+ retval = put_user(tmp32, (s32 __user *) arg);
break;
case JS_SET_ALL:
- err = copy_from_user(&ds32, argp,
- sizeof(ds32)) ? -EFAULT : 0;
- if (err == 0) {
+ retval = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (retval == 0) {
joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
joydev->glue.BUSY = ds32.BUSY;
joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
@@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
ds32.JS_SAVE = joydev->glue.JS_SAVE;
ds32.JS_CORR = joydev->glue.JS_CORR;
- err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
+ retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
break;
default:
- err = joydev_ioctl_common(joydev, cmd, argp);
+ retval = joydev_ioctl_common(joydev, cmd, argp);
+ break;
}
- return err;
+
+ out:
+ mutex_unlock(&joydev->mutex);
+ return retval;
}
#endif /* CONFIG_COMPAT */
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long joydev_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
+ int retval;
- if (!joydev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
+
+ case JS_SET_TIMELIMIT:
+ retval = get_user(joydev->glue.JS_TIMELIMIT,
+ (long __user *) arg);
+ break;
+
+ case JS_GET_TIMELIMIT:
+ retval = put_user(joydev->glue.JS_TIMELIMIT,
+ (long __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ retval = copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT: 0;
+ break;
+
+ case JS_GET_ALL:
+ retval = copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ break;
- switch(cmd) {
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(joydev->glue)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(joydev->glue)) ? -EFAULT : 0;
- default:
- return joydev_ioctl_common(joydev, cmd, argp);
+ default:
+ retval = joydev_ioctl_common(joydev, cmd, argp);
+ break;
}
+ out:
+ mutex_unlock(&joydev->mutex);
+ return retval;
}
static const struct file_operations joydev_fops = {
- .owner = THIS_MODULE,
- .read = joydev_read,
- .write = joydev_write,
- .poll = joydev_poll,
- .open = joydev_open,
- .release = joydev_release,
- .ioctl = joydev_ioctl,
+ .owner = THIS_MODULE,
+ .read = joydev_read,
+ .poll = joydev_poll,
+ .open = joydev_open,
+ .release = joydev_release,
+ .unlocked_ioctl = joydev_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = joydev_compat_ioctl,
+ .compat_ioctl = joydev_compat_ioctl,
#endif
- .fasync = joydev_fasync,
+ .fasync = joydev_fasync,
};
+static int joydev_install_chrdev(struct joydev *joydev)
+{
+ joydev_table[joydev->minor] = joydev;
+ return 0;
+}
+
+static void joydev_remove_chrdev(struct joydev *joydev)
+{
+ mutex_lock(&joydev_table_mutex);
+ joydev_table[joydev->minor] = NULL;
+ mutex_unlock(&joydev_table_mutex);
+}
+
+/*
+ * Mark device non-existant. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void joydev_mark_dead(struct joydev *joydev)
+{
+ mutex_lock(&joydev->mutex);
+ joydev->exist = 0;
+ mutex_unlock(&joydev->mutex);
+}
+
+static void joydev_cleanup(struct joydev *joydev)
+{
+ struct input_handle *handle = &joydev->handle;
+
+ joydev_mark_dead(joydev);
+ joydev_hangup(joydev);
+ joydev_remove_chrdev(joydev);
+
+ /* joydev is marked dead so noone else accesses joydev->open */
+ if (joydev->open)
+ input_close_device(handle);
+}
+
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
@@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
int i, j, t, minor;
int error;
- for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+ for (minor = 0; minor < JOYDEV_MINORS; minor++)
+ if (!joydev_table[minor])
+ break;
+
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
return -ENFILE;
@@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
return -ENOMEM;
INIT_LIST_HEAD(&joydev->client_list);
+ spin_lock_init(&joydev->client_lock);
+ mutex_init(&joydev->mutex);
init_waitqueue_head(&joydev->wait);
+ snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
+ joydev->exist = 1;
joydev->minor = minor;
+
joydev->exist = 1;
joydev->handle.dev = dev;
joydev->handle.name = joydev->name;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
- snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
for (i = 0; i < ABS_MAX + 1; i++)
if (test_bit(i, dev->absbit)) {
@@ -545,67 +785,65 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
}
joydev->corr[i].type = JS_CORR_BROKEN;
joydev->corr[i].prec = dev->absfuzz[j];
- joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
- joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
- if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
- continue;
- joydev->corr[i].coef[2] = (1 << 29) / t;
- joydev->corr[i].coef[3] = (1 << 29) / t;
-
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
+ joydev->corr[i].coef[0] =
+ (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
+ joydev->corr[i].coef[1] =
+ (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
+
+ t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j];
+ if (t) {
+ joydev->corr[i].coef[2] = (1 << 29) / t;
+ joydev->corr[i].coef[3] = (1 << 29) / t;
+
+ joydev->abs[i] = joydev_correct(dev->abs[j],
+ joydev->corr + i);
+ }
}
- snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
- "js%d", minor);
+ strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
+ joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
joydev->dev.class = &input_class;
joydev->dev.parent = &dev->dev;
- joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
joydev->dev.release = joydev_free;
device_initialize(&joydev->dev);
- joydev_table[minor] = joydev;
-
- error = device_add(&joydev->dev);
+ error = input_register_handle(&joydev->handle);
if (error)
goto err_free_joydev;
- error = input_register_handle(&joydev->handle);
+ error = joydev_install_chrdev(joydev);
if (error)
- goto err_delete_joydev;
+ goto err_unregister_handle;
+
+ error = device_add(&joydev->dev);
+ if (error)
+ goto err_cleanup_joydev;
return 0;
- err_delete_joydev:
- device_del(&joydev->dev);
+ err_cleanup_joydev:
+ joydev_cleanup(joydev);
+ err_unregister_handle:
+ input_unregister_handle(&joydev->handle);
err_free_joydev:
put_device(&joydev->dev);
return error;
}
-
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- struct joydev_client *client;
- input_unregister_handle(handle);
device_del(&joydev->dev);
-
- joydev->exist = 0;
-
- if (joydev->open) {
- input_close_device(handle);
- list_for_each_entry(client, &joydev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&joydev->wait);
- }
-
+ joydev_cleanup(joydev);
+ input_unregister_handle(handle);
put_device(&joydev->dev);
}
static const struct input_device_id joydev_blacklist[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
}, /* Avoid itouchpads, touchscreens and tablets */
@@ -614,17 +852,20 @@ static const struct input_device_id joydev_blacklist[] = {
static const struct input_device_id joydev_ids[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_X) },
},
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_WHEEL) },
},
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_THROTTLE) },
},
@@ -634,14 +875,14 @@ static const struct input_device_id joydev_ids[] = {
MODULE_DEVICE_TABLE(input, joydev_ids);
static struct input_handler joydev_handler = {
- .event = joydev_event,
- .connect = joydev_connect,
- .disconnect = joydev_disconnect,
- .fops = &joydev_fops,
- .minor = JOYDEV_MINOR_BASE,
- .name = "joydev",
- .id_table = joydev_ids,
- .blacklist = joydev_blacklist,
+ .event = joydev_event,
+ .connect = joydev_connect,
+ .disconnect = joydev_disconnect,
+ .fops = &joydev_fops,
+ .minor = JOYDEV_MINOR_BASE,
+ .name = "joydev",
+ .id_table = joydev_ids,
+ .blacklist = joydev_blacklist,
};
static int __init joydev_init(void)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 28080395899..623629a69b0 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -223,12 +223,16 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
struct input_dev *dev = xpad->dev;
/* left stick */
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 12)));
+ input_report_abs(dev, ABS_Y,
+ (__s16) le16_to_cpup((__le16 *)(data + 14)));
/* right stick */
- input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
- input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 16)));
+ input_report_abs(dev, ABS_RY,
+ (__s16) le16_to_cpup((__le16 *)(data + 18)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[10]);
@@ -236,8 +240,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* digital pad */
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
@@ -274,14 +280,17 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
* http://www.free60.org/wiki/Gamepad
*/
-static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+static void xpad360_process_packet(struct usb_xpad *xpad,
+ u16 cmd, unsigned char *data)
{
struct input_dev *dev = xpad->dev;
/* digital pad */
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
} else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (right, left, down, up) */
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
@@ -308,12 +317,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
input_report_key(dev, BTN_MODE, data[3] & 0x04);
/* left stick */
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8]));
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 6)));
+ input_report_abs(dev, ABS_Y,
+ (__s16) le16_to_cpup((__le16 *)(data + 8)));
/* right stick */
- input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10]));
- input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12]));
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 10)));
+ input_report_abs(dev, ABS_RY,
+ (__s16) le16_to_cpup((__le16 *)(data + 12)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[4]);
@@ -335,10 +348,12 @@ static void xpad_irq_in(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
goto exit;
}
@@ -367,10 +382,12 @@ static void xpad_irq_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
goto exit;
}
@@ -378,7 +395,7 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __FUNCTION__, retval);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -595,7 +612,7 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev (intf);
+ struct usb_device *udev = interface_to_usbdev(intf);
struct usb_xpad *xpad;
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c97d5eb0075..2316a018fae 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -208,6 +208,27 @@ config KEYBOARD_HIL
This driver implements support for HIL-keyboards attached
to your machine, so normally you should say Y here.
+config KEYBOARD_HP6XX
+ tristate "HP Jornada 6XX Keyboard support"
+ depends on SH_HP6XX
+ select INPUT_POLLDEV
+ help
+ This adds support for the onboard keyboard found on
+ HP Jornada 620/660/680/690.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada680_kbd.
+
+config KEYBOARD_HP7XX
+ tristate "HP Jornada 7XX Keyboard Driver"
+ depends on SA1100_JORNADA720_SSP && SA1100_SSP
+ help
+ Say Y here to add support for the HP Jornada 7xx (710/720/728)
+ onboard keyboard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_kbd.
+
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
@@ -253,4 +274,23 @@ config KEYBOARD_GPIO
To compile this driver as a module, choose M here: the
module will be called gpio-keys.
+config KEYBOARD_MAPLE
+ tristate "Maple bus keyboard"
+ depends on SH_DREAMCAST && MAPLE
+ help
+ Say Y here if you have a Dreamcast console running Linux and have
+ a keyboard attached to its Maple bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called maple_keyb.
+
+config KEYBOARD_BFIN
+ tristate "Blackfin BF54x keypad support"
+ depends on BF54x
+ help
+ Say Y here if you want to use the BF54x keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bf54x-keys.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 28d211b87b1..e97455fdcc8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -21,4 +21,7 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
-
+obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
+obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
+obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
+obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index ded1d6ac6ff..a1800151b6c 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -55,7 +55,140 @@ MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
MODULE_DESCRIPTION("Atari keyboard driver");
MODULE_LICENSE("GPL");
-static unsigned char atakbd_keycode[0x72];
+/*
+ 0x47: KP_7 71
+ 0x48: KP_8 72
+ 0x49: KP_9 73
+ 0x62: KP_/ 98
+ 0x4b: KP_4 75
+ 0x4c: KP_5 76
+ 0x4d: KP_6 77
+ 0x37: KP_* 55
+ 0x4f: KP_1 79
+ 0x50: KP_2 80
+ 0x51: KP_3 81
+ 0x4a: KP_- 74
+ 0x52: KP_0 82
+ 0x53: KP_. 83
+ 0x4e: KP_+ 78
+
+ 0x67: Up 103
+ 0x6c: Down 108
+ 0x69: Left 105
+ 0x6a: Right 106
+ */
+
+
+static unsigned char atakbd_keycode[0x72] = { /* American layout */
+ [0] = KEY_GRAVE,
+ [1] = KEY_ESC,
+ [2] = KEY_1,
+ [3] = KEY_2,
+ [4] = KEY_3,
+ [5] = KEY_4,
+ [6] = KEY_5,
+ [7] = KEY_6,
+ [8] = KEY_7,
+ [9] = KEY_8,
+ [10] = KEY_9,
+ [11] = KEY_0,
+ [12] = KEY_MINUS,
+ [13] = KEY_EQUAL,
+ [14] = KEY_BACKSPACE,
+ [15] = KEY_TAB,
+ [16] = KEY_Q,
+ [17] = KEY_W,
+ [18] = KEY_E,
+ [19] = KEY_R,
+ [20] = KEY_T,
+ [21] = KEY_Y,
+ [22] = KEY_U,
+ [23] = KEY_I,
+ [24] = KEY_O,
+ [25] = KEY_P,
+ [26] = KEY_LEFTBRACE,
+ [27] = KEY_RIGHTBRACE,
+ [28] = KEY_ENTER,
+ [29] = KEY_LEFTCTRL,
+ [30] = KEY_A,
+ [31] = KEY_S,
+ [32] = KEY_D,
+ [33] = KEY_F,
+ [34] = KEY_G,
+ [35] = KEY_H,
+ [36] = KEY_J,
+ [37] = KEY_K,
+ [38] = KEY_L,
+ [39] = KEY_SEMICOLON,
+ [40] = KEY_APOSTROPHE,
+ [41] = KEY_BACKSLASH, /* FIXME, '#' */
+ [42] = KEY_LEFTSHIFT,
+ [43] = KEY_GRAVE, /* FIXME: '~' */
+ [44] = KEY_Z,
+ [45] = KEY_X,
+ [46] = KEY_C,
+ [47] = KEY_V,
+ [48] = KEY_B,
+ [49] = KEY_N,
+ [50] = KEY_M,
+ [51] = KEY_COMMA,
+ [52] = KEY_DOT,
+ [53] = KEY_SLASH,
+ [54] = KEY_RIGHTSHIFT,
+ [55] = KEY_KPASTERISK,
+ [56] = KEY_LEFTALT,
+ [57] = KEY_SPACE,
+ [58] = KEY_CAPSLOCK,
+ [59] = KEY_F1,
+ [60] = KEY_F2,
+ [61] = KEY_F3,
+ [62] = KEY_F4,
+ [63] = KEY_F5,
+ [64] = KEY_F6,
+ [65] = KEY_F7,
+ [66] = KEY_F8,
+ [67] = KEY_F9,
+ [68] = KEY_F10,
+ [69] = KEY_ESC,
+ [70] = KEY_DELETE,
+ [71] = KEY_KP7,
+ [72] = KEY_KP8,
+ [73] = KEY_KP9,
+ [74] = KEY_KPMINUS,
+ [75] = KEY_KP4,
+ [76] = KEY_KP5,
+ [77] = KEY_KP6,
+ [78] = KEY_KPPLUS,
+ [79] = KEY_KP1,
+ [80] = KEY_KP2,
+ [81] = KEY_KP3,
+ [82] = KEY_KP0,
+ [83] = KEY_KPDOT,
+ [90] = KEY_KPLEFTPAREN,
+ [91] = KEY_KPRIGHTPAREN,
+ [92] = KEY_KPASTERISK, /* FIXME */
+ [93] = KEY_KPASTERISK,
+ [94] = KEY_KPPLUS,
+ [95] = KEY_HELP,
+ [96] = KEY_BACKSLASH, /* FIXME: '<' */
+ [97] = KEY_KPASTERISK, /* FIXME */
+ [98] = KEY_KPSLASH,
+ [99] = KEY_KPLEFTPAREN,
+ [100] = KEY_KPRIGHTPAREN,
+ [101] = KEY_KPSLASH,
+ [102] = KEY_KPASTERISK,
+ [103] = KEY_UP,
+ [104] = KEY_KPASTERISK, /* FIXME */
+ [105] = KEY_LEFT,
+ [106] = KEY_RIGHT,
+ [107] = KEY_KPASTERISK, /* FIXME */
+ [108] = KEY_DOWN,
+ [109] = KEY_KPASTERISK, /* FIXME */
+ [110] = KEY_KPASTERISK, /* FIXME */
+ [111] = KEY_KPASTERISK, /* FIXME */
+ [112] = KEY_KPASTERISK, /* FIXME */
+ [113] = KEY_KPASTERISK /* FIXME */
+};
static struct input_dev *atakbd_dev;
@@ -84,23 +217,22 @@ static void atakbd_interrupt(unsigned char scancode, char down)
static int __init atakbd_init(void)
{
- int i;
+ int i, error;
- if (!ATARIHW_PRESENT(ST_MFP))
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
return -EIO;
- // TODO: request_mem_region if not done in arch code
-
- if (!(atakbd_dev = input_allocate_device()))
- return -ENOMEM;
-
// need to init core driver if not already done so
if (atari_keyb_init())
return -ENODEV;
+ atakbd_dev = input_allocate_device();
+ if (!atakbd_dev)
+ return -ENOMEM;
+
atakbd_dev->name = "Atari Keyboard";
atakbd_dev->phys = "atakbd/input0";
- atakbd_dev->id.bustype = BUS_ATARI;
+ atakbd_dev->id.bustype = BUS_HOST;
atakbd_dev->id.vendor = 0x0001;
atakbd_dev->id.product = 0x0001;
atakbd_dev->id.version = 0x0100;
@@ -111,16 +243,18 @@ static int __init atakbd_init(void)
atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
for (i = 1; i < 0x72; i++) {
- atakbd_keycode[i] = i;
set_bit(atakbd_keycode[i], atakbd_dev->keybit);
}
- input_register_device(atakbd_dev);
+ /* error check */
+ error = input_register_device(atakbd_dev);
+ if (error) {
+ input_free_device(atakbd_dev);
+ return error;
+ }
atari_input_keyboard_interrupt_hook = atakbd_interrupt;
- printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
-
return 0;
}
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
new file mode 100644
index 00000000000..a67b29b089e
--- /dev/null
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -0,0 +1,382 @@
+/*
+ * File: drivers/input/keyboard/bf54x-keys.c
+ * Based on:
+ * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
+ *
+ * Created:
+ * Description: keypad driver for Analog Devices Blackfin BF54x Processors
+ *
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+#include <asm/portmux.h>
+#include <asm/mach/bf54x_keys.h>
+
+#define DRV_NAME "bf54x-keys"
+#define TIME_SCALE 100 /* 100 ns */
+#define MAX_MULT (0xFF * TIME_SCALE)
+#define MAX_RC 8 /* Max Row/Col */
+
+static const u16 per_rows[] = {
+ P_KEY_ROW7,
+ P_KEY_ROW6,
+ P_KEY_ROW5,
+ P_KEY_ROW4,
+ P_KEY_ROW3,
+ P_KEY_ROW2,
+ P_KEY_ROW1,
+ P_KEY_ROW0,
+ 0
+};
+
+static const u16 per_cols[] = {
+ P_KEY_COL7,
+ P_KEY_COL6,
+ P_KEY_COL5,
+ P_KEY_COL4,
+ P_KEY_COL3,
+ P_KEY_COL2,
+ P_KEY_COL1,
+ P_KEY_COL0,
+ 0
+};
+
+struct bf54x_kpad {
+ struct input_dev *input;
+ int irq;
+ unsigned short lastkey;
+ unsigned short *keycode;
+ struct timer_list timer;
+ unsigned int keyup_test_jiffies;
+};
+
+static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
+ struct input_dev *input, u16 keyident)
+{
+ u16 i;
+
+ for (i = 0; i < input->keycodemax; i++)
+ if (bf54x_kpad->keycode[i + input->keycodemax] == keyident)
+ return bf54x_kpad->keycode[i];
+ return -1;
+}
+
+static inline void bfin_keycodecpy(unsigned short *keycode,
+ const unsigned int *pdata_kc,
+ unsigned short keymapsize)
+{
+ unsigned int i;
+
+ for (i = 0; i < keymapsize; i++) {
+ keycode[i] = pdata_kc[i] & 0xffff;
+ keycode[i + keymapsize] = pdata_kc[i] >> 16;
+ }
+}
+
+static inline u16 bfin_kpad_get_prescale(u32 timescale)
+{
+ u32 sclk = get_sclk();
+
+ return ((((sclk / 1000) * timescale) / 1024) - 1);
+}
+
+static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad)
+{
+ return (bfin_read_KPAD_STAT() & KPAD_PRESSED);
+}
+
+static inline void bfin_kpad_clear_irq(void)
+{
+ bfin_write_KPAD_STAT(0xFFFF);
+ bfin_write_KPAD_ROWCOL(0xFFFF);
+}
+
+static void bfin_kpad_timer(unsigned long data)
+{
+ struct platform_device *pdev = (struct platform_device *) data;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ if (bfin_kpad_get_keypressed(bf54x_kpad)) {
+ /* Try again later */
+ mod_timer(&bf54x_kpad->timer,
+ jiffies + bf54x_kpad->keyup_test_jiffies);
+ return;
+ }
+
+ input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0);
+ input_sync(bf54x_kpad->input);
+
+ /* Clear IRQ Status */
+
+ bfin_kpad_clear_irq();
+ enable_irq(bf54x_kpad->irq);
+}
+
+static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+ struct input_dev *input = bf54x_kpad->input;
+ int key;
+ u16 rowcol = bfin_read_KPAD_ROWCOL();
+
+ key = bfin_kpad_find_key(bf54x_kpad, input, rowcol);
+
+ input_report_key(input, key, 1);
+ input_sync(input);
+
+ if (bfin_kpad_get_keypressed(bf54x_kpad)) {
+ disable_irq(bf54x_kpad->irq);
+ bf54x_kpad->lastkey = key;
+ mod_timer(&bf54x_kpad->timer,
+ jiffies + bf54x_kpad->keyup_test_jiffies);
+ } else {
+ input_report_key(input, key, 0);
+ input_sync(input);
+
+ bfin_kpad_clear_irq();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit bfin_kpad_probe(struct platform_device *pdev)
+{
+ struct bf54x_kpad *bf54x_kpad;
+ struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input;
+ int i, error;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ printk(KERN_ERR DRV_NAME
+ ": No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymapsize ||
+ pdata->keymapsize > (pdata->rows * pdata->cols)) {
+ printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
+ return -EINVAL;
+ }
+
+ bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL);
+ if (!bf54x_kpad)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, bf54x_kpad);
+
+ /* Allocate memory for keymap followed by private LUT */
+ bf54x_kpad->keycode = kmalloc(pdata->keymapsize *
+ sizeof(unsigned short) * 2, GFP_KERNEL);
+ if (!bf54x_kpad->keycode) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT ||
+ !pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) {
+ printk(KERN_ERR DRV_NAME
+ ": Invalid Debounce/Columdrive Time from pdata\n");
+ bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
+ } else {
+ bfin_write_KPAD_MSEL(
+ ((pdata->debounce_time / TIME_SCALE)
+ & DBON_SCALE) |
+ (((pdata->coldrive_time / TIME_SCALE) << 8)
+ & COLDRV_SCALE));
+
+ }
+
+ if (!pdata->keyup_test_interval)
+ bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50);
+ else
+ bf54x_kpad->keyup_test_jiffies =
+ msecs_to_jiffies(pdata->keyup_test_interval);
+
+ if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
+ DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ error = -EFAULT;
+ goto out0;
+ }
+
+ if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
+ DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ error = -EFAULT;
+ goto out1;
+ }
+
+ bf54x_kpad->irq = platform_get_irq(pdev, 0);
+ if (bf54x_kpad->irq < 0) {
+ error = -ENODEV;
+ goto out2;
+ }
+
+ error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
+ IRQF_SAMPLE_RANDOM, DRV_NAME, pdev);
+ if (error) {
+ printk(KERN_ERR DRV_NAME
+ ": unable to claim irq %d; error %d\n",
+ bf54x_kpad->irq, error);
+ error = -EBUSY;
+ goto out2;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto out3;
+ }
+
+ bf54x_kpad->input = input;
+
+ input->name = pdev->name;
+ input->phys = "bf54x-keys/input0";
+ input->dev.parent = &pdev->dev;
+
+ input_set_drvdata(input, bf54x_kpad);
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ input->keycodesize = sizeof(unsigned short);
+ input->keycodemax = pdata->keymapsize;
+ input->keycode = bf54x_kpad->keycode;
+
+ bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize);
+
+ /* setup input device */
+ __set_bit(EV_KEY, input->evbit);
+
+ if (pdata->repeat)
+ __set_bit(EV_REP, input->evbit);
+
+ for (i = 0; i < input->keycodemax; i++)
+ __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
+
+ error = input_register_device(input);
+ if (error) {
+ printk(KERN_ERR DRV_NAME
+ ": Unable to register input device (%d)\n", error);
+ goto out4;
+ }
+
+ /* Init Keypad Key Up/Release test timer */
+
+ setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev);
+
+ bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
+
+ bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) |
+ (((pdata->rows - 1) << 10) & KPAD_ROWEN) |
+ (2 & KPAD_IRQMODE));
+
+ bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN);
+
+ printk(KERN_ERR DRV_NAME
+ ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
+
+ return 0;
+
+out4:
+ input_free_device(input);
+out3:
+ free_irq(bf54x_kpad->irq, pdev);
+out2:
+ peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
+out1:
+ peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
+out0:
+ kfree(bf54x_kpad->keycode);
+out:
+ kfree(bf54x_kpad);
+ platform_set_drvdata(pdev, NULL);
+
+ return error;
+}
+
+static int __devexit bfin_kpad_remove(struct platform_device *pdev)
+{
+ struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ del_timer_sync(&bf54x_kpad->timer);
+ free_irq(bf54x_kpad->irq, pdev);
+
+ input_unregister_device(bf54x_kpad->input);
+
+ peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
+ peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
+
+ kfree(bf54x_kpad->keycode);
+ kfree(bf54x_kpad);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+struct platform_driver bfin_kpad_device_driver = {
+ .probe = bfin_kpad_probe,
+ .remove = __devexit_p(bfin_kpad_remove),
+ .driver = {
+ .name = DRV_NAME,
+ }
+};
+
+static int __init bfin_kpad_init(void)
+{
+ return platform_driver_register(&bfin_kpad_device_driver);
+}
+
+static void __exit bfin_kpad_exit(void)
+{
+ platform_driver_unregister(&bfin_kpad_device_driver);
+}
+
+module_init(bfin_kpad_init);
+module_exit(bfin_kpad_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Keypad driver for BF54x Processors");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index f0b22b8b276..e2a3293bc67 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -54,6 +54,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
int i, error;
+ int wakeup = 0;
input = input_allocate_device();
if (!input)
@@ -77,31 +78,51 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
int irq = gpio_to_irq(button->gpio);
unsigned int type = button->type ?: EV_KEY;
- set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
- error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
- button->desc ? button->desc : "gpio_keys",
- pdev);
+ if (irq < 0) {
+ error = irq;
+ printk(KERN_ERR
+ "gpio-keys: "
+ "Unable to get irq number for GPIO %d,"
+ "error %d\n",
+ button->gpio, error);
+ goto fail;
+ }
+
+ error = request_irq(irq, gpio_keys_isr,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ button->desc ? button->desc : "gpio_keys",
+ pdev);
if (error) {
- printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
+ printk(KERN_ERR
+ "gpio-keys: Unable to claim irq %d; error %d\n",
irq, error);
goto fail;
}
+ if (button->wakeup)
+ wakeup = 1;
+
input_set_capability(input, type, button->code);
}
error = input_register_device(input);
if (error) {
- printk(KERN_ERR "Unable to register gpio-keys input device\n");
+ printk(KERN_ERR
+ "gpio-keys: Unable to register input device, "
+ "error: %d\n", error);
goto fail;
}
+ device_init_wakeup(&pdev->dev, wakeup);
+
return 0;
fail:
- for (i = i - 1; i >= 0; i--)
+ while (--i >= 0)
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
+ platform_set_drvdata(pdev, NULL);
input_free_device(input);
return error;
@@ -113,6 +134,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
struct input_dev *input = platform_get_drvdata(pdev);
int i;
+ device_init_wakeup(&pdev->dev, 0);
+
for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio);
free_irq(irq, pdev);
@@ -123,9 +146,53 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
return 0;
}
+
+#ifdef CONFIG_PM
+static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ if (button->wakeup) {
+ int irq = gpio_to_irq(button->gpio);
+ enable_irq_wake(irq);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gpio_keys_resume(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ if (button->wakeup) {
+ int irq = gpio_to_irq(button->gpio);
+ disable_irq_wake(irq);
+ }
+ }
+ }
+
+ return 0;
+}
+#else
+#define gpio_keys_suspend NULL
+#define gpio_keys_resume NULL
+#endif
+
struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
+ .suspend = gpio_keys_suspend,
+ .resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
}
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 00000000000..bec1cf48372
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,277 @@
+/*
+ * drivers/input/keyboard/jornada680_kbd.c
+ *
+ * HP Jornada 620/660/680/690 scan keyboard platform driver
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Based on hp680_keyb.c
+ * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2005 Andriy Skulysh
+ * Split from drivers/input/keyboard/hp600_keyb.c
+ * Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ * Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static const unsigned short jornada_scancodes[] = {
+/* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, /* 1 -> 8 */
+ KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /* 9 -> 16 */
+/* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */
+ KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N, /* 25 -> 32 */
+/* PTD7 */ KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, /* 33 -> 40 */
+ 0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA, /* 41 -> 48 */
+/* PTE0 */ 0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, /* 49 -> 56 */
+ KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /* 57 -> 64 */
+/* PTE1 */ KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/* 65 -> 72 */
+ KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H, /* 73 -> 80 */
+/* PTE3 */ KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0, /* 81 -> 88 */
+ 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 89 -> 96 */
+/* PTE6 */ KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0, /* 97 -> 104 */
+ KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R, /* 105 -> 112 */
+/* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */
+ KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */
+/* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+#define JORNADA_SCAN_SIZE 18
+
+struct jornadakbd {
+ struct input_polled_dev *poll_dev;
+ unsigned short keymap[ARRAY_SIZE(jornada_scancodes)];
+ unsigned char length;
+ unsigned char old_scan[JORNADA_SCAN_SIZE];
+ unsigned char new_scan[JORNADA_SCAN_SIZE];
+};
+
+static void jornada_parse_kbd(struct jornadakbd *jornadakbd)
+{
+ struct input_dev *input_dev = jornadakbd->poll_dev->input;
+ unsigned short *keymap = jornadakbd->keymap;
+ unsigned int sync_me = 0;
+ unsigned int i, j;
+
+ for (i = 0; i < JORNADA_SCAN_SIZE; i++) {
+ unsigned char new = jornadakbd->new_scan[i];
+ unsigned char old = jornadakbd->old_scan[i];
+ unsigned int xor = new ^ old;
+
+ if (xor == 0)
+ continue;
+
+ for (j = 0; j < 8; j++) {
+ unsigned int bit = 1 << j;
+ if (xor & bit) {
+ unsigned int scancode = (i << 3) + j;
+ input_event(input_dev,
+ EV_MSC, MSC_SCAN, scancode);
+ input_report_key(input_dev,
+ keymap[scancode],
+ !(new & bit));
+ sync_me = 1;
+ }
+ }
+ }
+
+ if (sync_me)
+ input_sync(input_dev);
+}
+
+static void jornada_scan_keyb(unsigned char *s)
+{
+ int i;
+ unsigned short ec_static, dc_static; /* = UINT16_t */
+ unsigned char matrix_switch[] = {
+ 0xfd, 0xff, /* PTD1 PD(1) */
+ 0xdf, 0xff, /* PTD5 PD(5) */
+ 0x7f, 0xff, /* PTD7 PD(7) */
+ 0xff, 0xfe, /* PTE0 PE(0) */
+ 0xff, 0xfd, /* PTE1 PE(1) */
+ 0xff, 0xf7, /* PTE3 PE(3) */
+ 0xff, 0xbf, /* PTE6 PE(6) */
+ 0xff, 0x7f, /* PTE7 PE(7) */
+ }, *t = matrix_switch;
+ /* PD(x) :
+ 1. 0xcc0c & (1~(1 << (2*(x)+1)))))
+ 2. (0xf0cf & 0xfffff) */
+ /* PE(x) :
+ 1. 0xcc0c & 0xffff
+ 2. 0xf0cf & (1~(1 << (2*(x)+1))))) */
+ unsigned short matrix_PDE[] = {
+ 0xcc04, 0xf0cf, /* PD(1) */
+ 0xc40c, 0xf0cf, /* PD(5) */
+ 0x4c0c, 0xf0cf, /* PD(7) */
+ 0xcc0c, 0xf0cd, /* PE(0) */
+ 0xcc0c, 0xf0c7, /* PE(1) */
+ 0xcc0c, 0xf04f, /* PE(3) */
+ 0xcc0c, 0xd0cf, /* PE(6) */
+ 0xcc0c, 0x70cf, /* PE(7) */
+ }, *y = matrix_PDE;
+
+ /* Save these control reg bits */
+ dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+ ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+ for (i = 0; i < 8; i++) {
+ /* disable output for all but the one we want to scan */
+ ctrl_outw((dc_static | *y++), PDCR);
+ ctrl_outw((ec_static | *y++), PECR);
+ udelay(5);
+
+ /* Get scanline row */
+ ctrl_outb(*t++, PDDR);
+ ctrl_outb(*t++, PEDR);
+ udelay(50);
+
+ /* Read data */
+ *s++ = ctrl_inb(PCDR);
+ *s++ = ctrl_inb(PFDR);
+ }
+ /* Scan no lines */
+ ctrl_outb(0xff, PDDR);
+ ctrl_outb(0xff, PEDR);
+
+ /* Enable all scanlines */
+ ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+ ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+
+ /* Ignore extra keys and events */
+ *s++ = ctrl_inb(PGDR);
+ *s++ = ctrl_inb(PHDR);
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+ struct jornadakbd *jornadakbd = dev->private;
+
+ jornada_scan_keyb(jornadakbd->new_scan);
+ jornada_parse_kbd(jornadakbd);
+ memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE);
+}
+
+static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input_dev;
+ int i, error;
+
+ jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+ if (!jornadakbd)
+ return -ENOMEM;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ error = -ENOMEM;
+ goto failed;
+ }
+
+ platform_set_drvdata(pdev, jornadakbd);
+
+ jornadakbd->poll_dev = poll_dev;
+
+ memcpy(jornadakbd->keymap, jornada_scancodes,
+ sizeof(jornadakbd->keymap));
+
+ poll_dev->private = jornadakbd;
+ poll_dev->poll = jornadakbd680_poll;
+ poll_dev->poll_interval = 50; /* msec */
+
+ input_dev = poll_dev->input;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->name = "HP Jornada 680 keyboard";
+ input_dev->phys = "jornadakbd/input0";
+ input_dev->keycode = jornadakbd->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_HOST;
+
+ for (i = 0; i < 128; i++)
+ if (jornadakbd->keymap[i])
+ __set_bit(jornadakbd->keymap[i], input_dev->keybit);
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ error = input_register_polled_device(jornadakbd->poll_dev);
+ if (error)
+ goto failed;
+
+ return 0;
+
+ failed:
+ printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
+ error);
+ platform_set_drvdata(pdev, NULL);
+ input_free_polled_device(poll_dev);
+ kfree(jornadakbd);
+ return error;
+
+}
+
+static int __devexit jornada680kbd_remove(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_polled_device(jornadakbd->poll_dev);
+ input_free_polled_device(jornadakbd->poll_dev);
+ kfree(jornadakbd);
+
+ return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+ .driver = {
+ .name = "jornada680_kbd",
+ },
+ .probe = jornada680kbd_probe,
+ .remove = __devexit_p(jornada680kbd_remove),
+};
+
+static int __init jornada680kbd_init(void)
+{
+ return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+ platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
new file mode 100644
index 00000000000..e6696b3c941
--- /dev/null
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -0,0 +1,185 @@
+/*
+ * drivers/input/keyboard/jornada720_kbd.c
+ *
+ * HP Jornada 720 keyboard platform driver
+ *
+ * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>
+ *
+ * Copyright (C) 2006 jornada 720 kbd driver by
+ Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX
+ * based on (C) 2004 jornada 720 kbd driver by
+ Alex Lange <chicken@handhelds.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/jornada720.h>
+#include <asm/hardware.h>
+
+MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
+MODULE_LICENSE("GPLv2");
+
+static unsigned short jornada_std_keymap[128] = { /* ROW */
+ 0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */
+ KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, /* -> */
+ 0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, /* #2 */
+ KEY_0, KEY_MINUS, KEY_EQUAL,0, 0, 0, /* -> */
+ 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, /* #3 */
+ KEY_P, KEY_BACKSLASH, KEY_BACKSPACE, 0, 0, 0, /* -> */
+ 0, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, /* #4 */
+ KEY_SEMICOLON, KEY_LEFTBRACE, KEY_RIGHTBRACE, 0, 0, 0, /* -> */
+ 0, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, /* #5 */
+ KEY_DOT, KEY_KPMINUS, KEY_APOSTROPHE, KEY_ENTER, 0, 0,0, /* -> */
+ 0, KEY_TAB, 0, KEY_LEFTSHIFT, 0, KEY_APOSTROPHE, 0, 0, 0, 0, /* #6 */
+ KEY_UP, 0, KEY_RIGHTSHIFT, 0, 0, 0,0, 0, 0, 0, 0, KEY_LEFTALT, KEY_GRAVE, /* -> */
+ 0, 0, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0,0, KEY_KPASTERISK, /* -> */
+ KEY_LEFTCTRL, 0, KEY_SPACE, 0, 0, 0, KEY_SLASH, KEY_DELETE, 0, 0, /* -> */
+ 0, 0, 0, KEY_POWER, /* -> */
+};
+
+struct jornadakbd {
+ unsigned short keymap[ARRAY_SIZE(jornada_std_keymap)];
+ struct input_dev *input;
+};
+
+static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+ struct input_dev *input = jornadakbd->input;
+ u8 count, kbd_data, scan_code;
+
+ /* startup ssp with spinlock */
+ jornada_ssp_start();
+
+ if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) {
+ printk(KERN_DEBUG
+ "jornada720_kbd: "
+ "GetKeycode command failed with ETIMEDOUT, "
+ "flushed bus\n");
+ } else {
+ /* How many keycodes are waiting for us? */
+ count = jornada_ssp_byte(TXDUMMY);
+
+ /* Lets drag them out one at a time */
+ while (count--) {
+ /* Exchange TxDummy for location (keymap[kbddata]) */
+ kbd_data = jornada_ssp_byte(TXDUMMY);
+ scan_code = kbd_data & 0x7f;
+
+ input_event(input, EV_MSC, MSC_SCAN, scan_code);
+ input_report_key(input, jornadakbd->keymap[scan_code],
+ !(kbd_data & 0x80));
+ input_sync(input);
+ }
+ }
+
+ /* release spinlock and turn off ssp */
+ jornada_ssp_end();
+
+ return IRQ_HANDLED;
+};
+
+static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd;
+ struct input_dev *input_dev;
+ int i, err;
+
+ jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!jornadakbd || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ platform_set_drvdata(pdev, jornadakbd);
+
+ memcpy(jornadakbd->keymap, jornada_std_keymap,
+ sizeof(jornada_std_keymap));
+ jornadakbd->input = input_dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->name = "HP Jornada 720 keyboard";
+ input_dev->phys = "jornadakbd/input0";
+ input_dev->keycode = jornadakbd->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(jornada_std_keymap);
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(jornadakbd->keymap); i++)
+ __set_bit(jornadakbd->keymap[i], input_dev->keybit);
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ err = request_irq(IRQ_GPIO0,
+ jornada720_kbd_interrupt,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "jornadakbd", pdev);
+ if (err) {
+ printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");
+ goto fail1;
+ }
+
+ err = input_register_device(jornadakbd->input);
+ if (err)
+ goto fail2;
+
+ return 0;
+
+ fail2: /* IRQ, DEVICE, MEMORY */
+ free_irq(IRQ_GPIO0, pdev);
+ fail1: /* DEVICE, MEMORY */
+ platform_set_drvdata(pdev, NULL);
+ input_free_device(input_dev);
+ kfree(jornadakbd);
+ return err;
+};
+
+static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+ free_irq(IRQ_GPIO0, pdev);
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(jornadakbd->input);
+ kfree(jornadakbd);
+
+ return 0;
+}
+
+static struct platform_driver jornada720_kbd_driver = {
+ .driver = {
+ .name = "jornada720_kbd",
+ },
+ .probe = jornada720_kbd_probe,
+ .remove = __devexit_p(jornada720_kbd_remove),
+};
+
+static int __init jornada720_kbd_init(void)
+{
+ return platform_driver_register(&jornada720_kbd_driver);
+}
+
+static void __exit jornada720_kbd_exit(void)
+{
+ platform_driver_unregister(&jornada720_kbd_driver);
+}
+
+module_init(jornada720_kbd_init);
+module_exit(jornada720_kbd_exit);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
new file mode 100644
index 00000000000..2b404284c28
--- /dev/null
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -0,0 +1,252 @@
+/*
+ * SEGA Dreamcast keyboard driver
+ * Based on drivers/usb/usbkbd.c
+ * Copyright YAEGASHI Takeshi, 2001
+ * Porting to 2.6 Copyright Adrian McMenamin, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+#include <asm/mach/maple.h>
+
+/* Very simple mutex to ensure proper cleanup */
+static DEFINE_MUTEX(maple_keyb_mutex);
+
+#define NR_SCANCODES 256
+
+MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin");
+MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
+MODULE_LICENSE("GPL");
+
+struct dc_kbd {
+ struct input_dev *dev;
+ unsigned short keycode[NR_SCANCODES];
+ unsigned char new[8];
+ unsigned char old[8];
+};
+
+static const unsigned short dc_kbd_keycode[NR_SCANCODES] = {
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D,
+ KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
+ KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
+ KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
+ KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA,
+ KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6,
+ KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ,
+ KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE,
+ KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
+ KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2,
+ KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
+ KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15,
+ KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
+ KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
+ KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
+ KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN,
+ KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
+ KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
+ KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP,
+ KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED
+};
+
+static void dc_scan_kbd(struct dc_kbd *kbd)
+{
+ struct input_dev *dev = kbd->dev;
+ void *ptr;
+ int code, keycode;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ code = i + 224;
+ keycode = kbd->keycode[code];
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, (kbd->new[0] >> i) & 1);
+ }
+
+ for (i = 2; i < 8; i++) {
+ ptr = memchr(kbd->new + 2, kbd->old[i], 6);
+ code = kbd->old[i];
+ if (code > 3 && ptr == NULL) {
+ keycode = kbd->keycode[code];
+ if (keycode) {
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, 0);
+ } else
+ printk(KERN_DEBUG "maple_keyb: "
+ "Unknown key (scancode %#x) released.",
+ code);
+ }
+ ptr = memchr(kbd->old + 2, kbd->new[i], 6);
+ code = kbd->new[i];
+ if (code > 3 && ptr) {
+ keycode = kbd->keycode[code];
+ if (keycode) {
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, 1);
+ } else
+ printk(KERN_DEBUG "maple_keyb: "
+ "Unknown key (scancode %#x) pressed.",
+ code);
+ }
+ }
+ input_sync(dev);
+ memcpy(kbd->old, kbd->new, 8);
+}
+
+static void dc_kbd_callback(struct mapleq *mq)
+{
+ struct maple_device *mapledev = mq->dev;
+ struct dc_kbd *kbd = mapledev->private_data;
+ unsigned long *buf = mq->recvbuf;
+
+ /*
+ * We should always be getting the lock because the only
+ * time it may be locked if driver is in cleanup phase.
+ */
+ if (likely(mutex_trylock(&maple_keyb_mutex))) {
+
+ if (buf[1] == mapledev->function) {
+ memcpy(kbd->new, buf + 2, 8);
+ dc_scan_kbd(kbd);
+ }
+
+ mutex_unlock(&maple_keyb_mutex);
+ }
+}
+
+static int dc_kbd_connect(struct maple_device *mdev)
+{
+ int i, error;
+ struct dc_kbd *kbd;
+ struct input_dev *dev;
+
+ if (!(mdev->function & MAPLE_FUNC_KEYBOARD))
+ return -EINVAL;
+
+ kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
+ dev = input_allocate_device();
+ if (!kbd || !dev) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ mdev->private_data = kbd;
+
+ kbd->dev = dev;
+ memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode));
+
+ dev->name = mdev->product_name;
+ dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ dev->keycode = kbd->keycode;
+ dev->keycodesize = sizeof (unsigned short);
+ dev->keycodemax = ARRAY_SIZE(kbd->keycode);
+ dev->id.bustype = BUS_HOST;
+ dev->dev.parent = &mdev->dev;
+
+ for (i = 0; i < NR_SCANCODES; i++)
+ __set_bit(dc_kbd_keycode[i], dev->keybit);
+ __clear_bit(KEY_RESERVED, dev->keybit);
+
+ input_set_capability(dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(dev, kbd);
+
+ error = input_register_device(dev);
+ if (error)
+ goto fail;
+
+ /* Maple polling is locked to VBLANK - which may be just 50/s */
+ maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD);
+ return 0;
+
+ fail:
+ input_free_device(dev);
+ kfree(kbd);
+ mdev->private_data = NULL;
+ return error;
+}
+
+static void dc_kbd_disconnect(struct maple_device *mdev)
+{
+ struct dc_kbd *kbd;
+
+ mutex_lock(&maple_keyb_mutex);
+
+ kbd = mdev->private_data;
+ mdev->private_data = NULL;
+ input_unregister_device(kbd->dev);
+ kfree(kbd);
+
+ mutex_unlock(&maple_keyb_mutex);
+}
+
+/* allow the keyboard to be used */
+static int probe_maple_kbd(struct device *dev)
+{
+ struct maple_device *mdev = to_maple_dev(dev);
+ struct maple_driver *mdrv = to_maple_driver(dev->driver);
+ int error;
+
+ error = dc_kbd_connect(mdev);
+ if (error)
+ return error;
+
+ mdev->driver = mdrv;
+ mdev->registered = 1;
+
+ return 0;
+}
+
+static struct maple_driver dc_kbd_driver = {
+ .function = MAPLE_FUNC_KEYBOARD,
+ .connect = dc_kbd_connect,
+ .disconnect = dc_kbd_disconnect,
+ .drv = {
+ .name = "Dreamcast_keyboard",
+ .probe = probe_maple_kbd,
+ },
+};
+
+static int __init dc_kbd_init(void)
+{
+ return maple_driver_register(&dc_kbd_driver.drv);
+}
+
+static void __exit dc_kbd_exit(void)
+{
+ driver_unregister(&dc_kbd_driver.drv);
+}
+
+module_init(dc_kbd_init);
+module_exit(dc_kbd_exit);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 3a228634f10..76f1969552c 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -233,7 +233,7 @@ static void omap_kp_tasklet(unsigned long data)
omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
kp_cur_group = -1;
}
- }
+ }
}
static ssize_t omap_kp_enable_show(struct device *dev,
@@ -318,7 +318,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
keymap = pdata->keymap;
if (pdata->rep)
- set_bit(EV_REP, input_dev->evbit);
+ __set_bit(EV_REP, input_dev->evbit);
if (pdata->delay)
omap_kp->delay = pdata->delay;
@@ -365,9 +365,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
goto err2;
/* setup input device */
- set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
for (i = 0; keymap[i] != 0; i++)
- set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ __set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
input_dev->dev.parent = &pdev->dev;
@@ -377,10 +377,6 @@ static int __init omap_kp_probe(struct platform_device *pdev)
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->keycode = keymap;
- input_dev->keycodesize = sizeof(unsigned int);
- input_dev->keycodemax = pdata->keymapsize;
-
ret = input_register_device(omap_kp->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register omap-keypad input device\n");
@@ -403,15 +399,15 @@ static int __init omap_kp_probe(struct platform_device *pdev)
} else {
for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
- omap_kp_interrupt,
+ omap_kp_interrupt,
IRQF_TRIGGER_FALLING,
- "omap-keypad", omap_kp) < 0)
+ "omap-keypad", omap_kp) < 0)
goto err5;
}
}
return 0;
err5:
- for (i = irq_idx-1; i >=0; i--)
+ for (i = irq_idx - 1; i >=0; i--)
free_irq(row_gpios[i], 0);
err4:
input_unregister_device(omap_kp->input);
@@ -440,9 +436,9 @@ static int omap_kp_remove(struct platform_device *pdev)
if (cpu_is_omap24xx()) {
int i;
for (i = 0; i < omap_kp->cols; i++)
- omap_free_gpio(col_gpios[i]);
+ omap_free_gpio(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
- omap_free_gpio(row_gpios[i]);
+ omap_free_gpio(row_gpios[i]);
free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
}
} else {
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 906bf5e8de8..c19f77fbaf2 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,17 +17,18 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/platform_device.h>
-#include <asm/8253pit.h>
#include <asm/io.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
#ifdef CONFIG_X86
/* Use the global PIT lock ! */
#include <asm/i8253.h>
#else
+#include <asm/8253pit.h>
static DEFINE_SPINLOCK(i8253_lock);
#endif
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 2c5f11a4f6b..64d70a9b714 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -48,11 +48,13 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
};
/*
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index a1804bfdbb8..0117817bf53 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -502,18 +502,23 @@ static void atp_complete(struct urb* urb)
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+ }
+
+ /* Geyser 3 will continue to send packets continually after
+ the first touch unless reinitialised. Do so if it's been
+ idle for a while in order to avoid waking the kernel up
+ several hundred times a second */
- /* Geyser 3 will continue to send packets continually after
- the first touch unless reinitialised. Do so if it's been
- idle for a while in order to avoid waking the kernel up
- several hundred times a second */
- if (!key && atp_is_geyser_3(dev)) {
+ if (atp_is_geyser_3(dev)) {
+ if (!x && !y && !key) {
dev->idlecount++;
if (dev->idlecount == 10) {
dev->valid = 0;
schedule_work(&dev->work);
}
}
+ else
+ dev->idlecount = 0;
}
input_report_key(dev->input, BTN_LEFT, key);
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 43ab6566fb6..c8c7244b48a 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -73,14 +73,11 @@ static void atamouse_interrupt(char *buf)
{
int buttons, dx, dy;
-/* ikbd_mouse_disable(); */
-
buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
#ifdef FIXED_ATARI_JOYSTICK
buttons |= atari_mouse_buttons & 2;
atari_mouse_buttons = buttons;
#endif
-/* ikbd_mouse_rel_pos(); */
/* only relative events get here */
dx = buf[1];
@@ -126,15 +123,16 @@ static int __init atamouse_init(void)
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
return -ENODEV;
- if (!(atamouse_dev = input_allocate_device()))
- return -ENOMEM;
-
if (!(atari_keyb_init()))
return -ENODEV;
+ atamouse_dev = input_allocate_device();
+ if (!atamouse_dev)
+ return -ENOMEM;
+
atamouse_dev->name = "Atari mouse";
atamouse_dev->phys = "atamouse/input0";
- atamouse_dev->id.bustype = BUS_ATARI;
+ atamouse_dev->id.bustype = BUS_HOST;
atamouse_dev->id.vendor = 0x0001;
atamouse_dev->id.product = 0x0002;
atamouse_dev->id.version = 0x0100;
@@ -145,9 +143,11 @@ static int __init atamouse_init(void)
atamouse_dev->open = atamouse_open;
atamouse_dev->close = atamouse_close;
- input_register_device(atamouse_dev);
+ if (input_register_device(atamouse_dev)) {
+ input_free_device(atamouse_dev);
+ return -ENOMEM;
+ }
- printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
return 0;
}
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 608674d0be8..d7de4c53b3d 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -97,6 +97,14 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
.callback = lifebook_set_6byte_proto,
},
{
+ .ident = "CF-72",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
+ },
+ .callback = lifebook_set_serio_phys,
+ .driver_data = "isa0060/serio3",
+ },
+ {
.ident = "Lifebook B142",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
@@ -282,7 +290,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
int lifebook_init(struct psmouse *psmouse)
{
struct input_dev *dev1 = psmouse->dev;
- int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
+ int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
if (lifebook_absolute_mode(psmouse))
return -1;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index b9f0fb2530e..07352575653 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -648,9 +648,10 @@ static int psmouse_extensions(struct psmouse *psmouse,
/*
* Reset to defaults in case the device got confused by extended
- * protocol probes. Note that we do full reset becuase some mice
- * put themselves to sleep when see PSMOUSE_RESET_DIS.
+ * protocol probes. Note that we follow up with full reset because
+ * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
*/
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 9173916b8be..79146d6ed2a 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -61,9 +61,11 @@ struct mousedev {
int open;
int minor;
char name[16];
+ struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
- struct input_handle handle;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
struct list_head mixdev_node;
@@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static DEFINE_MUTEX(mousedev_table_mutex);
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
+static void mixdev_open_devices(void);
+static void mixdev_close_devices(void);
+
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
-static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_touchpad_event(struct input_dev *dev,
+ struct mousedev *mousedev,
+ unsigned int code, int value)
{
int size, tmp;
enum { FRACTION_DENOM = 128 };
switch (code) {
- case ABS_X:
- fx(0) = value;
- if (mousedev->touch && mousedev->pkt_count >= 2) {
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = 256 * 2;
- tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dx;
- mousedev->packet.dx = tmp / FRACTION_DENOM;
- mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
- }
- break;
- case ABS_Y:
- fy(0) = value;
- if (mousedev->touch && mousedev->pkt_count >= 2) {
- /* use X size to keep the same scale */
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = 256 * 2;
- tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dy;
- mousedev->packet.dy = tmp / FRACTION_DENOM;
- mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
- }
- break;
+ case ABS_X:
+ fx(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
+ tmp += mousedev->frac_dx;
+ mousedev->packet.dx = tmp / FRACTION_DENOM;
+ mousedev->frac_dx =
+ tmp - mousedev->packet.dx * FRACTION_DENOM;
+ }
+ break;
+
+ case ABS_Y:
+ fy(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ /* use X size to keep the same scale */
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
+ tmp += mousedev->frac_dy;
+ mousedev->packet.dy = tmp / FRACTION_DENOM;
+ mousedev->frac_dy = tmp -
+ mousedev->packet.dy * FRACTION_DENOM;
+ }
+ break;
}
}
-static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
+ unsigned int code, int value)
{
int size;
switch (code) {
- case ABS_X:
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = xres ? : 1;
- if (value > dev->absmax[ABS_X])
- value = dev->absmax[ABS_X];
- if (value < dev->absmin[ABS_X])
- value = dev->absmin[ABS_X];
- mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
- mousedev->packet.abs_event = 1;
- break;
- case ABS_Y:
- size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
- if (size == 0)
- size = yres ? : 1;
- if (value > dev->absmax[ABS_Y])
- value = dev->absmax[ABS_Y];
- if (value < dev->absmin[ABS_Y])
- value = dev->absmin[ABS_Y];
- mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
- mousedev->packet.abs_event = 1;
- break;
+ case ABS_X:
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = xres ? : 1;
+ if (value > dev->absmax[ABS_X])
+ value = dev->absmax[ABS_X];
+ if (value < dev->absmin[ABS_X])
+ value = dev->absmin[ABS_X];
+ mousedev->packet.x =
+ ((value - dev->absmin[ABS_X]) * xres) / size;
+ mousedev->packet.abs_event = 1;
+ break;
+
+ case ABS_Y:
+ size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+ if (size == 0)
+ size = yres ? : 1;
+ if (value > dev->absmax[ABS_Y])
+ value = dev->absmax[ABS_Y];
+ if (value < dev->absmin[ABS_Y])
+ value = dev->absmin[ABS_Y];
+ mousedev->packet.y = yres -
+ ((value - dev->absmin[ABS_Y]) * yres) / size;
+ mousedev->packet.abs_event = 1;
+ break;
}
}
-static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_rel_event(struct mousedev *mousedev,
+ unsigned int code, int value)
{
switch (code) {
- case REL_X: mousedev->packet.dx += value; break;
- case REL_Y: mousedev->packet.dy -= value; break;
- case REL_WHEEL: mousedev->packet.dz -= value; break;
+ case REL_X:
+ mousedev->packet.dx += value;
+ break;
+
+ case REL_Y:
+ mousedev->packet.dy -= value;
+ break;
+
+ case REL_WHEEL:
+ mousedev->packet.dz -= value;
+ break;
}
}
-static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_key_event(struct mousedev *mousedev,
+ unsigned int code, int value)
{
int index;
switch (code) {
- case BTN_TOUCH:
- case BTN_0:
- case BTN_LEFT: index = 0; break;
- case BTN_STYLUS:
- case BTN_1:
- case BTN_RIGHT: index = 1; break;
- case BTN_2:
- case BTN_FORWARD:
- case BTN_STYLUS2:
- case BTN_MIDDLE: index = 2; break;
- case BTN_3:
- case BTN_BACK:
- case BTN_SIDE: index = 3; break;
- case BTN_4:
- case BTN_EXTRA: index = 4; break;
- default: return;
+
+ case BTN_TOUCH:
+ case BTN_0:
+ case BTN_LEFT: index = 0; break;
+
+ case BTN_STYLUS:
+ case BTN_1:
+ case BTN_RIGHT: index = 1; break;
+
+ case BTN_2:
+ case BTN_FORWARD:
+ case BTN_STYLUS2:
+ case BTN_MIDDLE: index = 2; break;
+
+ case BTN_3:
+ case BTN_BACK:
+ case BTN_SIDE: index = 3; break;
+
+ case BTN_4:
+ case BTN_EXTRA: index = 4; break;
+
+ default: return;
}
if (value) {
@@ -226,19 +257,23 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
}
}
-static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
+static void mousedev_notify_readers(struct mousedev *mousedev,
+ struct mousedev_hw_data *packet)
{
struct mousedev_client *client;
struct mousedev_motion *p;
- unsigned long flags;
+ unsigned int new_head;
int wake_readers = 0;
- list_for_each_entry(client, &mousedev->client_list, node) {
- spin_lock_irqsave(&client->packet_lock, flags);
+ rcu_read_lock();
+ list_for_each_entry_rcu(client, &mousedev->client_list, node) {
+
+ /* Just acquire the lock, interrupts already disabled */
+ spin_lock(&client->packet_lock);
p = &client->packets[client->head];
if (client->ready && p->buttons != mousedev->packet.buttons) {
- unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+ new_head = (client->head + 1) % PACKET_QUEUE_LEN;
if (new_head != client->tail) {
p = &client->packets[client->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
@@ -253,25 +288,29 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
}
client->pos_x += packet->dx;
- client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
+ client->pos_x = client->pos_x < 0 ?
+ 0 : (client->pos_x >= xres ? xres : client->pos_x);
client->pos_y += packet->dy;
- client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
+ client->pos_y = client->pos_y < 0 ?
+ 0 : (client->pos_y >= yres ? yres : client->pos_y);
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
- if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
+ if (p->dx || p->dy || p->dz ||
+ p->buttons != client->last_buttons)
client->ready = 1;
- spin_unlock_irqrestore(&client->packet_lock, flags);
+ spin_unlock(&client->packet_lock);
if (client->ready) {
kill_fasync(&client->fasync, SIGIO, POLL_IN);
wake_readers = 1;
}
}
+ rcu_read_unlock();
if (wake_readers)
wake_up_interruptible(&mousedev->wait);
@@ -281,7 +320,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
- time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
+ time_before(jiffies,
+ mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
@@ -290,7 +330,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
set_bit(0, &mousedev->packet.buttons);
set_bit(0, &mousedev_mix->packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix->packet);
- mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
+ mousedev_notify_readers(mousedev_mix,
+ &mousedev_mix->packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix->packet.buttons);
}
@@ -302,54 +343,61 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
mousedev->touch = jiffies;
}
-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void mousedev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
- case EV_ABS:
- /* Ignore joysticks */
- if (test_bit(BTN_TRIGGER, handle->dev->keybit))
- return;
- if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
- mousedev_touchpad_event(handle->dev, mousedev, code, value);
- else
- mousedev_abs_event(handle->dev, mousedev, code, value);
+ case EV_ABS:
+ /* Ignore joysticks */
+ if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+ return;
- break;
+ if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_event(handle->dev,
+ mousedev, code, value);
+ else
+ mousedev_abs_event(handle->dev, mousedev, code, value);
- case EV_REL:
- mousedev_rel_event(mousedev, code, value);
- break;
+ break;
- case EV_KEY:
- if (value != 2) {
- if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
- mousedev_touchpad_touch(mousedev, value);
- else
- mousedev_key_event(mousedev, code, value);
- }
- break;
+ case EV_REL:
+ mousedev_rel_event(mousedev, code, value);
+ break;
- case EV_SYN:
- if (code == SYN_REPORT) {
- if (mousedev->touch) {
- mousedev->pkt_count++;
- /* Input system eats duplicate events, but we need all of them
- * to do correct averaging so apply present one forward
- */
- fx(0) = fx(1);
- fy(0) = fy(1);
- }
-
- mousedev_notify_readers(mousedev, &mousedev->packet);
- mousedev_notify_readers(mousedev_mix, &mousedev->packet);
-
- mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
- mousedev->packet.abs_event = 0;
+ case EV_KEY:
+ if (value != 2) {
+ if (code == BTN_TOUCH &&
+ test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_touch(mousedev, value);
+ else
+ mousedev_key_event(mousedev, code, value);
+ }
+ break;
+
+ case EV_SYN:
+ if (code == SYN_REPORT) {
+ if (mousedev->touch) {
+ mousedev->pkt_count++;
+ /*
+ * Input system eats duplicate events,
+ * but we need all of them to do correct
+ * averaging so apply present one forward
+ */
+ fx(0) = fx(1);
+ fy(0) = fy(1);
}
- break;
+
+ mousedev_notify_readers(mousedev, &mousedev->packet);
+ mousedev_notify_readers(mousedev_mix, &mousedev->packet);
+
+ mousedev->packet.dx = mousedev->packet.dy =
+ mousedev->packet.dz = 0;
+ mousedev->packet.abs_event = 0;
+ }
+ break;
}
}
@@ -367,41 +415,48 @@ static void mousedev_free(struct device *dev)
{
struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
- mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
}
-static int mixdev_add_device(struct mousedev *mousedev)
+static int mousedev_open_device(struct mousedev *mousedev)
{
- int error;
+ int retval;
- if (mousedev_mix->open) {
- error = input_open_device(&mousedev->handle);
- if (error)
- return error;
+ retval = mutex_lock_interruptible(&mousedev->mutex);
+ if (retval)
+ return retval;
- mousedev->open++;
- mousedev->mixdev_open = 1;
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_open_devices();
+ else if (!mousedev->exist)
+ retval = -ENODEV;
+ else if (!mousedev->open++) {
+ retval = input_open_device(&mousedev->handle);
+ if (retval)
+ mousedev->open--;
}
- get_device(&mousedev->dev);
- list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
-
- return 0;
+ mutex_unlock(&mousedev->mutex);
+ return retval;
}
-static void mixdev_remove_device(struct mousedev *mousedev)
+static void mousedev_close_device(struct mousedev *mousedev)
{
- if (mousedev->mixdev_open) {
- mousedev->mixdev_open = 0;
- if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
- }
+ mutex_lock(&mousedev->mutex);
- list_del_init(&mousedev->mixdev_node);
- put_device(&mousedev->dev);
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_close_devices();
+ else if (mousedev->exist && !--mousedev->open)
+ input_close_device(&mousedev->handle);
+
+ mutex_unlock(&mousedev->mutex);
}
+/*
+ * Open all available devices so they can all be multiplexed in one.
+ * stream. Note that this function is called with mousedev_mix->mutex
+ * held.
+ */
static void mixdev_open_devices(void)
{
struct mousedev *mousedev;
@@ -411,16 +466,19 @@ static void mixdev_open_devices(void)
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (!mousedev->mixdev_open) {
- if (!mousedev->open && mousedev->exist)
- if (input_open_device(&mousedev->handle))
- continue;
+ if (mousedev_open_device(mousedev))
+ continue;
- mousedev->open++;
mousedev->mixdev_open = 1;
}
}
}
+/*
+ * Close all devices that were opened as part of multiplexed
+ * device. Note that this function is called with mousedev_mix->mutex
+ * held.
+ */
static void mixdev_close_devices(void)
{
struct mousedev *mousedev;
@@ -431,33 +489,45 @@ static void mixdev_close_devices(void)
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (mousedev->mixdev_open) {
mousedev->mixdev_open = 0;
- if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
+ mousedev_close_device(mousedev);
}
}
}
+
+static void mousedev_attach_client(struct mousedev *mousedev,
+ struct mousedev_client *client)
+{
+ spin_lock(&mousedev->client_lock);
+ list_add_tail_rcu(&client->node, &mousedev->client_list);
+ spin_unlock(&mousedev->client_lock);
+ synchronize_rcu();
+}
+
+static void mousedev_detach_client(struct mousedev *mousedev,
+ struct mousedev_client *client)
+{
+ spin_lock(&mousedev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&mousedev->client_lock);
+ synchronize_rcu();
+}
+
static int mousedev_release(struct inode *inode, struct file *file)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
mousedev_fasync(-1, file, 0);
-
- list_del(&client->node);
+ mousedev_detach_client(mousedev, client);
kfree(client);
- if (mousedev->minor == MOUSEDEV_MIX)
- mixdev_close_devices();
- else if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
-
+ mousedev_close_device(mousedev);
put_device(&mousedev->dev);
return 0;
}
-
static int mousedev_open(struct inode *inode, struct file *file)
{
struct mousedev_client *client;
@@ -475,12 +545,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
if (i >= MOUSEDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&mousedev_table_mutex);
+ if (error)
+ return error;
mousedev = mousedev_table[i];
+ if (mousedev)
+ get_device(&mousedev->dev);
+ mutex_unlock(&mousedev_table_mutex);
+
if (!mousedev)
return -ENODEV;
- get_device(&mousedev->dev);
-
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
@@ -491,21 +566,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
client->pos_x = xres / 2;
client->pos_y = yres / 2;
client->mousedev = mousedev;
- list_add_tail(&client->node, &mousedev->client_list);
+ mousedev_attach_client(mousedev, client);
- if (mousedev->minor == MOUSEDEV_MIX)
- mixdev_open_devices();
- else if (!mousedev->open++ && mousedev->exist) {
- error = input_open_device(&mousedev->handle);
- if (error)
- goto err_free_client;
- }
+ error = mousedev_open_device(mousedev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ mousedev_detach_client(mousedev, client);
kfree(client);
err_put_mousedev:
put_device(&mousedev->dev);
@@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(int delta, int limit)
return delta > limit ? limit : (delta < -limit ? -limit : delta);
}
-static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client,
+ signed char *ps2_data)
{
- struct mousedev_motion *p;
- unsigned long flags;
-
- spin_lock_irqsave(&client->packet_lock, flags);
- p = &client->packets[client->tail];
+ struct mousedev_motion *p = &client->packets[client->tail];
- ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
+ ps2_data[0] = 0x08 |
+ ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
ps2_data[2] = mousedev_limit_delta(p->dy, 127);
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (client->mode) {
- case MOUSEDEV_EMUL_EXPS:
- ps2_data[3] = mousedev_limit_delta(p->dz, 7);
- p->dz -= ps2_data[3];
- ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
- client->bufsiz = 4;
- break;
-
- case MOUSEDEV_EMUL_IMPS:
- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
- ps2_data[3] = mousedev_limit_delta(p->dz, 127);
- p->dz -= ps2_data[3];
- client->bufsiz = 4;
- break;
-
- case MOUSEDEV_EMUL_PS2:
- default:
- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
- p->dz = 0;
- client->bufsiz = 3;
- break;
+ case MOUSEDEV_EMUL_EXPS:
+ ps2_data[3] = mousedev_limit_delta(p->dz, 7);
+ p->dz -= ps2_data[3];
+ ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+ client->bufsiz = 4;
+ break;
+
+ case MOUSEDEV_EMUL_IMPS:
+ ps2_data[0] |=
+ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+ ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+ p->dz -= ps2_data[3];
+ client->bufsiz = 4;
+ break;
+
+ case MOUSEDEV_EMUL_PS2:
+ default:
+ ps2_data[0] |=
+ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+ p->dz = 0;
+ client->bufsiz = 3;
+ break;
}
if (!p->dx && !p->dy && !p->dz) {
@@ -561,12 +632,56 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat
} else
client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
}
-
- spin_unlock_irqrestore(&client->packet_lock, flags);
}
+static void mousedev_generate_response(struct mousedev_client *client,
+ int command)
+{
+ client->ps2[0] = 0xfa; /* ACK */
+
+ switch (command) {
-static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+ case 0xeb: /* Poll */
+ mousedev_packet(client, &client->ps2[1]);
+ client->bufsiz++; /* account for leading ACK */
+ break;
+
+ case 0xf2: /* Get ID */
+ switch (client->mode) {
+ case MOUSEDEV_EMUL_PS2:
+ client->ps2[1] = 0;
+ break;
+ case MOUSEDEV_EMUL_IMPS:
+ client->ps2[1] = 3;
+ break;
+ case MOUSEDEV_EMUL_EXPS:
+ client->ps2[1] = 4;
+ break;
+ }
+ client->bufsiz = 2;
+ break;
+
+ case 0xe9: /* Get info */
+ client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+ client->bufsiz = 4;
+ break;
+
+ case 0xff: /* Reset */
+ client->impsseq = client->imexseq = 0;
+ client->mode = MOUSEDEV_EMUL_PS2;
+ client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+ client->bufsiz = 3;
+ break;
+
+ default:
+ client->bufsiz = 1;
+ break;
+ }
+ client->buffer = client->bufsiz;
+}
+
+static ssize_t mousedev_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
unsigned char c;
@@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size
if (get_user(c, buffer + i))
return -EFAULT;
+ spin_lock_irq(&client->packet_lock);
+
if (c == mousedev_imex_seq[client->imexseq]) {
if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
client->imexseq = 0;
@@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size
} else
client->impsseq = 0;
- client->ps2[0] = 0xfa;
-
- switch (c) {
-
- case 0xeb: /* Poll */
- mousedev_packet(client, &client->ps2[1]);
- client->bufsiz++; /* account for leading ACK */
- break;
-
- case 0xf2: /* Get ID */
- switch (client->mode) {
- case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
- case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
- case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
- }
- client->bufsiz = 2;
- break;
-
- case 0xe9: /* Get info */
- client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
- client->bufsiz = 4;
- break;
-
- case 0xff: /* Reset */
- client->impsseq = client->imexseq = 0;
- client->mode = MOUSEDEV_EMUL_PS2;
- client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
- client->bufsiz = 3;
- break;
-
- default:
- client->bufsiz = 1;
- break;
- }
+ mousedev_generate_response(client, c);
- client->buffer = client->bufsiz;
+ spin_unlock_irq(&client->packet_lock);
}
kill_fasync(&client->fasync, SIGIO, POLL_IN);
-
wake_up_interruptible(&client->mousedev->wait);
return count;
}
-static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
+ struct mousedev *mousedev = client->mousedev;
+ signed char data[sizeof(client->ps2)];
int retval = 0;
- if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
+ if (!client->ready && !client->buffer && mousedev->exist &&
+ (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(client->mousedev->wait,
- !client->mousedev->exist || client->ready || client->buffer);
-
+ retval = wait_event_interruptible(mousedev->wait,
+ !mousedev->exist || client->ready || client->buffer);
if (retval)
return retval;
- if (!client->mousedev->exist)
+ if (!mousedev->exist)
return -ENODEV;
+ spin_lock_irq(&client->packet_lock);
+
if (!client->buffer && client->ready) {
mousedev_packet(client, client->ps2);
client->buffer = client->bufsiz;
@@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun
if (count > client->buffer)
count = client->buffer;
+ memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
client->buffer -= count;
- if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
+ spin_unlock_irq(&client->packet_lock);
+
+ if (copy_to_user(buffer, data, count))
return -EFAULT;
return count;
@@ -692,6 +783,60 @@ static const struct file_operations mousedev_fops = {
.fasync = mousedev_fasync,
};
+static int mousedev_install_chrdev(struct mousedev *mousedev)
+{
+ mousedev_table[mousedev->minor] = mousedev;
+ return 0;
+}
+
+static void mousedev_remove_chrdev(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev_table_mutex);
+ mousedev_table[mousedev->minor] = NULL;
+ mutex_unlock(&mousedev_table_mutex);
+}
+
+/*
+ * Mark device non-existent. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void mousedev_mark_dead(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev->mutex);
+ mousedev->exist = 0;
+ mutex_unlock(&mousedev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void mousedev_hangup(struct mousedev *mousedev)
+{
+ struct mousedev_client *client;
+
+ spin_lock(&mousedev->client_lock);
+ list_for_each_entry(client, &mousedev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&mousedev->client_lock);
+
+ wake_up_interruptible(&mousedev->wait);
+}
+
+static void mousedev_cleanup(struct mousedev *mousedev)
+{
+ struct input_handle *handle = &mousedev->handle;
+
+ mousedev_mark_dead(mousedev);
+ mousedev_hangup(mousedev);
+ mousedev_remove_chrdev(mousedev);
+
+ /* mousedev is marked dead so no one else accesses mousedev->open */
+ if (mousedev->open)
+ input_close_device(handle);
+}
+
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
int minor)
@@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
INIT_LIST_HEAD(&mousedev->client_list);
INIT_LIST_HEAD(&mousedev->mixdev_node);
+ spin_lock_init(&mousedev->client_lock);
+ mutex_init(&mousedev->mutex);
+ lockdep_set_subclass(&mousedev->mutex,
+ minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
init_waitqueue_head(&mousedev->wait);
if (minor == MOUSEDEV_MIX)
@@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
mousedev->dev.release = mousedev_free;
device_initialize(&mousedev->dev);
- mousedev_table[minor] = mousedev;
+ if (minor != MOUSEDEV_MIX) {
+ error = input_register_handle(&mousedev->handle);
+ if (error)
+ goto err_free_mousedev;
+ }
+
+ error = mousedev_install_chrdev(mousedev);
+ if (error)
+ goto err_unregister_handle;
error = device_add(&mousedev->dev);
if (error)
- goto err_free_mousedev;
+ goto err_cleanup_mousedev;
return mousedev;
+ err_cleanup_mousedev:
+ mousedev_cleanup(mousedev);
+ err_unregister_handle:
+ if (minor != MOUSEDEV_MIX)
+ input_unregister_handle(&mousedev->handle);
err_free_mousedev:
put_device(&mousedev->dev);
err_out:
@@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
static void mousedev_destroy(struct mousedev *mousedev)
{
- struct mousedev_client *client;
-
device_del(&mousedev->dev);
- mousedev->exist = 0;
+ mousedev_cleanup(mousedev);
+ if (mousedev->minor != MOUSEDEV_MIX)
+ input_unregister_handle(&mousedev->handle);
+ put_device(&mousedev->dev);
+}
- if (mousedev->open) {
- input_close_device(&mousedev->handle);
- list_for_each_entry(client, &mousedev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&mousedev->wait);
+static int mixdev_add_device(struct mousedev *mousedev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&mousedev_mix->mutex);
+ if (retval)
+ return retval;
+
+ if (mousedev_mix->open) {
+ retval = mousedev_open_device(mousedev);
+ if (retval)
+ goto out;
+
+ mousedev->mixdev_open = 1;
}
+ get_device(&mousedev->dev);
+ list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+ out:
+ mutex_unlock(&mousedev_mix->mutex);
+ return retval;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev_mix->mutex);
+
+ if (mousedev->mixdev_open) {
+ mousedev->mixdev_open = 0;
+ mousedev_close_device(mousedev);
+ }
+
+ list_del_init(&mousedev->mixdev_node);
+ mutex_unlock(&mousedev_mix->mutex);
+
put_device(&mousedev->dev);
}
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+static int mousedev_connect(struct input_handler *handler,
+ struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
int minor;
int error;
- for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+ for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
+ if (!mousedev_table[minor])
+ break;
+
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return -ENFILE;
@@ -779,21 +976,13 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
- error = input_register_handle(&mousedev->handle);
- if (error)
- goto err_delete_mousedev;
-
error = mixdev_add_device(mousedev);
- if (error)
- goto err_unregister_handle;
+ if (error) {
+ mousedev_destroy(mousedev);
+ return error;
+ }
return 0;
-
- err_unregister_handle:
- input_unregister_handle(&mousedev->handle);
- err_delete_mousedev:
- device_unregister(&mousedev->dev);
- return error;
}
static void mousedev_disconnect(struct input_handle *handle)
@@ -801,33 +990,42 @@ static void mousedev_disconnect(struct input_handle *handle)
struct mousedev *mousedev = handle->private;
mixdev_remove_device(mousedev);
- input_unregister_handle(handle);
mousedev_destroy(mousedev);
}
static const struct input_device_id mousedev_ids[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
.relbit = { BIT(REL_X) | BIT(REL_Y) },
- }, /* A mouse like device, at least one button, two relative axes */
+ }, /* A mouse like device, at least one button,
+ two relative axes */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
.relbit = { BIT(REL_WHEEL) },
}, /* A separate scrollwheel */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
- }, /* A tablet like device, at least touch detection, two absolute axes */
+ }, /* A tablet like device, at least touch detection,
+ two absolute axes */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
.keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
+ .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
+ BIT(ABS_TOOL_WIDTH) },
}, /* A touchpad */
{ }, /* Terminating entry */
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index c2eea2767e1..11dafc0ee99 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -385,6 +385,8 @@ static int i8042_enable_kbd_port(void)
i8042_ctr |= I8042_CTR_KBDINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ i8042_ctr &= ~I8042_CTR_KBDINT;
+ i8042_ctr |= I8042_CTR_KBDDIS;
printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
return -EIO;
}
@@ -402,6 +404,8 @@ static int i8042_enable_aux_port(void)
i8042_ctr |= I8042_CTR_AUXINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ i8042_ctr &= ~I8042_CTR_AUXINT;
+ i8042_ctr |= I8042_CTR_AUXDIS;
printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
return -EIO;
}
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 372ca493119..b3bc15acd3f 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
#define SERIO_ADD_UEVENT_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct serio *serio;
- int i = 0;
- int len = 0;
if (!dev)
return -ENODEV;
@@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
- envp[i] = NULL;
return 0;
}
@@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
#else
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index f929fcdbae2..e3e0baa1a15 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -126,6 +126,16 @@ config TOUCHSCREEN_HP600
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
+config TOUCHSCREEN_HP7XX
+ tristate "HP Jornada 710/720/728 touchscreen"
+ depends on SA1100_JORNADA720_SSP
+ help
+ Say Y here if you have a HP Jornada 710/720/728 and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_ts.
+
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
@@ -191,6 +201,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- Gunze AHL61
- DMC TSC-10/25
- IRTOUCHSYSTEMS/UNITOP
+ - IdealTEK URTC1000
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -238,4 +249,14 @@ config TOUCHSCREEN_USB_IRTOUCH
bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
+config TOUCHSCREEN_USB_IDEALTEK
+ default y
+ bool "IdealTEK URTC1000 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GENERAL_TOUCH
+ default y
+ bool "GeneralTouch Touchscreen device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 5de8933c499..35d4097df35 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 96581d08774..51ae4fb7d12 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -83,7 +83,7 @@ struct ads7846 {
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
- struct class_device *hwmon;
+ struct device *hwmon;
#endif
u16 model;
@@ -369,7 +369,7 @@ static struct attribute_group ads7845_attr_group = {
static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
{
- struct class_device *hwmon;
+ struct device *hwmon;
int err;
/* hwmon sensors need a reference voltage */
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
new file mode 100644
index 00000000000..42a1c9a1940
--- /dev/null
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -0,0 +1,182 @@
+/*
+ * drivers/input/touchscreen/jornada720_ts.c
+ *
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * HP Jornada 710/720/729 Touchscreen Driver
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/jornada720.h>
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
+MODULE_LICENSE("GPLv2");
+
+struct jornada_ts {
+ struct input_dev *dev;
+ int x_data[4]; /* X sample values */
+ int y_data[4]; /* Y sample values */
+};
+
+static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
+{
+
+ /* 3 low word X samples */
+ jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
+
+ /* 3 low word Y samples */
+ jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
+
+ /* combined x samples bits */
+ jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
+
+ /* combined y samples bits */
+ jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
+}
+
+static int jornada720_ts_average(int coords[4])
+{
+ int coord, high_bits = coords[3];
+
+ coord = coords[0] | ((high_bits & 0x03) << 8);
+ coord += coords[1] | ((high_bits & 0x0c) << 6);
+ coord += coords[2] | ((high_bits & 0x30) << 4);
+
+ return coord / 3;
+}
+
+static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+ struct input_dev *input = jornada_ts->dev;
+ int x, y;
+
+ /* If GPIO_GPIO9 is set to high then report pen up */
+ if (GPLR & GPIO_GPIO(9)) {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_sync(input);
+ } else {
+ jornada_ssp_start();
+
+ /* proper reply to request is always TXDUMMY */
+ if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) {
+ jornada720_ts_collect_data(jornada_ts);
+
+ x = jornada720_ts_average(jornada_ts->x_data);
+ y = jornada720_ts_average(jornada_ts->y_data);
+
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_sync(input);
+ }
+
+ jornada_ssp_end();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit jornada720_ts_probe(struct platform_device *pdev)
+{
+ struct jornada_ts *jornada_ts;
+ struct input_dev *input_dev;
+ int error;
+
+ jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
+ input_dev = input_allocate_device();
+
+ if (!jornada_ts || !input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ platform_set_drvdata(pdev, jornada_ts);
+
+ jornada_ts->dev = input_dev;
+
+ input_dev->name = "HP Jornada 7xx Touchscreen";
+ input_dev->phys = "jornadats/input0";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
+
+ error = request_irq(IRQ_GPIO9,
+ jornada720_ts_interrupt,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "HP7XX Touchscreen driver", pdev);
+ if (error) {
+ printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
+ goto fail1;
+ }
+
+ error = input_register_device(jornada_ts->dev);
+ if (error)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ free_irq(IRQ_GPIO9, pdev);
+ fail1:
+ platform_set_drvdata(pdev, NULL);
+ input_free_device(input_dev);
+ kfree(jornada_ts);
+ return error;
+}
+
+static int __devexit jornada720_ts_remove(struct platform_device *pdev)
+{
+ struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+
+ free_irq(IRQ_GPIO9, pdev);
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(jornada_ts->dev);
+ kfree(jornada_ts);
+
+ return 0;
+}
+
+static struct platform_driver jornada720_ts_driver = {
+ .probe = jornada720_ts_probe,
+ .remove = __devexit_p(jornada720_ts_remove),
+ .driver = {
+ .name = "jornada_ts",
+ },
+};
+
+static int __init jornada720_ts_init(void)
+{
+ return platform_driver_register(&jornada720_ts_driver);
+}
+
+static void __exit jornada720_ts_exit(void)
+{
+ platform_driver_unregister(&jornada720_ts_driver);
+}
+
+module_init(jornada720_ts_init);
+module_exit(jornada720_ts_exit);
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 36f94401915..86aed64ec0f 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -130,8 +130,7 @@ static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel)
if (val & UCB_ADC_DAT_VALID)
break;
/* yield to other processes */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
}
return UCB_ADC_DAT_VALUE(val);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 741f6c6f1e5..9fb3d5c3099 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -10,6 +10,7 @@
* - Gunze AHL61
* - DMC TSC-10/25
* - IRTOUCHSYSTEMS/UNITOP
+ * - IdealTEK URTC1000
*
* Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -92,7 +93,7 @@ struct usbtouch_usb {
};
-#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO)
+#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK)
#define MULTI_PACKET
#endif
@@ -112,6 +113,8 @@ enum {
DEVTYPE_GUNZE,
DEVTYPE_DMC_TSC10,
DEVTYPE_IRTOUCH,
+ DEVTYPE_IDEALTEK,
+ DEVTYPE_GENERAL_TOUCH,
};
static struct usb_device_id usbtouch_devices[] = {
@@ -157,6 +160,14 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
+#endif
+
{}
};
@@ -396,7 +407,8 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
return ret;
- if (buf[0] != 0x06 || buf[1] != 0x00)
+ if ((buf[0] != 0x06 || buf[1] != 0x00) &&
+ (buf[0] != 0x15 || buf[1] != 0x01))
return -ENODEV;
/* start sending data */
@@ -438,6 +450,57 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
/*****************************************************************************
+ * IdealTEK URTC1000 Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+static int idealtek_get_pkt_len(unsigned char *buf, int len)
+{
+ if (buf[0] & 0x80)
+ return 5;
+ if (buf[0] == 0x01)
+ return len;
+ return 0;
+}
+
+static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ switch (pkt[0] & 0x98) {
+ case 0x88:
+ /* touch data in IdealTEK mode */
+ dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
+ dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
+ dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+ return 1;
+
+ case 0x98:
+ /* touch data in MT emulation mode */
+ dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
+ dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
+ dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * General Touch Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
+ dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
+ dev->press = pkt[5] & 0xff;
+ dev->touch = pkt[0] & 0x01;
+
+ return 1;
+}
+#endif
+
+/*****************************************************************************
* the different device descriptors
*/
static struct usbtouch_device_info usbtouch_dev_info[] = {
@@ -537,6 +600,32 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = irtouch_read_data,
},
#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ [DEVTYPE_IDEALTEK] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .flags = USBTOUCH_FLG_BUFFER,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = idealtek_get_pkt_len,
+ .read_data = idealtek_read_data,
+ },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ [DEVTYPE_GENERAL_TOUCH] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0500,
+ .min_yc = 0x0,
+ .max_yc = 0x0500,
+ .rept_size = 7,
+ .read_data = general_touch_read_data,
+ }
+#endif
+
};
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
deleted file mode 100644
index d2f882e98e5..00000000000
--- a/drivers/input/tsdev.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
- *
- * Copyright (c) 2001 "Crazy" james Simmons
- *
- * Compaq touchscreen protocol driver. The protocol emulated by this driver
- * is obsolete; for new programs use the tslib library which can read directly
- * from evdev and perform dejittering, variance filtering and calibration -
- * all in user space, not at kernel level. The meaning of this driver is
- * to allow usage of newer input drivers with old applications that use the
- * old /dev/h3600_ts and /dev/h3600_tsraw devices.
- *
- * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
- * Fixed to actually work, not just output random numbers.
- * Added support for both h3600_ts and h3600_tsraw protocol
- * emulation.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <jsimmons@infradead.org>.
- */
-
-#define TSDEV_MINOR_BASE 128
-#define TSDEV_MINORS 32
-/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
-#define TSDEV_MINOR_MASK 15
-#define TSDEV_BUFFER_SIZE 64
-
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/major.h>
-#include <linux/random.h>
-#include <linux/time.h>
-#include <linux/device.h>
-
-#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
-#define CONFIG_INPUT_TSDEV_SCREEN_X 240
-#endif
-#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
-#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
-#endif
-
-/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
- * devices. The first one must output X/Y data in 'cooked' format, e.g.
- * filtered, dejittered and calibrated. Second device just outputs raw
- * data received from the hardware.
- *
- * This driver doesn't support filtering and dejittering; it supports only
- * calibration. Filtering and dejittering must be done in the low-level
- * driver, if needed, because it may gain additional benefits from knowing
- * the low-level details, the nature of noise and so on.
- *
- * The driver precomputes a calibration matrix given the initial xres and
- * yres values (quite innacurate for most touchscreens) that will result
- * in a more or less expected range of output values. The driver supports
- * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
- * new one, supposedly generated from the values taken from the raw device.
- */
-
-MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
-MODULE_DESCRIPTION("Input driver to touchscreen converter");
-MODULE_LICENSE("GPL");
-
-static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
-module_param(xres, uint, 0);
-MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
-
-static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
-module_param(yres, uint, 0);
-MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
-
-/* From Compaq's Touch Screen Specification version 0.2 (draft) */
-struct ts_event {
- short pressure;
- short x;
- short y;
- short millisecs;
-};
-
-struct ts_calibration {
- int xscale;
- int xtrans;
- int yscale;
- int ytrans;
- int xyswap;
-};
-
-struct tsdev {
- int exist;
- int open;
- int minor;
- char name[8];
- struct input_handle handle;
- wait_queue_head_t wait;
- struct list_head client_list;
- struct device dev;
-
- int x, y, pressure;
- struct ts_calibration cal;
-};
-
-struct tsdev_client {
- struct fasync_struct *fasync;
- struct list_head node;
- struct tsdev *tsdev;
- int head, tail;
- struct ts_event event[TSDEV_BUFFER_SIZE];
- int raw;
-};
-
-/* The following ioctl codes are defined ONLY for backward compatibility.
- * Don't use tsdev for new developement; use the tslib library instead.
- * Touchscreen calibration is a fully userspace task.
- */
-/* Use 'f' as magic number */
-#define IOC_H3600_TS_MAGIC 'f'
-#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
-#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
-
-static struct tsdev *tsdev_table[TSDEV_MINORS/2];
-
-static int tsdev_fasync(int fd, struct file *file, int on)
-{
- struct tsdev_client *client = file->private_data;
- int retval;
-
- retval = fasync_helper(fd, file, on, &client->fasync);
- return retval < 0 ? retval : 0;
-}
-
-static int tsdev_open(struct inode *inode, struct file *file)
-{
- int i = iminor(inode) - TSDEV_MINOR_BASE;
- struct tsdev_client *client;
- struct tsdev *tsdev;
- int error;
-
- printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
- "for removal.\nSee Documentation/feature-removal-schedule.txt "
- "for details.\n");
-
- if (i >= TSDEV_MINORS)
- return -ENODEV;
-
- tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
- if (!tsdev || !tsdev->exist)
- return -ENODEV;
-
- get_device(&tsdev->dev);
-
- client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
- if (!client) {
- error = -ENOMEM;
- goto err_put_tsdev;
- }
-
- client->tsdev = tsdev;
- client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
- list_add_tail(&client->node, &tsdev->client_list);
-
- if (!tsdev->open++ && tsdev->exist) {
- error = input_open_device(&tsdev->handle);
- if (error)
- goto err_free_client;
- }
-
- file->private_data = client;
- return 0;
-
- err_free_client:
- list_del(&client->node);
- kfree(client);
- err_put_tsdev:
- put_device(&tsdev->dev);
- return error;
-}
-
-static void tsdev_free(struct device *dev)
-{
- struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
-
- tsdev_table[tsdev->minor] = NULL;
- kfree(tsdev);
-}
-
-static int tsdev_release(struct inode *inode, struct file *file)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
-
- tsdev_fasync(-1, file, 0);
-
- list_del(&client->node);
- kfree(client);
-
- if (!--tsdev->open && tsdev->exist)
- input_close_device(&tsdev->handle);
-
- put_device(&tsdev->dev);
-
- return 0;
-}
-
-static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
- loff_t *ppos)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
- int retval = 0;
-
- if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
-
- retval = wait_event_interruptible(tsdev->wait,
- client->head != client->tail || !tsdev->exist);
- if (retval)
- return retval;
-
- if (!tsdev->exist)
- return -ENODEV;
-
- while (client->head != client->tail &&
- retval + sizeof (struct ts_event) <= count) {
- if (copy_to_user (buffer + retval, client->event + client->tail,
- sizeof (struct ts_event)))
- return -EFAULT;
- client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
- retval += sizeof (struct ts_event);
- }
-
- return retval;
-}
-
-/* No kernel lock - fine */
-static unsigned int tsdev_poll(struct file *file, poll_table *wait)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
-
- poll_wait(file, &tsdev->wait, wait);
- return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
- (tsdev->exist ? 0 : (POLLHUP | POLLERR));
-}
-
-static int tsdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
- int retval = 0;
-
- switch (cmd) {
- case TS_GET_CAL:
- if (copy_to_user((void __user *)arg, &tsdev->cal,
- sizeof (struct ts_calibration)))
- retval = -EFAULT;
- break;
-
- case TS_SET_CAL:
- if (copy_from_user(&tsdev->cal, (void __user *)arg,
- sizeof (struct ts_calibration)))
- retval = -EFAULT;
- break;
-
- default:
- retval = -EINVAL;
- break;
- }
-
- return retval;
-}
-
-static const struct file_operations tsdev_fops = {
- .owner = THIS_MODULE,
- .open = tsdev_open,
- .release = tsdev_release,
- .read = tsdev_read,
- .poll = tsdev_poll,
- .fasync = tsdev_fasync,
- .ioctl = tsdev_ioctl,
-};
-
-static void tsdev_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value)
-{
- struct tsdev *tsdev = handle->private;
- struct tsdev_client *client;
- struct timeval time;
-
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- tsdev->x = value;
- break;
-
- case ABS_Y:
- tsdev->y = value;
- break;
-
- case ABS_PRESSURE:
- if (value > handle->dev->absmax[ABS_PRESSURE])
- value = handle->dev->absmax[ABS_PRESSURE];
- value -= handle->dev->absmin[ABS_PRESSURE];
- if (value < 0)
- value = 0;
- tsdev->pressure = value;
- break;
- }
- break;
-
- case EV_REL:
- switch (code) {
- case REL_X:
- tsdev->x += value;
- if (tsdev->x < 0)
- tsdev->x = 0;
- else if (tsdev->x > xres)
- tsdev->x = xres;
- break;
-
- case REL_Y:
- tsdev->y += value;
- if (tsdev->y < 0)
- tsdev->y = 0;
- else if (tsdev->y > yres)
- tsdev->y = yres;
- break;
- }
- break;
-
- case EV_KEY:
- if (code == BTN_TOUCH || code == BTN_MOUSE) {
- switch (value) {
- case 0:
- tsdev->pressure = 0;
- break;
-
- case 1:
- if (!tsdev->pressure)
- tsdev->pressure = 1;
- break;
- }
- }
- break;
- }
-
- if (type != EV_SYN || code != SYN_REPORT)
- return;
-
- list_for_each_entry(client, &tsdev->client_list, node) {
- int x, y, tmp;
-
- do_gettimeofday(&time);
- client->event[client->head].millisecs = time.tv_usec / 1000;
- client->event[client->head].pressure = tsdev->pressure;
-
- x = tsdev->x;
- y = tsdev->y;
-
- /* Calibration */
- if (!client->raw) {
- x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
- y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
- if (tsdev->cal.xyswap) {
- tmp = x; x = y; y = tmp;
- }
- }
-
- client->event[client->head].x = x;
- client->event[client->head].y = y;
- client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
- wake_up_interruptible(&tsdev->wait);
-}
-
-static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
-{
- struct tsdev *tsdev;
- int minor, delta;
- int error;
-
- for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
- if (minor >= TSDEV_MINORS / 2) {
- printk(KERN_ERR
- "tsdev: You have way too many touchscreens\n");
- return -ENFILE;
- }
-
- tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
- if (!tsdev)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&tsdev->client_list);
- init_waitqueue_head(&tsdev->wait);
-
- tsdev->exist = 1;
- tsdev->minor = minor;
- tsdev->handle.dev = dev;
- tsdev->handle.name = tsdev->name;
- tsdev->handle.handler = handler;
- tsdev->handle.private = tsdev;
- snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
-
- /* Precompute the rough calibration matrix */
- delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
- if (delta == 0)
- delta = 1;
- tsdev->cal.xscale = (xres << 8) / delta;
- tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
-
- delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
- if (delta == 0)
- delta = 1;
- tsdev->cal.yscale = (yres << 8) / delta;
- tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
-
- snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
- "ts%d", minor);
- tsdev->dev.class = &input_class;
- tsdev->dev.parent = &dev->dev;
- tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
- tsdev->dev.release = tsdev_free;
- device_initialize(&tsdev->dev);
-
- tsdev_table[minor] = tsdev;
-
- error = device_add(&tsdev->dev);
- if (error)
- goto err_free_tsdev;
-
- error = input_register_handle(&tsdev->handle);
- if (error)
- goto err_delete_tsdev;
-
- return 0;
-
- err_delete_tsdev:
- device_del(&tsdev->dev);
- err_free_tsdev:
- put_device(&tsdev->dev);
- return error;
-}
-
-static void tsdev_disconnect(struct input_handle *handle)
-{
- struct tsdev *tsdev = handle->private;
- struct tsdev_client *client;
-
- input_unregister_handle(handle);
- device_del(&tsdev->dev);
-
- tsdev->exist = 0;
-
- if (tsdev->open) {
- input_close_device(handle);
- list_for_each_entry(client, &tsdev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&tsdev->wait);
- }
-
- put_device(&tsdev->dev);
-}
-
-static const struct input_device_id tsdev_ids[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
- .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
- .relbit = { BIT(REL_X) | BIT(REL_Y) },
- }, /* A mouse like device, at least one button, two relative axes */
-
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
- .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
- }, /* A tablet like device, at least touch detection, two absolute axes */
-
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_ABS) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
- }, /* A tablet like device with several gradations of pressure */
-
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, tsdev_ids);
-
-static struct input_handler tsdev_handler = {
- .event = tsdev_event,
- .connect = tsdev_connect,
- .disconnect = tsdev_disconnect,
- .fops = &tsdev_fops,
- .minor = TSDEV_MINOR_BASE,
- .name = "tsdev",
- .id_table = tsdev_ids,
-};
-
-static int __init tsdev_init(void)
-{
- return input_register_handler(&tsdev_handler);
-}
-
-static void __exit tsdev_exit(void)
-{
- input_unregister_handler(&tsdev_handler);
-}
-
-module_init(tsdev_init);
-module_exit(tsdev_exit);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index b04a178e502..f8b79783c8b 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -20,7 +20,6 @@
#include <linux/isapnp.h>
#include <linux/interrupt.h>
-extern const char *CardType[];
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
@@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
{
u_int val, ver;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, avm_pci_rev);
- printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_FRITZPCI)
- return (0);
- if (card->para[1]) {
- /* old manual method */
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_avm_d = NULL;
- if ((pnp_avm_c = pnp_find_card(
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (!cs->irq) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return(0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
- }
- } else {
- printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
- }
-#endif
-#ifdef CONFIG_PCI
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
- if (pci_enable_device(dev_avm))
- return(0);
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
-ready:
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
@@ -860,3 +774,137 @@ ready:
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ struct pnp_dev *pnp_avm_d = NULL;
+
+ if (!isapnp_present())
+ return(1); /* no-op: success */
+
+ if ((pnp_avm_c = pnp_find_card(
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+ if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+ int err;
+
+ pnp_disable_dev(pnp_avm_d);
+ err = pnp_activate_dev(pnp_avm_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ cs->hw.avm.cfg_reg =
+ pnp_port_start(pnp_avm_d, 0);
+ cs->irq = pnp_irq(pnp_avm_d, 0);
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPnP:No IRQ\n");
+ return(0);
+ }
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPnP:No IO address\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PNP;
+
+ return (2); /* goto 'ready' label */
+ }
+ }
+
+ return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+ if (pci_enable_device(dev_avm))
+ return(0);
+
+ cs->irq = dev_avm->irq;
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+
+ cs->subtyp = AVM_FRITZ_PCI;
+ } else {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+
+ cs->irq_flags |= IRQF_SHARED;
+
+ return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int rc;
+
+ strcpy(tmp, avm_pci_rev);
+ printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+ if (cs->typ != ISDN_CTYPE_FRITZPCI)
+ return (0);
+
+ if (card->para[1]) {
+ /* old manual method */
+ cs->hw.avm.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
+ }
+
+ rc = avm_pnp_setup(cs);
+ if (rc < 1)
+ return (0);
+ if (rc == 2)
+ goto ready;
+
+ rc = avm_pci_setup(cs);
+ if (rc < 1)
+ return (0);
+
+ready:
+ return avm_setup_rest(cs);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 6339bb443f6..99ef3b43fcd 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -20,8 +20,6 @@
#include <linux/pci.h>
#include "bkm_ax.h"
-#ifdef CONFIG_PCI
-
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
@@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0;
static u_char pci_device_fn __devinitdata = 0;
static u_char pci_irq __devinitdata = 0;
-#endif /* CONFIG_PCI */
-
int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
-#ifdef CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
@@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card)
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
-#else
- printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
}
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6eebeb441bf..82674507874 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -25,8 +25,6 @@
#include <linux/pci.h>
#include <linux/isapnp.h>
-extern const char *CardType[];
-
static const char *Diva_revision = "$Revision: 1.33.2.6 $";
#define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
{
- int bytecnt = 8;
+ int bytecnt;
u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Diva_revision);
- printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
- return(0);
- cs->hw.diva.status = 0;
- if (card->para[1]) {
- cs->hw.diva.ctrl_reg = 0;
- cs->hw.diva.cfg_reg = card->para[1];
- val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
- cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if ((val == 1) || (val==2)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
- }
- cs->irq = card->para[0];
- } else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.diva.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl =
- card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac =
- card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_HSCX_ADR;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
- }
- }
-#endif
-#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
- if (pci_enable_device(dev_diva))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
- if (pci_enable_device(dev_diva_u))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva_u->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
- if (pci_enable_device(dev_diva201))
- return(0);
- cs->subtyp = DIVA_IPAC_PCI;
- cs->irq = dev_diva201->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
- if (pci_enable_device(dev_diva202))
- return(0);
- cs->subtyp = DIVA_IPACX_PCI;
- cs->irq = dev_diva202->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
- } else {
- printk(KERN_WARNING "Diva: No PCI card found\n");
- return(0);
- }
-
- if (!cs->irq) {
- printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
-
- if (!cs->hw.diva.cfg_reg) {
- printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI) ) {
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = 0;
- cs->hw.diva.hscx = 0;
- cs->hw.diva.isac_adr = 0;
- cs->hw.diva.hscx_adr = 0;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- bytecnt = 0;
- } else {
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- bytecnt = 32;
- }
- }
-#ifdef __ISAPNP__
-ready:
-#endif
+ if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+ bytecnt = 8;
+ else
+ bytecnt = 32;
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@ ready:
if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %lx-%lx already in use\n",
- CardType[card->typ],
+ "diva",
cs->hw.diva.cfg_reg,
cs->hw.diva.cfg_reg + bytecnt);
iounmap_diva(cs);
@@ -1206,3 +994,290 @@ ready:
}
return (1);
}
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ if (!card->para[1])
+ return (-1); /* card not found; continue search */
+
+ cs->hw.diva.ctrl_reg = 0;
+ cs->hw.diva.cfg_reg = card->para[1];
+ val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+ cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+ if ((val == 1) || (val==2)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ }
+ cs->irq = card->para[0];
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return (-1); /* card not found; continue search */
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.diva.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl =
+ card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_HSCX_ADR;
+ }
+ return (1); /* card found */
+ } else {
+ printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c=NULL;
+ }
+
+ return (-1); /* card not found; continue search */
+}
+
+#else /* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+ if (pci_enable_device(dev_diva))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+ if (pci_enable_device(dev_diva_u))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva_u->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+ if (pci_enable_device(dev_diva201))
+ return(0);
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+ } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+ if (pci_enable_device(dev_diva202))
+ return(0);
+ cs->subtyp = DIVA_IPACX_PCI;
+ cs->irq = dev_diva202->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+ } else {
+ return (-1); /* card not found; continue search */
+ }
+
+ if (!cs->irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+
+ if (!cs->hw.diva.cfg_reg) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+
+ if ((cs->subtyp == DIVA_IPAC_PCI) ||
+ (cs->subtyp == DIVA_IPACX_PCI) ) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+ cs->hw.diva.isac_adr = 0;
+ cs->hw.diva.hscx_adr = 0;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+ }
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+ int rc, have_card = 0;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Diva_revision);
+ printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+ return(0);
+ cs->hw.diva.status = 0;
+
+ rc = setup_diva_isa(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_isapnp(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_pci(card);
+ if (!rc)
+ return rc;
+ if (rc > 0)
+ have_card = 1;
+
+ready:
+ if (!have_card) {
+ printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+ return(0);
+ }
+
+ return setup_diva_common(card->cs);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index fab3e4ea059..948a9b290fd 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -30,8 +30,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
-extern const char *CardType[];
-
static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
static const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs)
return (CARD_portlist[i]);
}
-static struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
+ printk(KERN_WARNING
+ "Elsa: no Elsa Microlink at %#lx\n",
+ cs->hw.elsa.base);
+ return (0);
+ }
+ } else
+ cs->hw.elsa.base = probe_elsa(cs);
+
+ if (!cs->hw.elsa.base) {
+ printk(KERN_WARNING
+ "No Elsa Microlink found\n");
+ return (0);
+ }
+
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+ } else {
+ const u_char CARD_IrqTab[8] =
+ {15, 10, 15, 3, 11, 5, 11, 9};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+ }
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+ if (val < 3)
+ val |= 8;
+ val += 'A' - 3;
+ if (val == 'B' || val == 'C')
+ val ^= 1;
+ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ val = 'C';
+ printk(KERN_INFO
+ "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
+ printk(KERN_WARNING
+ "Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
+
+ return (1);
+}
#ifdef __ISAPNP__
static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif /* __ISAPNP__ */
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
{
- int bytecnt;
- u_char val;
struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, Elsa_revision);
- printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
- cs->hw.elsa.ctrl_reg = 0;
- cs->hw.elsa.status = 0;
- cs->hw.elsa.MFlag = 0;
- cs->subtyp = 0;
- if (cs->typ == ISDN_CTYPE_ELSA) {
- cs->hw.elsa.base = card->para[0];
- printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (cs->hw.elsa.base) {
- if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
- cs->typ))) {
- printk(KERN_WARNING
- "Elsa: no Elsa Microlink at %#lx\n",
- cs->hw.elsa.base);
- return (0);
- }
- } else
- cs->hw.elsa.base = probe_elsa(cs);
- if (cs->hw.elsa.base) {
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- val = bytein(cs->hw.elsa.cfg);
- if (cs->subtyp == ELSA_PC) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
- } else if (cs->subtyp == ELSA_PCC8) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
- } else {
- const u_char CARD_IrqTab[8] =
- {15, 10, 15, 3, 11, 5, 11, 9};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
- }
- val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
- if (val < 3)
- val |= 8;
- val += 'A' - 3;
- if (val == 'B' || val == 'C')
- val ^= 1;
- if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
- val = 'C';
- printk(KERN_INFO
- "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- val, cs->irq);
- val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
- if (val) {
- printk(KERN_WARNING
- "Elsa: Microlink S0 bus power bad\n");
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- }
- } else {
- printk(KERN_WARNING
- "No Elsa Microlink found\n");
- return (0);
- }
- } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
+ if (!card->para[1] && isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- if (ipid->function == ISAPNP_FUNCTION(0x133))
- cs->subtyp = ELSA_QS1000;
- else
- cs->subtyp = ELSA_QS3000;
- break;
- } else {
- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
return(0);
}
+ if (ipid->function == ISAPNP_FUNCTION(0x133))
+ cs->subtyp = ELSA_QS1000;
+ else
+ cs->subtyp = ELSA_QS3000;
+ break;
+ } else {
+ printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+ return(0);
}
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
- return(0);
}
+ ipid++;
+ pnp_c=NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+ return(0);
}
-#endif
- if (card->para[1] && card->para[0]) {
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- if (!cs->subtyp)
- cs->subtyp = ELSA_QS1000;
- } else {
- printk(KERN_ERR "Elsa PnP: no parameter\n");
- }
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+ }
+#endif /* __ISAPNP__ */
+
+ if (card->para[1] && card->para[0]) {
cs->hw.elsa.base = card->para[1];
cs->irq = card->para[0];
- val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
- if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
- cs->subtyp = ELSA_PCMCIA_IPAC;
- cs->hw.elsa.ale = cs->hw.elsa.base + 0;
- cs->hw.elsa.isac = cs->hw.elsa.base + 2;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = ELSA_PCMCIA;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- }
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+ if (!cs->subtyp)
+ cs->subtyp = ELSA_QS1000;
+ } else {
+ printk(KERN_ERR "Elsa PnP: no parameter\n");
+ }
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+
+ return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+ if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+ cs->subtyp = ELSA_PCMCIA_IPAC;
+ cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+ cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ }
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+}
+
#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
- if (pci_enable_device(dev_qs1000))
- return(0);
- cs->subtyp = ELSA_QS1000PCI;
- cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
- if (pci_enable_device(dev_qs3000))
- return(0);
- cs->subtyp = ELSA_QS3000PCI;
- cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
- } else {
- printk(KERN_WARNING "Elsa: No PCI card found\n");
+static struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+ if (pci_enable_device(dev_qs1000))
return(0);
- }
- if (!cs->irq) {
- printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ cs->subtyp = ELSA_QS1000PCI;
+ cs->irq = dev_qs1000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
return(0);
- }
+ cs->subtyp = ELSA_QS3000PCI;
+ cs->irq = dev_qs3000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+ } else {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+ }
+ if (!cs->irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+ printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+ printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+ printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+ }
+ cs->hw.elsa.ale = cs->hw.elsa.base;
+ cs->hw.elsa.isac = cs->hw.elsa.base +1;
+ cs->hw.elsa.hscx = cs->hw.elsa.base +1;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
+
+ return (1);
+}
- if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
- printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
- return(0);
- }
- if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
- printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
- printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
- printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
- }
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base +1;
- cs->hw.elsa.hscx = cs->hw.elsa.base +1;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->hw.elsa.cfg,
- cs->irq);
#else
- printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
- return (0);
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ return (1);
+}
#endif /* CONFIG_PCI */
- } else
- return (0);
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+ int bytecnt;
switch (cs->subtyp) {
case ELSA_PC:
@@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card)
here, it would fail. */
if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
printk(KERN_WARNING
- "HiSax: %s config port %#lx-%#lx already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA config port %#lx-%#lx already in use\n",
cs->hw.elsa.base,
cs->hw.elsa.base + bytecnt);
return (0);
@@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card)
if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
printk(KERN_WARNING
- "HiSax: %s pci port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA pci port %x-%x already in use\n",
cs->hw.elsa.cfg,
cs->hw.elsa.cfg + 0x80);
release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card)
}
return (1);
}
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+ int rc;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Elsa_revision);
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+ cs->subtyp = 0;
+
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ rc = setup_elsa_isa(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+ rc = setup_elsa_isapnp(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+ setup_elsa_pcmcia(card);
+
+ else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+ rc = setup_elsa_pci(card);
+ if (!rc)
+ return (0);
+
+ } else
+ return (0);
+
+ return setup_elsa_common(card);
+}
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 8d9864453a2..5c46a7130e0 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1019,7 +1019,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
static unsigned int
*init_send_hfcd(int cnt)
{
- int i, *send;
+ int i;
+ unsigned *send;
if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 60843b3f3b6..98b0149bca6 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1,7 +1,7 @@
/*
* hfc_usb.c
*
- * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $
+ * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $
*
* modular HiSax ISDN driver for Colognechip HFC-S USB chip
*
@@ -45,7 +45,7 @@
#include "hfc_usb.h"
static const char *hfcusb_revision =
- "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ ";
+ "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ ";
/* Hisax debug support
* debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
@@ -126,6 +126,12 @@ static struct usb_device_id hfcusb_idtab[] = {
{LED_SCHEME1, {0x80, -64, -32, -16},
"Twister ISDN TA"}),
},
+ {
+ USB_DEVICE(0x071d, 0x1005),
+ .driver_info = (unsigned long) &((hfcsusb_vdata)
+ {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
+ "Eicon DIVA USB 4.0"}),
+ },
{ }
};
@@ -187,7 +193,7 @@ typedef struct hfcusb_data {
struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
struct usb_ctrlrequest ctrl_read; /* same for read request */
- __u8 old_led_state, led_state, led_new_data, led_b_active;
+ __u8 old_led_state, led_state;
volatile __u8 threshold_mask; /* threshold actually reported */
volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
@@ -263,7 +269,7 @@ ctrl_complete(struct urb *urb)
ctrl_start_transfer(hfc); /* start next transfer */
}
-} /* ctrl_complete */
+}
/* write led data to auxport & invert if necessary */
static void
@@ -276,18 +282,18 @@ write_led(hfcusb_data * hfc, __u8 led_state)
}
static void
-set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
+set_led_bit(hfcusb_data * hfc, signed short led_bits, int on)
{
- if (unset) {
+ if (on) {
if (led_bits < 0)
- hfc->led_state |= abs(led_bits);
+ hfc->led_state &= ~abs(led_bits);
else
- hfc->led_state &= ~led_bits;
+ hfc->led_state |= led_bits;
} else {
if (led_bits < 0)
- hfc->led_state &= ~abs(led_bits);
+ hfc->led_state |= abs(led_bits);
else
- hfc->led_state |= led_bits;
+ hfc->led_state &= ~led_bits;
}
}
@@ -304,34 +310,34 @@ handle_led(hfcusb_data * hfc, int event)
switch (event) {
case LED_POWER_ON:
- set_led_bit(hfc, driver_info->led_bits[0], 0);
- set_led_bit(hfc, driver_info->led_bits[1], 1);
- set_led_bit(hfc, driver_info->led_bits[2], 1);
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[0], 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
case LED_POWER_OFF:
- set_led_bit(hfc, driver_info->led_bits[0], 1);
- set_led_bit(hfc, driver_info->led_bits[1], 1);
- set_led_bit(hfc, driver_info->led_bits[2], 1);
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[0], 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
case LED_S0_ON:
- set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 1);
break;
case LED_S0_OFF:
- set_led_bit(hfc, driver_info->led_bits[1], 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
break;
case LED_B1_ON:
- set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 1);
break;
case LED_B1_OFF:
- set_led_bit(hfc, driver_info->led_bits[2], 1);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
break;
case LED_B2_ON:
- set_led_bit(hfc, driver_info->led_bits[3], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 1);
break;
case LED_B2_OFF:
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
}
write_led(hfc, hfc->led_state);
@@ -1159,7 +1165,6 @@ hfc_usb_init(hfcusb_data * hfc)
hfc->l1_activated = 0;
hfc->disc_flag = 0;
hfc->led_state = 0;
- hfc->led_new_data = 0;
hfc->old_led_state = 0;
/* init the t3 timer */
@@ -1514,20 +1519,18 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* callback for unplugged USB device */
static void
-hfc_usb_disconnect(struct usb_interface
- *intf)
+hfc_usb_disconnect(struct usb_interface *intf)
{
hfcusb_data *context = usb_get_intfdata(intf);
int i;
handle_led(context, LED_POWER_OFF);
- schedule_timeout((10 * HZ) / 1000);
+ schedule_timeout(HZ / 100);
printk(KERN_INFO "HFC-S USB: device disconnect\n");
context->disc_flag = 1;
usb_set_intfdata(intf, NULL);
- if (!context)
- return;
+
if (timer_pending(&context->t3_timer))
del_timer(&context->t3_timer);
if (timer_pending(&context->t4_timer))
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 3cd8d5ba239..34733c903df 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -202,7 +202,7 @@ struct Layer1 {
void *hardware;
struct BCState *bcs;
struct PStack **stlistp;
- long Flags;
+ unsigned long Flags;
struct FsmInst l1m;
struct FsmTimer timer;
void (*l1l2) (struct PStack *, int, void *);
diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h
index 4898fce2d50..aa7c94037b2 100644
--- a/drivers/isdn/hisax/hisax_if.h
+++ b/drivers/isdn/hisax/hisax_if.h
@@ -56,7 +56,7 @@ struct hisax_d_if {
struct IsdnCardState *cs;
struct hisax_b_if *b_if[2];
struct sk_buff_head erq;
- long ph_state;
+ unsigned long ph_state;
};
int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index fa2db87667c..a895dfed40e 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -151,7 +151,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
struct IsdnCardState *cs)
{
- int cfg;
+ u32 cfg;
if (pci_enable_device(dev_netjet))
return(0);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index ad06f3cc60f..03dfc32166a 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
#ifdef __ISAPNP__
static struct isapnp_device_id sedl_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return -1;
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+ cs->subtyp = SEDL_SPEED_FAX;
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ *bytecnt = 16;
+ } else {
+ cs->subtyp = SEDL_SPEED_CARD_WIN;
+ cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ }
+
+ return (1);
+ } else {
+ printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c = NULL;
+ }
+
+ printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+ return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u16 sub_vendor_id, sub_id;
+
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+ if (pci_enable_device(dev_sedl))
+ return(0);
+ cs->irq = dev_sedl->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+ sub_vendor_id = dev_sedl->subsystem_vendor;
+ sub_id = dev_sedl->subsystem_device;
+ printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+ sub_vendor_id, sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+ cs->hw.sedl.cfg_reg);
+ if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+ printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+ return(0);
+ }
+ if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PCI;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = HST_SAPHIR3;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+ } else {
+ printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+ sub_vendor_id);
+ return(0);
+ }
+
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+ byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+ mdelay(2);
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+ mdelay(10);
+
+ return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ return (1);
+}
+
+#endif /* CONFIG_PCI */
int __devinit
setup_sedlbauer(struct IsdnCard *card)
{
- int bytecnt, ver, val;
+ int bytecnt = 8, ver, val, rc;
struct IsdnCardState *cs = card->cs;
char tmp[64];
- u16 sub_vendor_id, sub_id;
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card)
bytecnt = 16;
}
} else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0x2)) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- bytecnt = 16;
- } else {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
- }
- }
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
- if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
- if (pci_enable_device(dev_sedl))
- return(0);
- cs->irq = dev_sedl->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
- } else {
- printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- sub_vendor_id = dev_sedl->subsystem_vendor;
- sub_id = dev_sedl->subsystem_device;
- printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
- sub_vendor_id, sub_id);
- printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
- cs->hw.sedl.cfg_reg);
- if (sub_id != PCI_SUB_ID_SEDLBAUER) {
- printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
- return(0);
- }
- if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = HST_SAPHIR3;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- } else {
- printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
- sub_vendor_id);
- return(0);
- }
+ rc = setup_sedlbauer_isapnp(card, &bytecnt);
+ if (!rc)
+ return (0);
+ if (rc > 0)
+ goto ready;
+
+ /* Probe for Sedlbauer speed pci */
+ rc = setup_sedlbauer_pci(card);
+ if (!rc)
+ return (0);
+
bytecnt = 256;
- cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- mdelay(10);
-#else
- printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
}
-#ifdef __ISAPNP__
ready:
-#endif
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index d09f6d033f1..4393003ae16 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card)
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
+
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
-#ifdef CONFIG_PCI
+
if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
return(0);
@@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card)
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
}
-#else
- printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
/* Initialize Zoran PCI controller */
writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 3aeceaf9769..39129b94f8b 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card)
printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_W6692)
return (0);
-#ifdef CONFIG_PCI
+
while (id_list[id_idx].vendor_id) {
dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card)
cs->hw.w6692.iobase + 255);
return (0);
}
-#else
- printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: W6692 unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
printk(KERN_INFO
"HiSax: %s config irq:%d I/O:%x\n",
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 9e01748a176..b7cc5c2f08c 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -20,10 +20,15 @@
#include "hysdn_defs.h"
static struct pci_device_id hysdn_pci_tbl[] = {
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@ MODULE_LICENSE("GPL");
static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
static int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0 */
-/**********************************************/
-static struct {
- unsigned short subid; /* PCI sub id */
- unsigned char cardtyp; /* card type assigned */
-} pci_subid_map[] = {
-
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
- },
- {
- 0, 0
- } /* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented. */
-/*********************************************************************/
-static void
-search_cards(void)
-{
- struct pci_dev *akt_pcidev = NULL;
- hysdn_card *card, *card_last;
- int i;
-
- card_root = NULL;
- card_last = NULL;
- while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- akt_pcidev)) != NULL) {
- if (pci_enable_device(akt_pcidev))
- continue;
-
- if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
- printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
- return;
- }
- card->myid = cardmax; /* set own id */
- card->bus = akt_pcidev->bus->number;
- card->devfn = akt_pcidev->devfn; /* slot + function */
- card->subsysid = akt_pcidev->subsystem_device;
- card->irq = akt_pcidev->irq;
- card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
- card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
- card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
- card->brdtype = BD_NONE; /* unknown */
- card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
- card->faxchans = 0; /* default no fax channels */
- card->bchans = 2; /* and 2 b-channels */
- for (i = 0; pci_subid_map[i].subid; i++)
- if (pci_subid_map[i].subid == card->subsysid) {
- card->brdtype = pci_subid_map[i].cardtyp;
- break;
- }
- if (card->brdtype != BD_NONE) {
- if (ergo_inithardware(card)) {
- printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
- kfree(card);
- continue;
- }
- } else {
- printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
- kfree(card); /* release mem */
- continue;
- }
- cardmax++;
- card->next = NULL; /*end of chain */
- if (card_last)
- card_last->next = card; /* pointer to next card */
- else
- card_root = card;
- card_last = card; /* new chain end */
- } /* device found */
-} /* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
- hysdn_card *card;
-
- while (card_root) {
- card = card_root;
- if (card->releasehardware)
- card->releasehardware(card); /* free all hardware resources */
- card_root = card_root->next; /* remove card from chain */
- kfree(card); /* return mem */
-
- } /* while card_root */
-} /* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
- hysdn_card *card;
-
- card = card_root; /* first in chain */
- while (card) {
- if (card->stopcard)
- card->stopcard(card);
- card = card->next; /* remove card from chain */
- } /* while card */
-} /* stop_cards */
+static hysdn_card *card_last = NULL; /* pointer to first card */
/****************************************************************************/
@@ -191,31 +75,138 @@ hysdn_getrev(const char *revision)
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+ const struct pci_device_id *ent)
+{
+ hysdn_card *card;
+ int rc;
+
+ rc = pci_enable_device(akt_pcidev);
+ if (rc)
+ return rc;
+
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ card->subsysid = akt_pcidev->subsystem_device;
+ card->irq = akt_pcidev->irq;
+ card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+ card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+ card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ card->brdtype = ent->driver_data;
+
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ rc = -EBUSY;
+ goto err_out_card;
+ }
+
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+
+ pci_set_drvdata(akt_pcidev, card);
+ return 0;
+
+err_out_card:
+ kfree(card);
+err_out:
+ pci_disable_device(akt_pcidev);
+ return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+ hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+ pci_set_drvdata(akt_pcidev, NULL);
+
+ if (card->stopcard)
+ card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_release(card);
+#endif
+
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+
+ if (card == card_root) {
+ card_root = card_root->next;
+ if (!card_root)
+ card_last = NULL;
+ } else {
+ hysdn_card *tmp = card_root;
+ while (tmp) {
+ if (tmp->next == card)
+ tmp->next = card->next;
+ card_last = tmp;
+ tmp = tmp->next;
+ }
+ }
+
+ kfree(card);
+ pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+ .name = "hysdn",
+ .id_table = hysdn_pci_tbl,
+ .probe = hysdn_pci_init_one,
+ .remove = __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
static int __init
hysdn_init(void)
{
char tmp[50];
+ int rc;
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
- search_cards();
+
+ rc = pci_register_driver(&hysdn_pci_driver);
+ if (rc)
+ return rc;
+
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
- if (hysdn_procconf_init()) {
- free_resources(); /* proc file_sys not created */
- return (-1);
- }
+ if (!hysdn_procconf_init())
+ hysdn_have_procfs = 1;
+
#ifdef CONFIG_HYSDN_CAPI
if(cardmax > 0) {
if(hycapi_init()) {
printk(KERN_ERR "HYCAPI: init failed\n");
- return(-1);
+
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+ return -ESPIPE;
}
}
#endif /* CONFIG_HYSDN_CAPI */
- return (0); /* no error */
+
+ return 0; /* no error */
} /* init_module */
@@ -230,20 +221,15 @@ hysdn_init(void)
static void __exit
hysdn_exit(void)
{
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+
#ifdef CONFIG_HYSDN_CAPI
- hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
- stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
- card = card_root; /* first in chain */
- while (card) {
- hycapi_capi_release(card);
- card = card->next; /* remove card from chain */
- } /* while card */
hycapi_cleanup();
#endif /* CONFIG_HYSDN_CAPI */
- hysdn_procconf_release();
- free_resources();
+
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 7c9cb7e19f2..b39d1f5b378 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -328,7 +328,7 @@ isdn_net_autohup(void)
l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
l->transcount = 0;
if (dev->net_verbose > 3)
- printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
+ printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
anymore = 1;
l->huptimer++;
@@ -350,12 +350,12 @@ isdn_net_autohup(void)
if (l->hupflags & ISDN_CHARGEHUP) {
if (l->hupflags & ISDN_WAITCHARGE) {
printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
- l->name, l->hupflags);
+ p->dev->name, l->hupflags);
isdn_net_hangup(p->dev);
} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
printk(KERN_DEBUG
"isdn_net: %s: chtime = %lu, chint = %d\n",
- l->name, l->chargetime, l->chargeint);
+ p->dev->name, l->chargetime, l->chargeint);
isdn_net_hangup(p->dev);
}
} else
@@ -442,8 +442,8 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#endif
isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- printk(KERN_INFO "%s: remote hangup\n", lp->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
+ printk(KERN_INFO "%s: remote hangup\n", p->dev->name);
+ printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name,
lp->charge);
isdn_net_unbind_channel(lp);
return 1;
@@ -487,7 +487,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
isdn_net_add_to_bundle(nd, lp);
}
}
- printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+ printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
@@ -534,7 +534,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
- lp->name, lp->chargetime);
+ p->dev->name, lp->chargetime);
return 1;
}
}
@@ -565,7 +565,7 @@ isdn_net_dial(void)
#ifdef ISDN_DEBUG_NET_DIAL
if (lp->dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
+ printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate);
#endif
switch (lp->dialstate) {
case 0:
@@ -578,7 +578,7 @@ isdn_net_dial(void)
lp->dial = lp->phone[1];
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
- lp->name);
+ p->dev->name);
isdn_net_hangup(p->dev);
break;
}
@@ -632,13 +632,13 @@ isdn_net_dial(void)
cmd.arg = lp->isdn_channel;
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
- lp->name);
+ p->dev->name);
isdn_net_hangup(p->dev);
break;
}
if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
lp->dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
+ printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name);
} else {
if(lp->dialtimeout > 0)
if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
@@ -688,7 +688,7 @@ isdn_net_dial(void)
dev->usage[i] |= ISDN_USAGE_OUTGOING;
isdn_info_update();
}
- printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+ printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name,
lp->dialretry, cmd.parm.setup.phone,
(cmd.parm.setup.si1 == 1) ? "DOV" : "");
lp->dtimer = 0;
@@ -797,7 +797,7 @@ isdn_net_dial(void)
*/
if (lp->dtimer++ > lp->cbdelay)
{
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
+ printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name);
lp->dtimer = 0;
lp->dialstate = 4;
cmd.driver = lp->isdn_device;
@@ -810,7 +810,7 @@ isdn_net_dial(void)
break;
default:
printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- lp->dialstate, lp->name);
+ lp->dialstate, p->dev->name);
}
p = (isdn_net_dev *) p->next;
}
@@ -836,11 +836,11 @@ isdn_net_hangup(struct net_device *d)
if (slp->flags & ISDN_NET_CONNECTED) {
printk(KERN_INFO
"isdn_net: hang up slave %s before %s\n",
- slp->name, lp->name);
+ lp->slave->name, d->name);
isdn_net_hangup(lp->slave);
}
}
- printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
+ printk(KERN_INFO "isdn_net: local hangup %s\n", d->name);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
@@ -858,7 +858,7 @@ isdn_net_hangup(struct net_device *d)
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = lp->isdn_channel;
isdn_command(&cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
+ printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
}
isdn_net_unbind_channel(lp);
@@ -885,7 +885,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
/* fall back to old isdn_net_log_packet method() */
char * buf = skb->data;
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+ printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name);
p = buf;
proto = ETH_P_IP;
switch (lp->p_encap) {
@@ -1023,7 +1023,7 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret != len) {
/* we should never get here */
- printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+ printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
goto error;
}
@@ -1461,7 +1461,7 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
mod_timer(&lp->cisco_timer, expires);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n",
- lp->name, lp->cisco_keepalive_period);
+ dev->name, lp->cisco_keepalive_period);
}
break;
@@ -1512,7 +1512,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
lp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
- " changed state to down\n", lp->name);
+ " changed state to down\n", lp->netdev->dev->name);
/* should stop routing higher-level data accross */
} else if ((!lp->cisco_line_state) &&
(myseq_diff >= 0) && (myseq_diff <= 2)) {
@@ -1520,14 +1520,14 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
lp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
- " changed state to up\n", lp->name);
+ " changed state to up\n", lp->netdev->dev->name);
/* restart routing higher-level data accross */
}
if (lp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- lp->name, last_cisco_myseq, lp->cisco_mineseen,
+ lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen,
((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
lp->cisco_yourseq,
((lp->cisco_line_state) ? "line up" : "line down"));
@@ -1682,7 +1682,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
"remote ip: %d.%d.%d.%d, "
"local ip: %d.%d.%d.%d "
"mask: %d.%d.%d.%d\n",
- lp->name,
+ lp->netdev->dev->name,
HIPQUAD(addr),
HIPQUAD(local),
HIPQUAD(mask));
@@ -1690,7 +1690,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
slarp_reply_out:
printk(KERN_INFO "%s: got invalid slarp "
"reply (%d.%d.%d.%d/%d.%d.%d.%d) "
- "- ignored\n", lp->name,
+ "- ignored\n", lp->netdev->dev->name,
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
@@ -1701,7 +1701,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
lp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
- lp->name, period, lp->cisco_keepalive_period);
+ lp->netdev->dev->name, period,
+ lp->cisco_keepalive_period);
}
lp->cisco_last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
@@ -1732,12 +1733,12 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
- lp->name, addr);
+ lp->netdev->dev->name, addr);
goto out_free;
}
if (ctrl != CISCO_CTRL) {
printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
- lp->name, ctrl);
+ lp->netdev->dev->name, ctrl);
goto out_free;
}
@@ -1748,7 +1749,8 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
printk(KERN_DEBUG "%s: Received CDP packet. use "
- "\"no cdp enable\" on cisco.\n", lp->name);
+ "\"no cdp enable\" on cisco.\n",
+ lp->netdev->dev->name);
goto out_free;
default:
/* no special cisco protocol */
@@ -1843,7 +1845,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
};
#endif /* CONFIG_ISDN_X25 */
printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->name);
+ lp->netdev->dev->name);
kfree_skb(skb);
return;
}
@@ -2174,7 +2176,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
wret = matchret;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- lp->name, lp->msn, lp->flags, lp->dialstate);
+ p->dev->name, lp->msn, lp->flags, lp->dialstate);
#endif
if ((!matchret) && /* EAZ is matching */
(((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
@@ -2277,7 +2279,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* */
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
/*
@@ -2286,7 +2288,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
*/
if (!isdn_net_device_started(p)) {
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
/* Interface is up, now see if it's a slave. If so, see if
@@ -2294,8 +2296,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
*/
if (lp->master) {
isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
- printk(KERN_DEBUG "ICALLslv: %s\n", lp->name);
- printk(KERN_DEBUG "master=%s\n", mlp->name);
+ printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
+ printk(KERN_DEBUG "master=%s\n", lp->master->name);
if (mlp->flags & ISDN_NET_CONNECTED) {
printk(KERN_DEBUG "master online\n");
/* Master is online, find parent-slave (master if first slave) */
@@ -2322,11 +2324,11 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* */
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
- lp->name, nr, eaz);
+ p->dev->name, nr, eaz);
if (lp->phone[1]) {
/* Grab a free ISDN-Channel */
spin_lock_irqsave(&dev->lock, flags);
@@ -2340,7 +2342,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
lp->msn)
) < 0) {
- printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
+ printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n",
+ p->dev->name);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
@@ -2361,11 +2364,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* Initiate dialing by returning 2 or 4 */
return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
} else
- printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
+ printk(KERN_WARNING "isdn_net: %s: No phone number\n",
+ p->dev->name);
return 0;
} else {
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
- eaz);
+ printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
+ p->dev->name, nr, eaz);
/* if this interface is dialing, it does it probably on a different
device, so free this device */
if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
@@ -2424,7 +2428,7 @@ isdn_net_findif(char *name)
isdn_net_dev *p = dev->netdev;
while (p) {
- if (!strcmp(p->local->name, name))
+ if (!strcmp(p->dev->name, name))
return p;
p = (isdn_net_dev *) p->next;
}
@@ -2453,7 +2457,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
lp->pre_device,
lp->pre_channel,
lp->msn)) < 0) {
- printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
+ printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n",
+ lp->netdev->dev->name);
spin_unlock_irqrestore(&dev->lock, flags);
return -EAGAIN;
}
@@ -2556,7 +2561,7 @@ isdn_net_new(char *name, struct net_device *master)
return NULL;
}
if (name == NULL)
- name = " ";
+ return NULL;
if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
@@ -2568,7 +2573,6 @@ isdn_net_new(char *name, struct net_device *master)
return NULL;
}
netdev->local = netdev->dev->priv;
- strcpy(netdev->local->name, netdev->dev->name);
netdev->dev->init = isdn_net_init;
if (master) {
/* Device shall be a slave */
@@ -2673,7 +2677,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#endif
if (isdn_net_device_started(p)) {
printk(KERN_WARNING "%s: cannot change encap when if is up\n",
- lp->name);
+ p->dev->name);
return -EBUSY;
}
#ifdef CONFIG_ISDN_X25
@@ -2698,7 +2702,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
case ISDN_NET_ENCAP_SYNCPPP:
#ifndef CONFIG_ISDN_PPP
printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- lp->name);
+ p->dev->name);
return -EINVAL;
#else
p->dev->type = ARPHRD_PPP; /* change ARP type */
@@ -2709,7 +2713,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
case ISDN_NET_ENCAP_X25IFACE:
#ifndef CONFIG_ISDN_X25
printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
- p->local->name);
+ p->dev->name);
return -EINVAL;
#else
p->dev->type = ARPHRD_X25; /* change ARP type */
@@ -2725,7 +2729,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
break;
printk(KERN_WARNING
"%s: encapsulation protocol %d not supported\n",
- p->local->name, cfg->p_encap);
+ p->dev->name, cfg->p_encap);
return -EINVAL;
}
if (strlen(cfg->drvid)) {
@@ -2902,13 +2906,18 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->pppbind = lp->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave)
- strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
- else
+ if (lp->slave) {
+ if (strlen(lp->slave->name) > 8)
+ strcpy(cfg->slave, "too-long");
+ else
+ strcpy(cfg->slave, lp->slave->name);
+ } else
cfg->slave[0] = '\0';
- if (lp->master)
- strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
- else
+ if (lp->master) {
+ if (strlen(lp->master->name) > 8)
+ strcpy(cfg->master, "too-long");
+ strcpy(cfg->master, lp->master->name);
+ } else
cfg->master[0] = '\0';
return 0;
}
@@ -2978,7 +2987,8 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
isdn_net_dev *p = isdn_net_findif(phone->name);
int ch, dv, idx;
- if (!p) return -ENODEV;
+ if (!p)
+ return -ENODEV;
/*
* Theoretical race: while this executes, the remote number might
* become invalid (hang up) or change (new connection), resulting
@@ -2987,14 +2997,18 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
*/
ch = p->local->isdn_channel;
dv = p->local->isdn_device;
- if(ch<0 && dv<0) return -ENOTCONN;
+ if(ch < 0 && dv < 0)
+ return -ENOTCONN;
idx = isdn_dc2minor(dv, ch);
- if (idx<0) return -ENODEV;
+ if (idx <0 )
+ return -ENODEV;
/* for pre-bound channels, we need this extra check */
- if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
- strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
- phone->outgoing=USG_OUTGOING(dev->usage[idx]);
- if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
+ if (strncmp(dev->num[idx], "???", 3) == 0)
+ return -ENOTCONN;
+ strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN);
+ phone->outgoing = USG_OUTGOING(dev->usage[idx]);
+ if (copy_to_user(peer, phone, sizeof(*peer)))
+ return -EFAULT;
return 0;
}
/*
@@ -3113,18 +3127,18 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
dev->netdev = p->next;
if (p->local->slave) {
/* If this interface has a slave, remove it also */
- char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
+ char *slavename = p->local->slave->name;
isdn_net_dev *n = dev->netdev;
q = NULL;
while (n) {
- if (!strcmp(n->local->name, slavename)) {
+ if (!strcmp(n->dev->name, slavename)) {
spin_unlock_irqrestore(&dev->lock, flags);
isdn_net_realrm(n, q);
spin_lock_irqsave(&dev->lock, flags);
break;
}
q = n;
- n = (isdn_net_dev *) n->next;
+ n = (isdn_net_dev *)n->next;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
@@ -3152,7 +3166,7 @@ isdn_net_rm(char *name)
p = dev->netdev;
q = NULL;
while (p) {
- if (!strcmp(p->local->name, name)) {
+ if (!strcmp(p->dev->name, name)) {
spin_unlock_irqrestore(&dev->lock, flags);
return (isdn_net_realrm(p, q));
}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 0e5e59f8434..9f5fe372f83 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -190,9 +190,11 @@ isdn_ppp_bind(isdn_net_local * lp)
retval = -1;
goto out;
}
- unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
+ /* get unit number from interface name .. ugly! */
+ unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
if (unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
+ printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
+ lp->netdev->dev->name);
retval = -1;
goto out;
}
@@ -507,7 +509,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCGIFNAME:
if(!lp)
return -EINVAL;
- if ((r = set_arg(argp, lp->name, strlen(lp->name))))
+ if ((r = set_arg(argp, lp->netdev->dev->name,
+ strlen(lp->netdev->dev->name))))
return r;
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 0a419a0de60..8749fa4ffce 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -17,6 +17,7 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on X86 && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
select ANON_INODES
---help---
Support hosting fully virtualized guest machines using hardware
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index c0a789fa9d6..e5a8f4d3e97 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -2,7 +2,7 @@
# Makefile for Kernel-based Virtual Machine module
#
-kvm-objs := kvm_main.o mmu.o x86_emulate.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o
obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
new file mode 100644
index 00000000000..a679157bc59
--- /dev/null
+++ b/drivers/kvm/i8259.c
@@ -0,0 +1,450 @@
+/*
+ * 8259 interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ * Port from Qemu.
+ */
+#include <linux/mm.h>
+#include "irq.h"
+
+/*
+ * set irq level. If an edge is detected, then the IRR is set to 1
+ */
+static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
+{
+ int mask;
+ mask = 1 << irq;
+ if (s->elcr & mask) /* level triggered */
+ if (level) {
+ s->irr |= mask;
+ s->last_irr |= mask;
+ } else {
+ s->irr &= ~mask;
+ s->last_irr &= ~mask;
+ }
+ else /* edge triggered */
+ if (level) {
+ if ((s->last_irr & mask) == 0)
+ s->irr |= mask;
+ s->last_irr |= mask;
+ } else
+ s->last_irr &= ~mask;
+}
+
+/*
+ * return the highest priority found in mask (highest = smallest
+ * number). Return 8 if no irq
+ */
+static inline int get_priority(struct kvm_kpic_state *s, int mask)
+{
+ int priority;
+ if (mask == 0)
+ return 8;
+ priority = 0;
+ while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+ priority++;
+ return priority;
+}
+
+/*
+ * return the pic wanted interrupt. return -1 if none
+ */
+static int pic_get_irq(struct kvm_kpic_state *s)
+{
+ int mask, cur_priority, priority;
+
+ mask = s->irr & ~s->imr;
+ priority = get_priority(s, mask);
+ if (priority == 8)
+ return -1;
+ /*
+ * compute current priority. If special fully nested mode on the
+ * master, the IRQ coming from the slave is not taken into account
+ * for the priority computation.
+ */
+ mask = s->isr;
+ if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+ mask &= ~(1 << 2);
+ cur_priority = get_priority(s, mask);
+ if (priority < cur_priority)
+ /*
+ * higher priority found: an irq should be generated
+ */
+ return (priority + s->priority_add) & 7;
+ else
+ return -1;
+}
+
+/*
+ * raise irq to CPU if necessary. must be called every time the active
+ * irq may change
+ */
+static void pic_update_irq(struct kvm_pic *s)
+{
+ int irq2, irq;
+
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0) {
+ /*
+ * if irq request by slave pic, signal master PIC
+ */
+ pic_set_irq1(&s->pics[0], 2, 1);
+ pic_set_irq1(&s->pics[0], 2, 0);
+ }
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0)
+ s->irq_request(s->irq_request_opaque, 1);
+ else
+ s->irq_request(s->irq_request_opaque, 0);
+}
+
+void kvm_pic_update_irq(struct kvm_pic *s)
+{
+ pic_update_irq(s);
+}
+
+void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+ struct kvm_pic *s = opaque;
+
+ pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+ pic_update_irq(s);
+}
+
+/*
+ * acknowledge interrupt 'irq'
+ */
+static inline void pic_intack(struct kvm_kpic_state *s, int irq)
+{
+ if (s->auto_eoi) {
+ if (s->rotate_on_auto_eoi)
+ s->priority_add = (irq + 1) & 7;
+ } else
+ s->isr |= (1 << irq);
+ /*
+ * We don't clear a level sensitive interrupt here
+ */
+ if (!(s->elcr & (1 << irq)))
+ s->irr &= ~(1 << irq);
+}
+
+int kvm_pic_read_irq(struct kvm_pic *s)
+{
+ int irq, irq2, intno;
+
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0) {
+ pic_intack(&s->pics[0], irq);
+ if (irq == 2) {
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0)
+ pic_intack(&s->pics[1], irq2);
+ else
+ /*
+ * spurious IRQ on slave controller
+ */
+ irq2 = 7;
+ intno = s->pics[1].irq_base + irq2;
+ irq = irq2 + 8;
+ } else
+ intno = s->pics[0].irq_base + irq;
+ } else {
+ /*
+ * spurious IRQ on host controller
+ */
+ irq = 7;
+ intno = s->pics[0].irq_base + irq;
+ }
+ pic_update_irq(s);
+
+ return intno;
+}
+
+static void pic_reset(void *opaque)
+{
+ struct kvm_kpic_state *s = opaque;
+
+ s->last_irr = 0;
+ s->irr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->priority_add = 0;
+ s->irq_base = 0;
+ s->read_reg_select = 0;
+ s->poll = 0;
+ s->special_mask = 0;
+ s->init_state = 0;
+ s->auto_eoi = 0;
+ s->rotate_on_auto_eoi = 0;
+ s->special_fully_nested_mode = 0;
+ s->init4 = 0;
+}
+
+static void pic_ioport_write(void *opaque, u32 addr, u32 val)
+{
+ struct kvm_kpic_state *s = opaque;
+ int priority, cmd, irq;
+
+ addr &= 1;
+ if (addr == 0) {
+ if (val & 0x10) {
+ pic_reset(s); /* init */
+ /*
+ * deassert a pending interrupt
+ */
+ s->pics_state->irq_request(s->pics_state->
+ irq_request_opaque, 0);
+ s->init_state = 1;
+ s->init4 = val & 1;
+ if (val & 0x02)
+ printk(KERN_ERR "single mode not supported");
+ if (val & 0x08)
+ printk(KERN_ERR
+ "level sensitive irq not supported");
+ } else if (val & 0x08) {
+ if (val & 0x04)
+ s->poll = 1;
+ if (val & 0x02)
+ s->read_reg_select = val & 1;
+ if (val & 0x40)
+ s->special_mask = (val >> 5) & 1;
+ } else {
+ cmd = val >> 5;
+ switch (cmd) {
+ case 0:
+ case 4:
+ s->rotate_on_auto_eoi = cmd >> 2;
+ break;
+ case 1: /* end of interrupt */
+ case 5:
+ priority = get_priority(s, s->isr);
+ if (priority != 8) {
+ irq = (priority + s->priority_add) & 7;
+ s->isr &= ~(1 << irq);
+ if (cmd == 5)
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ }
+ break;
+ case 3:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ pic_update_irq(s->pics_state);
+ break;
+ case 6:
+ s->priority_add = (val + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ case 7:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ default:
+ break; /* no operation */
+ }
+ }
+ } else
+ switch (s->init_state) {
+ case 0: /* normal mode */
+ s->imr = val;
+ pic_update_irq(s->pics_state);
+ break;
+ case 1:
+ s->irq_base = val & 0xf8;
+ s->init_state = 2;
+ break;
+ case 2:
+ if (s->init4)
+ s->init_state = 3;
+ else
+ s->init_state = 0;
+ break;
+ case 3:
+ s->special_fully_nested_mode = (val >> 4) & 1;
+ s->auto_eoi = (val >> 1) & 1;
+ s->init_state = 0;
+ break;
+ }
+}
+
+static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1)
+{
+ int ret;
+
+ ret = pic_get_irq(s);
+ if (ret >= 0) {
+ if (addr1 >> 7) {
+ s->pics_state->pics[0].isr &= ~(1 << 2);
+ s->pics_state->pics[0].irr &= ~(1 << 2);
+ }
+ s->irr &= ~(1 << ret);
+ s->isr &= ~(1 << ret);
+ if (addr1 >> 7 || ret != 2)
+ pic_update_irq(s->pics_state);
+ } else {
+ ret = 0x07;
+ pic_update_irq(s->pics_state);
+ }
+
+ return ret;
+}
+
+static u32 pic_ioport_read(void *opaque, u32 addr1)
+{
+ struct kvm_kpic_state *s = opaque;
+ unsigned int addr;
+ int ret;
+
+ addr = addr1;
+ addr &= 1;
+ if (s->poll) {
+ ret = pic_poll_read(s, addr1);
+ s->poll = 0;
+ } else
+ if (addr == 0)
+ if (s->read_reg_select)
+ ret = s->isr;
+ else
+ ret = s->irr;
+ else
+ ret = s->imr;
+ return ret;
+}
+
+static void elcr_ioport_write(void *opaque, u32 addr, u32 val)
+{
+ struct kvm_kpic_state *s = opaque;
+ s->elcr = val & s->elcr_mask;
+}
+
+static u32 elcr_ioport_read(void *opaque, u32 addr1)
+{
+ struct kvm_kpic_state *s = opaque;
+ return s->elcr;
+}
+
+static int picdev_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ case 0x4d0:
+ case 0x4d1:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void picdev_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *val)
+{
+ struct kvm_pic *s = this->private;
+ unsigned char data = *(unsigned char *)val;
+
+ if (len != 1) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "PIC: non byte write\n");
+ return;
+ }
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ pic_ioport_write(&s->pics[addr >> 7], addr, data);
+ break;
+ case 0x4d0:
+ case 0x4d1:
+ elcr_ioport_write(&s->pics[addr & 1], addr, data);
+ break;
+ }
+}
+
+static void picdev_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *val)
+{
+ struct kvm_pic *s = this->private;
+ unsigned char data = 0;
+
+ if (len != 1) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "PIC: non byte read\n");
+ return;
+ }
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ data = pic_ioport_read(&s->pics[addr >> 7], addr);
+ break;
+ case 0x4d0:
+ case 0x4d1:
+ data = elcr_ioport_read(&s->pics[addr & 1], addr);
+ break;
+ }
+ *(unsigned char *)val = data;
+}
+
+/*
+ * callback when PIC0 irq status changed
+ */
+static void pic_irq_request(void *opaque, int level)
+{
+ struct kvm *kvm = opaque;
+ struct kvm_vcpu *vcpu = kvm->vcpus[0];
+
+ pic_irqchip(kvm)->output = level;
+ if (vcpu)
+ kvm_vcpu_kick(vcpu);
+}
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm)
+{
+ struct kvm_pic *s;
+ s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
+ if (!s)
+ return NULL;
+ s->pics[0].elcr_mask = 0xf8;
+ s->pics[1].elcr_mask = 0xde;
+ s->irq_request = pic_irq_request;
+ s->irq_request_opaque = kvm;
+ s->pics[0].pics_state = s;
+ s->pics[1].pics_state = s;
+
+ /*
+ * Initialize PIO device
+ */
+ s->dev.read = picdev_read;
+ s->dev.write = picdev_write;
+ s->dev.in_range = picdev_in_range;
+ s->dev.private = s;
+ kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev);
+ return s;
+}
diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c
new file mode 100644
index 00000000000..c7992e667fd
--- /dev/null
+++ b/drivers/kvm/ioapic.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2001 MandrakeSoft S.A.
+ *
+ * MandrakeSoft S.A.
+ * 43, rue d'Aboukir
+ * 75002 Paris - France
+ * http://www.linux-mandrake.com/
+ * http://www.mandrakesoft.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Yunhong Jiang <yunhong.jiang@intel.com>
+ * Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ * Based on Xen 3.1 code.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/io_apic.h>
+#include "irq.h"
+/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define ioapic_debug(fmt, arg...)
+static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
+
+static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
+ unsigned long addr,
+ unsigned long length)
+{
+ unsigned long result = 0;
+
+ switch (ioapic->ioregsel) {
+ case IOAPIC_REG_VERSION:
+ result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
+ | (IOAPIC_VERSION_ID & 0xff));
+ break;
+
+ case IOAPIC_REG_APIC_ID:
+ case IOAPIC_REG_ARB_ID:
+ result = ((ioapic->id & 0xf) << 24);
+ break;
+
+ default:
+ {
+ u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
+ u64 redir_content;
+
+ ASSERT(redir_index < IOAPIC_NUM_PINS);
+
+ redir_content = ioapic->redirtbl[redir_index].bits;
+ result = (ioapic->ioregsel & 0x1) ?
+ (redir_content >> 32) & 0xffffffff :
+ redir_content & 0xffffffff;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
+{
+ union ioapic_redir_entry *pent;
+
+ pent = &ioapic->redirtbl[idx];
+
+ if (!pent->fields.mask) {
+ ioapic_deliver(ioapic, idx);
+ if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
+ pent->fields.remote_irr = 1;
+ }
+ if (!pent->fields.trig_mode)
+ ioapic->irr &= ~(1 << idx);
+}
+
+static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
+{
+ unsigned index;
+
+ switch (ioapic->ioregsel) {
+ case IOAPIC_REG_VERSION:
+ /* Writes are ignored. */
+ break;
+
+ case IOAPIC_REG_APIC_ID:
+ ioapic->id = (val >> 24) & 0xf;
+ break;
+
+ case IOAPIC_REG_ARB_ID:
+ break;
+
+ default:
+ index = (ioapic->ioregsel - 0x10) >> 1;
+
+ ioapic_debug("change redir index %x val %x", index, val);
+ if (index >= IOAPIC_NUM_PINS)
+ return;
+ if (ioapic->ioregsel & 1) {
+ ioapic->redirtbl[index].bits &= 0xffffffff;
+ ioapic->redirtbl[index].bits |= (u64) val << 32;
+ } else {
+ ioapic->redirtbl[index].bits &= ~0xffffffffULL;
+ ioapic->redirtbl[index].bits |= (u32) val;
+ ioapic->redirtbl[index].fields.remote_irr = 0;
+ }
+ if (ioapic->irr & (1 << index))
+ ioapic_service(ioapic, index);
+ break;
+ }
+}
+
+static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
+ struct kvm_lapic *target,
+ u8 vector, u8 trig_mode, u8 delivery_mode)
+{
+ ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode,
+ delivery_mode);
+
+ ASSERT((delivery_mode == dest_Fixed) ||
+ (delivery_mode == dest_LowestPrio));
+
+ kvm_apic_set_irq(target, vector, trig_mode);
+}
+
+static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+ u8 dest_mode)
+{
+ u32 mask = 0;
+ int i;
+ struct kvm *kvm = ioapic->kvm;
+ struct kvm_vcpu *vcpu;
+
+ ioapic_debug("dest %d dest_mode %d", dest, dest_mode);
+
+ if (dest_mode == 0) { /* Physical mode. */
+ if (dest == 0xFF) { /* Broadcast. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ if (kvm->vcpus[i] && kvm->vcpus[i]->apic)
+ mask |= 1 << i;
+ return mask;
+ }
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (kvm_apic_match_physical_addr(vcpu->apic, dest)) {
+ if (vcpu->apic)
+ mask = 1 << i;
+ break;
+ }
+ }
+ } else if (dest != 0) /* Logical mode, MDA non-zero. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (vcpu->apic &&
+ kvm_apic_match_logical_addr(vcpu->apic, dest))
+ mask |= 1 << vcpu->vcpu_id;
+ }
+ ioapic_debug("mask %x", mask);
+ return mask;
+}
+
+static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+{
+ u8 dest = ioapic->redirtbl[irq].fields.dest_id;
+ u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
+ u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
+ u8 vector = ioapic->redirtbl[irq].fields.vector;
+ u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
+ u32 deliver_bitmask;
+ struct kvm_lapic *target;
+ struct kvm_vcpu *vcpu;
+ int vcpu_id;
+
+ ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
+ "vector=%x trig_mode=%x",
+ dest, dest_mode, delivery_mode, vector, trig_mode);
+
+ deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
+ if (!deliver_bitmask) {
+ ioapic_debug("no target on destination");
+ return;
+ }
+
+ switch (delivery_mode) {
+ case dest_LowestPrio:
+ target =
+ kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask);
+ if (target != NULL)
+ ioapic_inj_irq(ioapic, target, vector,
+ trig_mode, delivery_mode);
+ else
+ ioapic_debug("null round robin: "
+ "mask=%x vector=%x delivery_mode=%x",
+ deliver_bitmask, vector, dest_LowestPrio);
+ break;
+ case dest_Fixed:
+ for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+ if (!(deliver_bitmask & (1 << vcpu_id)))
+ continue;
+ deliver_bitmask &= ~(1 << vcpu_id);
+ vcpu = ioapic->kvm->vcpus[vcpu_id];
+ if (vcpu) {
+ target = vcpu->apic;
+ ioapic_inj_irq(ioapic, target, vector,
+ trig_mode, delivery_mode);
+ }
+ }
+ break;
+
+ /* TODO: NMI */
+ default:
+ printk(KERN_WARNING "Unsupported delivery mode %d\n",
+ delivery_mode);
+ break;
+ }
+}
+
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
+{
+ u32 old_irr = ioapic->irr;
+ u32 mask = 1 << irq;
+ union ioapic_redir_entry entry;
+
+ if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
+ entry = ioapic->redirtbl[irq];
+ level ^= entry.fields.polarity;
+ if (!level)
+ ioapic->irr &= ~mask;
+ else {
+ ioapic->irr |= mask;
+ if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
+ || !entry.fields.remote_irr)
+ ioapic_service(ioapic, irq);
+ }
+ }
+}
+
+static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
+{
+ int i;
+
+ for (i = 0; i < IOAPIC_NUM_PINS; i++)
+ if (ioapic->redirtbl[i].fields.vector == vector)
+ return i;
+ return -1;
+}
+
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
+{
+ struct kvm_ioapic *ioapic = kvm->vioapic;
+ union ioapic_redir_entry *ent;
+ int gsi;
+
+ gsi = get_eoi_gsi(ioapic, vector);
+ if (gsi == -1) {
+ printk(KERN_WARNING "Can't find redir item for %d EOI\n",
+ vector);
+ return;
+ }
+
+ ent = &ioapic->redirtbl[gsi];
+ ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
+
+ ent->fields.remote_irr = 0;
+ if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
+ ioapic_deliver(ioapic, gsi);
+}
+
+static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+
+ return ((addr >= ioapic->base_address &&
+ (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
+}
+
+static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
+ void *val)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ u32 result;
+
+ ioapic_debug("addr %lx", (unsigned long)addr);
+ ASSERT(!(addr & 0xf)); /* check alignment */
+
+ addr &= 0xff;
+ switch (addr) {
+ case IOAPIC_REG_SELECT:
+ result = ioapic->ioregsel;
+ break;
+
+ case IOAPIC_REG_WINDOW:
+ result = ioapic_read_indirect(ioapic, addr, len);
+ break;
+
+ default:
+ result = 0;
+ break;
+ }
+ switch (len) {
+ case 8:
+ *(u64 *) val = result;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ memcpy(val, (char *)&result, len);
+ break;
+ default:
+ printk(KERN_WARNING "ioapic: wrong length %d\n", len);
+ }
+}
+
+static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
+ const void *val)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ u32 data;
+
+ ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n",
+ addr, len, val);
+ ASSERT(!(addr & 0xf)); /* check alignment */
+ if (len == 4 || len == 8)
+ data = *(u32 *) val;
+ else {
+ printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
+ return;
+ }
+
+ addr &= 0xff;
+ switch (addr) {
+ case IOAPIC_REG_SELECT:
+ ioapic->ioregsel = data;
+ break;
+
+ case IOAPIC_REG_WINDOW:
+ ioapic_write_indirect(ioapic, data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+int kvm_ioapic_init(struct kvm *kvm)
+{
+ struct kvm_ioapic *ioapic;
+ int i;
+
+ ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
+ if (!ioapic)
+ return -ENOMEM;
+ kvm->vioapic = ioapic;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++)
+ ioapic->redirtbl[i].fields.mask = 1;
+ ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
+ ioapic->dev.read = ioapic_mmio_read;
+ ioapic->dev.write = ioapic_mmio_write;
+ ioapic->dev.in_range = ioapic_in_range;
+ ioapic->dev.private = ioapic;
+ ioapic->kvm = kvm;
+ kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev);
+ return 0;
+}
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
new file mode 100644
index 00000000000..7628c7ff628
--- /dev/null
+++ b/drivers/kvm/irq.c
@@ -0,0 +1,98 @@
+/*
+ * irq.c: API for in kernel interrupt controller
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#include <linux/module.h>
+
+#include "kvm.h"
+#include "irq.h"
+
+/*
+ * check if there is pending interrupt without
+ * intack.
+ */
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
+{
+ struct kvm_pic *s;
+
+ if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */
+ if (kvm_apic_accept_pic_intr(v)) {
+ s = pic_irqchip(v->kvm); /* PIC */
+ return s->output;
+ } else
+ return 0;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
+
+/*
+ * Read pending interrupt vector and intack.
+ */
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+{
+ struct kvm_pic *s;
+ int vector;
+
+ vector = kvm_get_apic_interrupt(v); /* APIC */
+ if (vector == -1) {
+ if (kvm_apic_accept_pic_intr(v)) {
+ s = pic_irqchip(v->kvm);
+ s->output = 0; /* PIC */
+ vector = kvm_pic_read_irq(s);
+ }
+ }
+ return vector;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
+
+static void vcpu_kick_intr(void *info)
+{
+#ifdef DEBUG
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
+ printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
+#endif
+}
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+ int ipi_pcpu = vcpu->cpu;
+
+ if (waitqueue_active(&vcpu->wq)) {
+ wake_up_interruptible(&vcpu->wq);
+ ++vcpu->stat.halt_wakeup;
+ }
+ if (vcpu->guest_mode)
+ smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
+}
+
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
+{
+ kvm_inject_apic_timer_irqs(vcpu);
+ /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
+
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+ kvm_apic_timer_intr_post(vcpu, vec);
+ /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
new file mode 100644
index 00000000000..11fc014e2b3
--- /dev/null
+++ b/drivers/kvm/irq.h
@@ -0,0 +1,165 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include "kvm.h"
+
+typedef void irq_request_func(void *opaque, int level);
+
+struct kvm_kpic_state {
+ u8 last_irr; /* edge detection */
+ u8 irr; /* interrupt request register */
+ u8 imr; /* interrupt mask register */
+ u8 isr; /* interrupt service register */
+ u8 priority_add; /* highest irq priority */
+ u8 irq_base;
+ u8 read_reg_select;
+ u8 poll;
+ u8 special_mask;
+ u8 init_state;
+ u8 auto_eoi;
+ u8 rotate_on_auto_eoi;
+ u8 special_fully_nested_mode;
+ u8 init4; /* true if 4 byte init */
+ u8 elcr; /* PIIX edge/trigger selection */
+ u8 elcr_mask;
+ struct kvm_pic *pics_state;
+};
+
+struct kvm_pic {
+ struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
+ irq_request_func *irq_request;
+ void *irq_request_opaque;
+ int output; /* intr from master PIC */
+ struct kvm_io_device dev;
+};
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm);
+void kvm_pic_set_irq(void *opaque, int irq, int level);
+int kvm_pic_read_irq(struct kvm_pic *s);
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+void kvm_pic_update_irq(struct kvm_pic *s);
+
+#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS
+#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
+#define IOAPIC_EDGE_TRIG 0
+#define IOAPIC_LEVEL_TRIG 1
+
+#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
+#define IOAPIC_MEM_LENGTH 0x100
+
+/* Direct registers. */
+#define IOAPIC_REG_SELECT 0x00
+#define IOAPIC_REG_WINDOW 0x10
+#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */
+
+/* Indirect registers. */
+#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */
+#define IOAPIC_REG_VERSION 0x01
+#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */
+
+struct kvm_ioapic {
+ u64 base_address;
+ u32 ioregsel;
+ u32 id;
+ u32 irr;
+ u32 pad;
+ union ioapic_redir_entry {
+ u64 bits;
+ struct {
+ u8 vector;
+ u8 delivery_mode:3;
+ u8 dest_mode:1;
+ u8 delivery_status:1;
+ u8 polarity:1;
+ u8 remote_irr:1;
+ u8 trig_mode:1;
+ u8 mask:1;
+ u8 reserve:7;
+ u8 reserved[4];
+ u8 dest_id;
+ } fields;
+ } redirtbl[IOAPIC_NUM_PINS];
+ struct kvm_io_device dev;
+ struct kvm *kvm;
+};
+
+struct kvm_lapic {
+ unsigned long base_address;
+ struct kvm_io_device dev;
+ struct {
+ atomic_t pending;
+ s64 period; /* unit: ns */
+ u32 divide_count;
+ ktime_t last_update;
+ struct hrtimer dev;
+ } timer;
+ struct kvm_vcpu *vcpu;
+ struct page *regs_page;
+ void *regs;
+};
+
+#ifdef DEBUG
+#define ASSERT(x) \
+do { \
+ if (!(x)) { \
+ printk(KERN_EMERG "assertion failed %s: %d: %s\n", \
+ __FILE__, __LINE__, #x); \
+ BUG(); \
+ } \
+} while (0)
+#else
+#define ASSERT(x) do { } while (0)
+#endif
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
+int kvm_create_lapic(struct kvm_vcpu *vcpu);
+void kvm_lapic_reset(struct kvm_vcpu *vcpu);
+void kvm_free_apic(struct kvm_lapic *apic);
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+ unsigned long bitmap);
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
+int kvm_ioapic_init(struct kvm *kvm);
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+
+#endif
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 336be86c6f5..3b0bc4bda5f 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -13,60 +13,38 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/preempt.h>
#include <asm/signal.h>
-#include "vmx.h"
#include <linux/kvm.h>
#include <linux/kvm_para.h>
-#define CR0_PE_MASK (1ULL << 0)
-#define CR0_MP_MASK (1ULL << 1)
-#define CR0_TS_MASK (1ULL << 3)
-#define CR0_NE_MASK (1ULL << 5)
-#define CR0_WP_MASK (1ULL << 16)
-#define CR0_NW_MASK (1ULL << 29)
-#define CR0_CD_MASK (1ULL << 30)
-#define CR0_PG_MASK (1ULL << 31)
-
-#define CR3_WPT_MASK (1ULL << 3)
-#define CR3_PCD_MASK (1ULL << 4)
-
-#define CR3_RESEVED_BITS 0x07ULL
-#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
-#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
-
-#define CR4_VME_MASK (1ULL << 0)
-#define CR4_PSE_MASK (1ULL << 4)
-#define CR4_PAE_MASK (1ULL << 5)
-#define CR4_PGE_MASK (1ULL << 7)
-#define CR4_VMXE_MASK (1ULL << 13)
+#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
+#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
+#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL)
#define KVM_GUEST_CR0_MASK \
- (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
- | CR0_NW_MASK | CR0_CD_MASK)
+ (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
+ | X86_CR0_NW | X86_CR0_CD)
#define KVM_VM_CR0_ALWAYS_ON \
- (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \
- | CR0_MP_MASK)
+ (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
+ | X86_CR0_MP)
#define KVM_GUEST_CR4_MASK \
- (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
-#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
-#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+ (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
#define INVALID_PAGE (~(hpa_t)0)
#define UNMAPPED_GVA (~(gpa_t)0)
#define KVM_MAX_VCPUS 4
#define KVM_ALIAS_SLOTS 4
-#define KVM_MEMORY_SLOTS 4
+#define KVM_MEMORY_SLOTS 8
#define KVM_NUM_MMU_PAGES 1024
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
#define KVM_MAX_CPUID_ENTRIES 40
-#define FX_IMAGE_SIZE 512
-#define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
-
#define DE_VECTOR 0
#define NM_VECTOR 7
#define DF_VECTOR 8
@@ -158,15 +136,8 @@ struct kvm_mmu_page {
};
};
-struct vmcs {
- u32 revision_id;
- u32 abort;
- char data[0];
-};
-
-#define vmx_msr_entry kvm_msr_entry
-
struct kvm_vcpu;
+extern struct kmem_cache *kvm_vcpu_cache;
/*
* x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
@@ -260,6 +231,7 @@ struct kvm_stat {
u32 signal_exits;
u32 irq_window_exits;
u32 halt_exits;
+ u32 halt_wakeup;
u32 request_irq_exits;
u32 irq_exits;
u32 light_exits;
@@ -328,21 +300,17 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
struct kvm_vcpu {
struct kvm *kvm;
- union {
- struct vmcs *vmcs;
- struct vcpu_svm *svm;
- };
+ struct preempt_notifier preempt_notifier;
+ int vcpu_id;
struct mutex mutex;
int cpu;
- int launched;
u64 host_tsc;
struct kvm_run *run;
int interrupt_window_open;
int guest_mode;
unsigned long requests;
unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
- unsigned long irq_pending[NR_IRQ_WORDS];
+ DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
unsigned long rip; /* needs vcpu_load_rsp_rip() */
@@ -357,15 +325,15 @@ struct kvm_vcpu {
u64 pdptrs[4]; /* pae */
u64 shadow_efer;
u64 apic_base;
+ struct kvm_lapic *apic; /* kernel irqchip context */
+#define VCPU_MP_STATE_RUNNABLE 0
+#define VCPU_MP_STATE_UNINITIALIZED 1
+#define VCPU_MP_STATE_INIT_RECEIVED 2
+#define VCPU_MP_STATE_SIPI_RECEIVED 3
+#define VCPU_MP_STATE_HALTED 4
+ int mp_state;
+ int sipi_vector;
u64 ia32_misc_enable_msr;
- int nmsrs;
- int save_nmsrs;
- int msr_offset_efer;
-#ifdef CONFIG_X86_64
- int msr_offset_kernel_gs_base;
-#endif
- struct vmx_msr_entry *guest_msrs;
- struct vmx_msr_entry *host_msrs;
struct kvm_mmu mmu;
@@ -379,16 +347,10 @@ struct kvm_vcpu {
struct kvm_guest_debug guest_debug;
- char fx_buf[FX_BUF_SIZE];
- char *host_fx_image;
- char *guest_fx_image;
+ struct i387_fxsave_struct host_fx_image;
+ struct i387_fxsave_struct guest_fx_image;
int fpu_active;
int guest_fpu_loaded;
- struct vmx_host_state {
- int loaded;
- u16 fs_sel, gs_sel, ldt_sel;
- int fs_gs_ldt_reload_needed;
- } vmx_host_state;
int mmio_needed;
int mmio_read_completed;
@@ -399,6 +361,7 @@ struct kvm_vcpu {
gva_t mmio_fault_cr2;
struct kvm_pio_request pio;
void *pio_data;
+ wait_queue_head_t wq;
int sigset_active;
sigset_t sigset;
@@ -436,7 +399,7 @@ struct kvm_memory_slot {
};
struct kvm {
- spinlock_t lock; /* protects everything except vcpus */
+ struct mutex lock; /* protects everything except vcpus */
int naliases;
struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
int nmemslots;
@@ -447,39 +410,59 @@ struct kvm {
struct list_head active_mmu_pages;
int n_free_mmu_pages;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
- int nvcpus;
- struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
- int memory_config_version;
- int busy;
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
unsigned long rmap_overflow;
struct list_head vm_list;
struct file *filp;
struct kvm_io_bus mmio_bus;
struct kvm_io_bus pio_bus;
+ struct kvm_pic *vpic;
+ struct kvm_ioapic *vioapic;
+ int round_robin_prev_vcpu;
};
+static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
+{
+ return kvm->vpic;
+}
+
+static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
+{
+ return kvm->vioapic;
+}
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+ return pic_irqchip(kvm) != 0;
+}
+
struct descriptor_table {
u16 limit;
unsigned long base;
} __attribute__((packed));
-struct kvm_arch_ops {
+struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
void (*hardware_enable)(void *dummy); /* __init */
void (*hardware_disable)(void *dummy);
+ void (*check_processor_compatibility)(void *rtn);
int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */
- int (*vcpu_create)(struct kvm_vcpu *vcpu);
+ /* Create, but do not attach this VCPU */
+ struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
+ void (*vcpu_reset)(struct kvm_vcpu *vcpu);
- void (*vcpu_load)(struct kvm_vcpu *vcpu);
+ void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
+ void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
void (*vcpu_decache)(struct kvm_vcpu *vcpu);
int (*set_guest_debug)(struct kvm_vcpu *vcpu,
struct kvm_debug_guest *dbg);
+ void (*guest_debug_pre)(struct kvm_vcpu *vcpu);
int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -505,27 +488,43 @@ struct kvm_arch_ops {
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
- void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr);
void (*tlb_flush)(struct kvm_vcpu *vcpu);
void (*inject_page_fault)(struct kvm_vcpu *vcpu,
unsigned long addr, u32 err_code);
void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
- int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
- int (*vcpu_setup)(struct kvm_vcpu *vcpu);
+ void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+ int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu,
unsigned char *hypercall_addr);
+ int (*get_irq)(struct kvm_vcpu *vcpu);
+ void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
+ void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
+ void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
+ struct kvm_run *run);
};
-extern struct kvm_arch_ops *kvm_arch_ops;
+extern struct kvm_x86_ops *kvm_x86_ops;
+
+/* The guest did something we don't support. */
+#define pr_unimpl(vcpu, fmt, ...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_ERR "kvm: %i: cpu%i " fmt, \
+ current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
+ } while(0)
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
-void kvm_exit_arch(void);
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+ struct module *module);
+void kvm_exit_x86(void);
int kvm_mmu_module_init(void);
void kvm_mmu_module_exit(void);
@@ -545,8 +544,6 @@ static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
-void kvm_emulator_want_group7_invlpg(void);
-
extern hpa_t bad_page_address;
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
@@ -561,6 +558,7 @@ enum emulation_result {
int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long cr2, u16 error_code);
+void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
@@ -574,9 +572,11 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
- int size, unsigned long count, int string, int down,
- gva_t address, int rep, unsigned port);
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned port);
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int down,
+ gva_t address, int rep, unsigned port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
@@ -590,34 +590,33 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+unsigned long get_cr8(struct kvm_vcpu *vcpu);
void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
void fx_init(struct kvm_vcpu *vcpu);
-void load_msrs(struct vmx_msr_entry *e, int n);
-void save_msrs(struct vmx_msr_entry *e, int n);
void kvm_resched(struct kvm_vcpu *vcpu);
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_flush_remote_tlbs(struct kvm *kvm);
-int kvm_read_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *dest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *data);
+int emulator_read_std(unsigned long addr,
+ void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu);
+int emulator_write_emulated(unsigned long addr,
+ const void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu);
unsigned long segment_base(u16 selector);
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
- const u8 *old, const u8 *new, int bytes);
+ const u8 *new, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
int kvm_mmu_load(struct kvm_vcpu *vcpu);
@@ -625,6 +624,16 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu);
int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
+static inline void kvm_guest_enter(void)
+{
+ current->flags |= PF_VCPU;
+}
+
+static inline void kvm_guest_exit(void)
+{
+ current->flags &= ~PF_VCPU;
+}
+
static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
@@ -656,17 +665,17 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu)
static inline int is_pae(struct kvm_vcpu *vcpu)
{
- return vcpu->cr4 & CR4_PAE_MASK;
+ return vcpu->cr4 & X86_CR4_PAE;
}
static inline int is_pse(struct kvm_vcpu *vcpu)
{
- return vcpu->cr4 & CR4_PSE_MASK;
+ return vcpu->cr4 & X86_CR4_PSE;
}
static inline int is_paging(struct kvm_vcpu *vcpu)
{
- return vcpu->cr0 & CR0_PG_MASK;
+ return vcpu->cr0 & X86_CR0_PG;
}
static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
@@ -746,12 +755,12 @@ static inline unsigned long read_msr(unsigned long msr)
}
#endif
-static inline void fx_save(void *image)
+static inline void fx_save(struct i387_fxsave_struct *image)
{
asm ("fxsave (%0)":: "r" (image));
}
-static inline void fx_restore(void *image)
+static inline void fx_restore(struct i387_fxsave_struct *image)
{
asm ("fxrstor (%0)":: "r" (image));
}
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index cd0557954e5..af2d288c881 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -18,6 +18,7 @@
#include "kvm.h"
#include "x86_emulate.h"
#include "segment_descriptor.h"
+#include "irq.h"
#include <linux/kvm.h>
#include <linux/module.h>
@@ -37,6 +38,7 @@
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/anon_inodes.h>
+#include <linux/profile.h>
#include <asm/processor.h>
#include <asm/msr.h>
@@ -52,9 +54,11 @@ static LIST_HEAD(vm_list);
static cpumask_t cpus_hardware_enabled;
-struct kvm_arch_ops *kvm_arch_ops;
+struct kvm_x86_ops *kvm_x86_ops;
+struct kmem_cache *kvm_vcpu_cache;
+EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
-static void hardware_disable(void *ignored);
+static __read_mostly struct preempt_ops kvm_preempt_ops;
#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
@@ -73,6 +77,7 @@ static struct kvm_stats_debugfs_item {
{ "signal_exits", STAT_OFFSET(signal_exits) },
{ "irq_window", STAT_OFFSET(irq_window_exits) },
{ "halt_exits", STAT_OFFSET(halt_exits) },
+ { "halt_wakeup", STAT_OFFSET(halt_wakeup) },
{ "request_irq", STAT_OFFSET(request_irq_exits) },
{ "irq_exits", STAT_OFFSET(irq_exits) },
{ "light_exits", STAT_OFFSET(light_exits) },
@@ -84,10 +89,17 @@ static struct dentry *debugfs_dir;
#define MAX_IO_MSRS 256
-#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
-#define LMSW_GUEST_MASK 0x0eULL
-#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
-#define CR8_RESEVED_BITS (~0x0fULL)
+#define CR0_RESERVED_BITS \
+ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+#define CR4_RESERVED_BITS \
+ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
+ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \
+ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
#define EFER_RESERVED_BITS 0xfffffffffffff2fe
#ifdef CONFIG_X86_64
@@ -139,82 +151,14 @@ static inline int valid_vcpu(int n)
return likely(n >= 0 && n < KVM_MAX_VCPUS);
}
-int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
- void *dest)
-{
- unsigned char *host_buf = dest;
- unsigned long req_size = size;
-
- while (size) {
- hpa_t paddr;
- unsigned now;
- unsigned offset;
- hva_t guest_buf;
-
- paddr = gva_to_hpa(vcpu, addr);
-
- if (is_error_hpa(paddr))
- break;
-
- guest_buf = (hva_t)kmap_atomic(
- pfn_to_page(paddr >> PAGE_SHIFT),
- KM_USER0);
- offset = addr & ~PAGE_MASK;
- guest_buf |= offset;
- now = min(size, PAGE_SIZE - offset);
- memcpy(host_buf, (void*)guest_buf, now);
- host_buf += now;
- addr += now;
- size -= now;
- kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
- }
- return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_read_guest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
- void *data)
-{
- unsigned char *host_buf = data;
- unsigned long req_size = size;
-
- while (size) {
- hpa_t paddr;
- unsigned now;
- unsigned offset;
- hva_t guest_buf;
- gfn_t gfn;
-
- paddr = gva_to_hpa(vcpu, addr);
-
- if (is_error_hpa(paddr))
- break;
-
- gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT;
- mark_page_dirty(vcpu->kvm, gfn);
- guest_buf = (hva_t)kmap_atomic(
- pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
- offset = addr & ~PAGE_MASK;
- guest_buf |= offset;
- now = min(size, PAGE_SIZE - offset);
- memcpy((void*)guest_buf, host_buf, now);
- host_buf += now;
- addr += now;
- size -= now;
- kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
- }
- return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_write_guest);
-
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
return;
vcpu->guest_fpu_loaded = 1;
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ fx_save(&vcpu->host_fx_image);
+ fx_restore(&vcpu->guest_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
@@ -224,8 +168,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
return;
vcpu->guest_fpu_loaded = 0;
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
@@ -234,13 +178,21 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
*/
static void vcpu_load(struct kvm_vcpu *vcpu)
{
+ int cpu;
+
mutex_lock(&vcpu->mutex);
- kvm_arch_ops->vcpu_load(vcpu);
+ cpu = get_cpu();
+ preempt_notifier_register(&vcpu->preempt_notifier);
+ kvm_x86_ops->vcpu_load(vcpu, cpu);
+ put_cpu();
}
static void vcpu_put(struct kvm_vcpu *vcpu)
{
- kvm_arch_ops->vcpu_put(vcpu);
+ preempt_disable();
+ kvm_x86_ops->vcpu_put(vcpu);
+ preempt_notifier_unregister(&vcpu->preempt_notifier);
+ preempt_enable();
mutex_unlock(&vcpu->mutex);
}
@@ -261,8 +213,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
atomic_set(&completed, 0);
cpus_clear(cpus);
needed = 0;
- for (i = 0; i < kvm->nvcpus; ++i) {
- vcpu = &kvm->vcpus[i];
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
continue;
cpu = vcpu->cpu;
@@ -286,37 +240,79 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
}
}
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
+{
+ struct page *page;
+ int r;
+
+ mutex_init(&vcpu->mutex);
+ vcpu->cpu = -1;
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ vcpu->kvm = kvm;
+ vcpu->vcpu_id = id;
+ if (!irqchip_in_kernel(kvm) || id == 0)
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ else
+ vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED;
+ init_waitqueue_head(&vcpu->wq);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ vcpu->run = page_address(page);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail_free_run;
+ }
+ vcpu->pio_data = page_address(page);
+
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto fail_free_pio_data;
+
+ return 0;
+
+fail_free_pio_data:
+ free_page((unsigned long)vcpu->pio_data);
+fail_free_run:
+ free_page((unsigned long)vcpu->run);
+fail:
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_init);
+
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+ kvm_mmu_destroy(vcpu);
+ if (vcpu->apic)
+ hrtimer_cancel(&vcpu->apic->timer.dev);
+ kvm_free_apic(vcpu->apic);
+ free_page((unsigned long)vcpu->pio_data);
+ free_page((unsigned long)vcpu->run);
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
+
static struct kvm *kvm_create_vm(void)
{
struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
- int i;
if (!kvm)
return ERR_PTR(-ENOMEM);
kvm_io_bus_init(&kvm->pio_bus);
- spin_lock_init(&kvm->lock);
+ mutex_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
kvm_io_bus_init(&kvm->mmio_bus);
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu = &kvm->vcpus[i];
-
- mutex_init(&vcpu->mutex);
- vcpu->cpu = -1;
- vcpu->kvm = kvm;
- vcpu->mmu.root_hpa = INVALID_PAGE;
- }
spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
return kvm;
}
-static int kvm_dev_open(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
/*
* Free any memory in @free but not in @dont.
*/
@@ -353,7 +349,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
{
int i;
- for (i = 0; i < 2; ++i)
+ for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
if (vcpu->pio.guest_pages[i]) {
__free_page(vcpu->pio.guest_pages[i]);
vcpu->pio.guest_pages[i] = NULL;
@@ -362,30 +358,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->vmcs)
- return;
-
vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
}
-static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
-{
- if (!vcpu->vmcs)
- return;
-
- vcpu_load(vcpu);
- kvm_mmu_destroy(vcpu);
- vcpu_put(vcpu);
- kvm_arch_ops->vcpu_free(vcpu);
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
- free_page((unsigned long)vcpu->pio_data);
- vcpu->pio_data = NULL;
- free_pio_guest_pages(vcpu);
-}
-
static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
@@ -394,14 +371,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
* Unpin any mmu pages first.
*/
for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_free_vcpu(&kvm->vcpus[i]);
-}
+ if (kvm->vcpus[i])
+ kvm_unload_vcpu_mmu(kvm->vcpus[i]);
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ if (kvm->vcpus[i]) {
+ kvm_x86_ops->vcpu_free(kvm->vcpus[i]);
+ kvm->vcpus[i] = NULL;
+ }
+ }
-static int kvm_dev_release(struct inode *inode, struct file *filp)
-{
- return 0;
}
static void kvm_destroy_vm(struct kvm *kvm)
@@ -411,6 +389,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
spin_unlock(&kvm_lock);
kvm_io_bus_destroy(&kvm->pio_bus);
kvm_io_bus_destroy(&kvm->mmio_bus);
+ kfree(kvm->vpic);
+ kfree(kvm->vioapic);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
kfree(kvm);
@@ -426,7 +406,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
static void inject_gp(struct kvm_vcpu *vcpu)
{
- kvm_arch_ops->inject_gp(vcpu, 0);
+ kvm_x86_ops->inject_gp(vcpu, 0);
}
/*
@@ -437,58 +417,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
int i;
- u64 pdpte;
u64 *pdpt;
int ret;
struct page *page;
+ u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
page = gfn_to_page(vcpu->kvm, pdpt_gfn);
- /* FIXME: !page - emulate? 0xff? */
+ if (!page) {
+ ret = 0;
+ goto out;
+ }
+
pdpt = kmap_atomic(page, KM_USER0);
+ memcpy(pdpte, pdpt+offset, sizeof(pdpte));
+ kunmap_atomic(pdpt, KM_USER0);
- ret = 1;
- for (i = 0; i < 4; ++i) {
- pdpte = pdpt[offset + i];
- if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
+ for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
+ if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
ret = 0;
goto out;
}
}
+ ret = 1;
- for (i = 0; i < 4; ++i)
- vcpu->pdptrs[i] = pdpt[offset + i];
-
+ memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
out:
- kunmap_atomic(pdpt, KM_USER0);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return ret;
}
void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
- if (cr0 & CR0_RESEVED_BITS) {
+ if (cr0 & CR0_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
cr0, vcpu->cr0);
inject_gp(vcpu);
return;
}
- if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+ if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
inject_gp(vcpu);
return;
}
- if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+ if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
"and a clear PE flag\n");
inject_gp(vcpu);
return;
}
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
#ifdef CONFIG_X86_64
if ((vcpu->shadow_efer & EFER_LME)) {
int cs_db, cs_l;
@@ -499,7 +481,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
inject_gp(vcpu);
return;
}
- kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
if (cs_l) {
printk(KERN_DEBUG "set_cr0: #GP, start paging "
"in long mode while CS.L == 1\n");
@@ -518,12 +500,12 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
- kvm_arch_ops->set_cr0(vcpu, cr0);
+ kvm_x86_ops->set_cr0(vcpu, cr0);
vcpu->cr0 = cr0;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
kvm_mmu_reset_context(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return;
}
EXPORT_SYMBOL_GPL(set_cr0);
@@ -536,62 +518,72 @@ EXPORT_SYMBOL_GPL(lmsw);
void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
- if (cr4 & CR4_RESEVED_BITS) {
+ if (cr4 & CR4_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
inject_gp(vcpu);
return;
}
if (is_long_mode(vcpu)) {
- if (!(cr4 & CR4_PAE_MASK)) {
+ if (!(cr4 & X86_CR4_PAE)) {
printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
"in long mode\n");
inject_gp(vcpu);
return;
}
- } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+ } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE)
&& !load_pdptrs(vcpu, vcpu->cr3)) {
printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
inject_gp(vcpu);
+ return;
}
- if (cr4 & CR4_VMXE_MASK) {
+ if (cr4 & X86_CR4_VMXE) {
printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
inject_gp(vcpu);
return;
}
- kvm_arch_ops->set_cr4(vcpu, cr4);
- spin_lock(&vcpu->kvm->lock);
+ kvm_x86_ops->set_cr4(vcpu, cr4);
+ vcpu->cr4 = cr4;
+ mutex_lock(&vcpu->kvm->lock);
kvm_mmu_reset_context(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
}
EXPORT_SYMBOL_GPL(set_cr4);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
if (is_long_mode(vcpu)) {
- if (cr3 & CR3_L_MODE_RESEVED_BITS) {
+ if (cr3 & CR3_L_MODE_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
inject_gp(vcpu);
return;
}
} else {
- if (cr3 & CR3_RESEVED_BITS) {
- printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
- inject_gp(vcpu);
- return;
- }
- if (is_paging(vcpu) && is_pae(vcpu) &&
- !load_pdptrs(vcpu, cr3)) {
- printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
- "reserved bits\n");
- inject_gp(vcpu);
- return;
+ if (is_pae(vcpu)) {
+ if (cr3 & CR3_PAE_RESERVED_BITS) {
+ printk(KERN_DEBUG
+ "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
+ printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+ "reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ } else {
+ if (cr3 & CR3_NONPAE_RESERVED_BITS) {
+ printk(KERN_DEBUG
+ "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
}
}
- vcpu->cr3 = cr3;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
/*
* Does the new cr3 value map to physical memory? (Note, we
* catch an invalid cr3 even in real-mode, because it would
@@ -603,46 +595,73 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
*/
if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
inject_gp(vcpu);
- else
+ else {
+ vcpu->cr3 = cr3;
vcpu->mmu.new_cr3(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ }
+ mutex_unlock(&vcpu->kvm->lock);
}
EXPORT_SYMBOL_GPL(set_cr3);
void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
- if ( cr8 & CR8_RESEVED_BITS) {
+ if (cr8 & CR8_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
inject_gp(vcpu);
return;
}
- vcpu->cr8 = cr8;
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_lapic_set_tpr(vcpu, cr8);
+ else
+ vcpu->cr8 = cr8;
}
EXPORT_SYMBOL_GPL(set_cr8);
-void fx_init(struct kvm_vcpu *vcpu)
+unsigned long get_cr8(struct kvm_vcpu *vcpu)
+{
+ if (irqchip_in_kernel(vcpu->kvm))
+ return kvm_lapic_get_cr8(vcpu);
+ else
+ return vcpu->cr8;
+}
+EXPORT_SYMBOL_GPL(get_cr8);
+
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
{
- struct __attribute__ ((__packed__)) fx_image_s {
- u16 control; //fcw
- u16 status; //fsw
- u16 tag; // ftw
- u16 opcode; //fop
- u64 ip; // fpu ip
- u64 operand;// fpu dp
- u32 mxcsr;
- u32 mxcsr_mask;
+ if (irqchip_in_kernel(vcpu->kvm))
+ return vcpu->apic_base;
+ else
+ return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_get_apic_base);
- } *fx_image;
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
+{
+ /* TODO: reserve bits check */
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_lapic_set_base(vcpu, data);
+ else
+ vcpu->apic_base = data;
+}
+EXPORT_SYMBOL_GPL(kvm_set_apic_base);
+
+void fx_init(struct kvm_vcpu *vcpu)
+{
+ unsigned after_mxcsr_mask;
- fx_save(vcpu->host_fx_image);
+ /* Initialize guest FPU by resetting ours and saving into guest's */
+ preempt_disable();
+ fx_save(&vcpu->host_fx_image);
fpu_init();
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
+ preempt_enable();
- fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
- fx_image->mxcsr = 0x1f80;
- memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
- 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+ vcpu->cr0 |= X86_CR0_ET;
+ after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
+ vcpu->guest_fx_image.mxcsr = 0x1f80;
+ memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
+ 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
}
EXPORT_SYMBOL_GPL(fx_init);
@@ -661,7 +680,6 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
unsigned long i;
struct kvm_memory_slot *memslot;
struct kvm_memory_slot old, new;
- int memory_config_version;
r = -EINVAL;
/* General sanity checks */
@@ -681,10 +699,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
if (!npages)
mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
-raced:
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
- memory_config_version = kvm->memory_config_version;
new = old = *memslot;
new.base_gfn = base_gfn;
@@ -707,11 +723,6 @@ raced:
(base_gfn >= s->base_gfn + s->npages)))
goto out_unlock;
}
- /*
- * Do memory allocations outside lock. memory_config_version will
- * detect any races.
- */
- spin_unlock(&kvm->lock);
/* Deallocate if slot is being removed */
if (!npages)
@@ -728,14 +739,14 @@ raced:
new.phys_mem = vmalloc(npages * sizeof(struct page *));
if (!new.phys_mem)
- goto out_free;
+ goto out_unlock;
memset(new.phys_mem, 0, npages * sizeof(struct page *));
for (i = 0; i < npages; ++i) {
new.phys_mem[i] = alloc_page(GFP_HIGHUSER
| __GFP_ZERO);
if (!new.phys_mem[i])
- goto out_free;
+ goto out_unlock;
set_page_private(new.phys_mem[i],0);
}
}
@@ -746,39 +757,25 @@ raced:
new.dirty_bitmap = vmalloc(dirty_bytes);
if (!new.dirty_bitmap)
- goto out_free;
+ goto out_unlock;
memset(new.dirty_bitmap, 0, dirty_bytes);
}
- spin_lock(&kvm->lock);
-
- if (memory_config_version != kvm->memory_config_version) {
- spin_unlock(&kvm->lock);
- kvm_free_physmem_slot(&new, &old);
- goto raced;
- }
-
- r = -EAGAIN;
- if (kvm->busy)
- goto out_unlock;
-
if (mem->slot >= kvm->nmemslots)
kvm->nmemslots = mem->slot + 1;
*memslot = new;
- ++kvm->memory_config_version;
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
kvm_flush_remote_tlbs(kvm);
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
kvm_free_physmem_slot(&old, &new);
return 0;
out_unlock:
- spin_unlock(&kvm->lock);
-out_free:
+ mutex_unlock(&kvm->lock);
kvm_free_physmem_slot(&new, &old);
out:
return r;
@@ -795,14 +792,8 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
int n;
unsigned long any = 0;
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
- /*
- * Prevent changes to guest memory configuration even while the lock
- * is not taken.
- */
- ++kvm->busy;
- spin_unlock(&kvm->lock);
r = -EINVAL;
if (log->slot >= KVM_MEMORY_SLOTS)
goto out;
@@ -821,18 +812,17 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
- spin_lock(&kvm->lock);
- kvm_mmu_slot_remove_write_access(kvm, log->slot);
- kvm_flush_remote_tlbs(kvm);
- memset(memslot->dirty_bitmap, 0, n);
- spin_unlock(&kvm->lock);
+ /* If nothing is dirty, don't bother messing with page tables. */
+ if (any) {
+ kvm_mmu_slot_remove_write_access(kvm, log->slot);
+ kvm_flush_remote_tlbs(kvm);
+ memset(memslot->dirty_bitmap, 0, n);
+ }
r = 0;
out:
- spin_lock(&kvm->lock);
- --kvm->busy;
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
return r;
}
@@ -862,7 +852,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
< alias->target_phys_addr)
goto out;
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
p = &kvm->aliases[alias->slot];
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
@@ -876,7 +866,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
kvm_mmu_zap_all(kvm);
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
return 0;
@@ -884,6 +874,63 @@ out:
return r;
}
+static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_PIC_MASTER:
+ memcpy (&chip->chip.pic,
+ &pic_irqchip(kvm)->pics[0],
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_PIC_SLAVE:
+ memcpy (&chip->chip.pic,
+ &pic_irqchip(kvm)->pics[1],
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy (&chip->chip.ioapic,
+ ioapic_irqchip(kvm),
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
+static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_PIC_MASTER:
+ memcpy (&pic_irqchip(kvm)->pics[0],
+ &chip->chip.pic,
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_PIC_SLAVE:
+ memcpy (&pic_irqchip(kvm)->pics[1],
+ &chip->chip.pic,
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy (ioapic_irqchip(kvm),
+ &chip->chip.ioapic,
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ kvm_pic_update_irq(pic_irqchip(kvm));
+ return r;
+}
+
static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
@@ -930,37 +977,26 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(gfn_to_page);
+/* WARNING: Does not work on aliased pages. */
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
- int i;
struct kvm_memory_slot *memslot;
- unsigned long rel_gfn;
- for (i = 0; i < kvm->nmemslots; ++i) {
- memslot = &kvm->memslots[i];
-
- if (gfn >= memslot->base_gfn
- && gfn < memslot->base_gfn + memslot->npages) {
+ memslot = __gfn_to_memslot(kvm, gfn);
+ if (memslot && memslot->dirty_bitmap) {
+ unsigned long rel_gfn = gfn - memslot->base_gfn;
- if (!memslot->dirty_bitmap)
- return;
-
- rel_gfn = gfn - memslot->base_gfn;
-
- /* avoid RMW */
- if (!test_bit(rel_gfn, memslot->dirty_bitmap))
- set_bit(rel_gfn, memslot->dirty_bitmap);
- return;
- }
+ /* avoid RMW */
+ if (!test_bit(rel_gfn, memslot->dirty_bitmap))
+ set_bit(rel_gfn, memslot->dirty_bitmap);
}
}
-static int emulator_read_std(unsigned long addr,
+int emulator_read_std(unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
void *data = val;
while (bytes) {
@@ -990,26 +1026,42 @@ static int emulator_read_std(unsigned long addr,
return X86EMUL_CONTINUE;
}
+EXPORT_SYMBOL_GPL(emulator_read_std);
static int emulator_write_std(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
- addr, bytes);
+ pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes);
return X86EMUL_UNHANDLEABLE;
}
+/*
+ * Only apic need an MMIO device hook, so shortcut now..
+ */
+static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ struct kvm_io_device *dev;
+
+ if (vcpu->apic) {
+ dev = &vcpu->apic->dev;
+ if (dev->in_range(dev, addr))
+ return dev;
+ }
+ return NULL;
+}
+
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
gpa_t addr)
{
- /*
- * Note that its important to have this wrapper function because
- * in the very near future we will be checking for MMIOs against
- * the LAPIC as well as the general MMIO bus
- */
- return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+ struct kvm_io_device *dev;
+
+ dev = vcpu_find_pervcpu_dev(vcpu, addr);
+ if (dev == NULL)
+ dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+ return dev;
}
static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
@@ -1021,9 +1073,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
struct kvm_io_device *mmio_dev;
gpa_t gpa;
@@ -1031,7 +1082,7 @@ static int emulator_read_emulated(unsigned long addr,
memcpy(val, vcpu->mmio_data, bytes);
vcpu->mmio_read_completed = 0;
return X86EMUL_CONTINUE;
- } else if (emulator_read_std(addr, val, bytes, ctxt)
+ } else if (emulator_read_std(addr, val, bytes, vcpu)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
@@ -1061,7 +1112,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
{
struct page *page;
void *virt;
- unsigned offset = offset_in_page(gpa);
if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
return 0;
@@ -1070,7 +1120,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
return 0;
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
- kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+ kvm_mmu_pte_write(vcpu, gpa, val, bytes);
memcpy(virt + offset_in_page(gpa), val, bytes);
kunmap_atomic(virt, KM_USER0);
return 1;
@@ -1079,14 +1129,13 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
static int emulator_write_emulated_onepage(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
struct kvm_io_device *mmio_dev;
gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
if (gpa == UNMAPPED_GVA) {
- kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
+ kvm_x86_ops->inject_page_fault(vcpu, addr, 2);
return X86EMUL_PROPAGATE_FAULT;
}
@@ -1111,31 +1160,32 @@ static int emulator_write_emulated_onepage(unsigned long addr,
return X86EMUL_CONTINUE;
}
-static int emulator_write_emulated(unsigned long addr,
+int emulator_write_emulated(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
/* Crossing a page boundary? */
if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
int rc, now;
now = -addr & ~PAGE_MASK;
- rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+ rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
if (rc != X86EMUL_CONTINUE)
return rc;
addr += now;
val += now;
bytes -= now;
}
- return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+ return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
}
+EXPORT_SYMBOL_GPL(emulator_write_emulated);
static int emulator_cmpxchg_emulated(unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
static int reported;
@@ -1143,12 +1193,12 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
reported = 1;
printk(KERN_WARNING "kvm: emulating exchange as write\n");
}
- return emulator_write_emulated(addr, new, bytes, ctxt);
+ return emulator_write_emulated(addr, new, bytes, vcpu);
}
static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
- return kvm_arch_ops->get_segment_base(vcpu, seg);
+ return kvm_x86_ops->get_segment_base(vcpu, seg);
}
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
@@ -1158,10 +1208,8 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
int emulate_clts(struct kvm_vcpu *vcpu)
{
- unsigned long cr0;
-
- cr0 = vcpu->cr0 & ~CR0_TS_MASK;
- kvm_arch_ops->set_cr0(vcpu, cr0);
+ vcpu->cr0 &= ~X86_CR0_TS;
+ kvm_x86_ops->set_cr0(vcpu, vcpu->cr0);
return X86EMUL_CONTINUE;
}
@@ -1171,11 +1219,10 @@ int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
switch (dr) {
case 0 ... 3:
- *dest = kvm_arch_ops->get_dr(vcpu, dr);
+ *dest = kvm_x86_ops->get_dr(vcpu, dr);
return X86EMUL_CONTINUE;
default:
- printk(KERN_DEBUG "%s: unexpected dr %u\n",
- __FUNCTION__, dr);
+ pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
return X86EMUL_UNHANDLEABLE;
}
}
@@ -1185,7 +1232,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
int exception;
- kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
+ kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
if (exception) {
/* FIXME: better handling */
return X86EMUL_UNHANDLEABLE;
@@ -1193,25 +1240,25 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
return X86EMUL_CONTINUE;
}
-static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
+void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
{
static int reported;
u8 opcodes[4];
- unsigned long rip = ctxt->vcpu->rip;
+ unsigned long rip = vcpu->rip;
unsigned long rip_linear;
- rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
+ rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
if (reported)
return;
- emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+ emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
- printk(KERN_ERR "emulation failed but !mmio_needed?"
- " rip %lx %02x %02x %02x %02x\n",
- rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+ printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
+ context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
reported = 1;
}
+EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
struct x86_emulate_ops emulate_ops = {
.read_std = emulator_read_std,
@@ -1231,12 +1278,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
int cs_db, cs_l;
vcpu->mmio_fault_cr2 = cr2;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
- kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
emulate_ctxt.vcpu = vcpu;
- emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
+ emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
emulate_ctxt.cr2 = cr2;
emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
? X86EMUL_MODE_REAL : cs_l
@@ -1259,9 +1306,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
vcpu->mmio_is_write = 0;
+ vcpu->pio.string = 0;
r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
+ if (vcpu->pio.string)
+ return EMULATE_DO_MMIO;
if ((r || vcpu->mmio_is_write) && run) {
+ run->exit_reason = KVM_EXIT_MMIO;
run->mmio.phys_addr = vcpu->mmio_phys_addr;
memcpy(run->mmio.data, vcpu->mmio_data, 8);
run->mmio.len = vcpu->mmio_size;
@@ -1272,14 +1323,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
return EMULATE_DONE;
if (!vcpu->mmio_needed) {
- report_emulation_failure(&emulate_ctxt);
+ kvm_report_emulation_failure(vcpu, "mmio");
return EMULATE_FAIL;
}
return EMULATE_DO_MMIO;
}
- kvm_arch_ops->decache_regs(vcpu);
- kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
+ kvm_x86_ops->decache_regs(vcpu);
+ kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags);
if (vcpu->mmio_is_write) {
vcpu->mmio_needed = 0;
@@ -1290,14 +1341,45 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);
-int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+/*
+ * The vCPU has executed a HLT instruction with in-kernel mode enabled.
+ */
+static void kvm_vcpu_block(struct kvm_vcpu *vcpu)
{
- if (vcpu->irq_summary)
- return 1;
+ DECLARE_WAITQUEUE(wait, current);
- vcpu->run->exit_reason = KVM_EXIT_HLT;
+ add_wait_queue(&vcpu->wq, &wait);
+
+ /*
+ * We will block until either an interrupt or a signal wakes us up
+ */
+ while (!kvm_cpu_has_interrupt(vcpu)
+ && !signal_pending(current)
+ && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE
+ && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ vcpu_put(vcpu);
+ schedule();
+ vcpu_load(vcpu);
+ }
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcpu->wq, &wait);
+}
+
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
++vcpu->stat.halt_exits;
- return 0;
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ vcpu->mp_state = VCPU_MP_STATE_HALTED;
+ kvm_vcpu_block(vcpu);
+ if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE)
+ return -EINTR;
+ return 1;
+ } else {
+ vcpu->run->exit_reason = KVM_EXIT_HLT;
+ return 0;
+ }
}
EXPORT_SYMBOL_GPL(kvm_emulate_halt);
@@ -1305,7 +1387,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
ret = -KVM_EINVAL;
#ifdef CONFIG_X86_64
if (is_long_mode(vcpu)) {
@@ -1329,6 +1411,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
}
switch (nr) {
default:
+ run->hypercall.nr = nr;
run->hypercall.args[0] = a0;
run->hypercall.args[1] = a1;
run->hypercall.args[2] = a2;
@@ -1337,11 +1420,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
run->hypercall.args[5] = a5;
run->hypercall.ret = ret;
run->hypercall.longmode = is_long_mode(vcpu);
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
return 0;
}
vcpu->regs[VCPU_REGS_RAX] = ret;
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
return 1;
}
EXPORT_SYMBOL_GPL(kvm_hypercall);
@@ -1355,26 +1438,26 @@ void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
{
struct descriptor_table dt = { limit, base };
- kvm_arch_ops->set_gdt(vcpu, &dt);
+ kvm_x86_ops->set_gdt(vcpu, &dt);
}
void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
{
struct descriptor_table dt = { limit, base };
- kvm_arch_ops->set_idt(vcpu, &dt);
+ kvm_x86_ops->set_idt(vcpu, &dt);
}
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags)
{
lmsw(vcpu, msw);
- *rflags = kvm_arch_ops->get_rflags(vcpu);
+ *rflags = kvm_x86_ops->get_rflags(vcpu);
}
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
{
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
switch (cr) {
case 0:
return vcpu->cr0;
@@ -1396,7 +1479,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
switch (cr) {
case 0:
set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
- *rflags = kvm_arch_ops->get_rflags(vcpu);
+ *rflags = kvm_x86_ops->get_rflags(vcpu);
break;
case 2:
vcpu->cr2 = val;
@@ -1439,7 +1522,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
- para_state = kmap_atomic(para_state_page, KM_USER0);
+ para_state = kmap(para_state_page);
printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version);
printk(KERN_DEBUG ".... size: %d\n", para_state->size);
@@ -1470,12 +1553,12 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT);
hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT),
KM_USER1) + (hypercall_hpa & ~PAGE_MASK);
- kvm_arch_ops->patch_hypercall(vcpu, hypercall);
+ kvm_x86_ops->patch_hypercall(vcpu, hypercall);
kunmap_atomic(hypercall, KM_USER1);
para_state->ret = 0;
err_kunmap_skip:
- kunmap_atomic(para_state, KM_USER0);
+ kunmap(para_state_page);
return 0;
err_gp:
return 1;
@@ -1511,7 +1594,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
data = 3;
break;
case MSR_IA32_APICBASE:
- data = vcpu->apic_base;
+ data = kvm_get_apic_base(vcpu);
break;
case MSR_IA32_MISC_ENABLE:
data = vcpu->ia32_misc_enable_msr;
@@ -1522,7 +1605,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
break;
#endif
default:
- printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr);
+ pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
return 1;
}
*pdata = data;
@@ -1537,7 +1620,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
*/
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
- return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
+ return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
}
#ifdef CONFIG_X86_64
@@ -1558,7 +1641,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
return;
}
- kvm_arch_ops->set_efer(vcpu, efer);
+ kvm_x86_ops->set_efer(vcpu, efer);
efer &= ~EFER_LMA;
efer |= vcpu->shadow_efer & EFER_LMA;
@@ -1577,11 +1660,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
break;
#endif
case MSR_IA32_MC0_STATUS:
- printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
+ pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
__FUNCTION__, data);
break;
case MSR_IA32_MCG_STATUS:
- printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
+ pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
__FUNCTION__, data);
break;
case MSR_IA32_UCODE_REV:
@@ -1589,7 +1672,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
case 0x200 ... 0x2ff: /* MTRRs */
break;
case MSR_IA32_APICBASE:
- vcpu->apic_base = data;
+ kvm_set_apic_base(vcpu, data);
break;
case MSR_IA32_MISC_ENABLE:
vcpu->ia32_misc_enable_msr = data;
@@ -1601,7 +1684,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
return vcpu_register_para(vcpu, data);
default:
- printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
+ pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr);
return 1;
}
return 0;
@@ -1615,44 +1698,24 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
*/
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
- return kvm_arch_ops->set_msr(vcpu, msr_index, data);
+ return kvm_x86_ops->set_msr(vcpu, msr_index, data);
}
void kvm_resched(struct kvm_vcpu *vcpu)
{
if (!need_resched())
return;
- vcpu_put(vcpu);
cond_resched();
- vcpu_load(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_resched);
-void load_msrs(struct vmx_msr_entry *e, int n)
-{
- int i;
-
- for (i = 0; i < n; ++i)
- wrmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(load_msrs);
-
-void save_msrs(struct vmx_msr_entry *e, int n)
-{
- int i;
-
- for (i = 0; i < n; ++i)
- rdmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(save_msrs);
-
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
{
int i;
u32 function;
struct kvm_cpuid_entry *e, *best;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
function = vcpu->regs[VCPU_REGS_RAX];
vcpu->regs[VCPU_REGS_RAX] = 0;
vcpu->regs[VCPU_REGS_RBX] = 0;
@@ -1678,8 +1741,8 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
vcpu->regs[VCPU_REGS_RCX] = best->ecx;
vcpu->regs[VCPU_REGS_RDX] = best->edx;
}
- kvm_arch_ops->decache_regs(vcpu);
- kvm_arch_ops->skip_emulated_instruction(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
@@ -1690,11 +1753,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
unsigned bytes;
int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
- kvm_arch_ops->vcpu_put(vcpu);
q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
PAGE_KERNEL);
if (!q) {
- kvm_arch_ops->vcpu_load(vcpu);
free_pio_guest_pages(vcpu);
return -ENOMEM;
}
@@ -1706,7 +1767,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
memcpy(p, q, bytes);
q -= vcpu->pio.guest_page_offset;
vunmap(q);
- kvm_arch_ops->vcpu_load(vcpu);
free_pio_guest_pages(vcpu);
return 0;
}
@@ -1717,7 +1777,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
long delta;
int r;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
if (!io->string) {
if (io->in)
@@ -1727,7 +1787,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
if (io->in) {
r = pio_copy_data(vcpu);
if (r) {
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
return r;
}
}
@@ -1750,79 +1810,109 @@ static int complete_pio(struct kvm_vcpu *vcpu)
vcpu->regs[VCPU_REGS_RSI] += delta;
}
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
io->count -= io->cur_count;
io->cur_count = 0;
- if (!io->count)
- kvm_arch_ops->skip_emulated_instruction(vcpu);
return 0;
}
-void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+static void kernel_pio(struct kvm_io_device *pio_dev,
+ struct kvm_vcpu *vcpu,
+ void *pd)
{
/* TODO: String I/O for in kernel device */
+ mutex_lock(&vcpu->kvm->lock);
if (vcpu->pio.in)
kvm_iodevice_read(pio_dev, vcpu->pio.port,
vcpu->pio.size,
- vcpu->pio_data);
+ pd);
else
kvm_iodevice_write(pio_dev, vcpu->pio.port,
vcpu->pio.size,
- vcpu->pio_data);
+ pd);
+ mutex_unlock(&vcpu->kvm->lock);
+}
+
+static void pio_string_write(struct kvm_io_device *pio_dev,
+ struct kvm_vcpu *vcpu)
+{
+ struct kvm_pio_request *io = &vcpu->pio;
+ void *pd = vcpu->pio_data;
+ int i;
+
+ mutex_lock(&vcpu->kvm->lock);
+ for (i = 0; i < io->cur_count; i++) {
+ kvm_iodevice_write(pio_dev, io->port,
+ io->size,
+ pd);
+ pd += io->size;
+ }
+ mutex_unlock(&vcpu->kvm->lock);
}
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
- int size, unsigned long count, int string, int down,
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned port)
+{
+ struct kvm_io_device *pio_dev;
+
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = vcpu->pio.size = size;
+ vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+ vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1;
+ vcpu->run->io.port = vcpu->pio.port = port;
+ vcpu->pio.in = in;
+ vcpu->pio.string = 0;
+ vcpu->pio.down = 0;
+ vcpu->pio.guest_page_offset = 0;
+ vcpu->pio.rep = 0;
+
+ kvm_x86_ops->cache_regs(vcpu);
+ memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
+ kvm_x86_ops->decache_regs(vcpu);
+
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
+ if (pio_dev) {
+ kernel_pio(pio_dev, vcpu, vcpu->pio_data);
+ complete_pio(vcpu);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio);
+
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int down,
gva_t address, int rep, unsigned port)
{
unsigned now, in_page;
- int i;
+ int i, ret = 0;
int nr_pages = 1;
struct page *page;
struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
- vcpu->run->io.size = size;
+ vcpu->run->io.size = vcpu->pio.size = size;
vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
- vcpu->run->io.count = count;
- vcpu->run->io.port = port;
- vcpu->pio.count = count;
- vcpu->pio.cur_count = count;
- vcpu->pio.size = size;
+ vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count;
+ vcpu->run->io.port = vcpu->pio.port = port;
vcpu->pio.in = in;
- vcpu->pio.port = port;
- vcpu->pio.string = string;
+ vcpu->pio.string = 1;
vcpu->pio.down = down;
vcpu->pio.guest_page_offset = offset_in_page(address);
vcpu->pio.rep = rep;
- pio_dev = vcpu_find_pio_dev(vcpu, port);
- if (!string) {
- kvm_arch_ops->cache_regs(vcpu);
- memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
- kvm_arch_ops->decache_regs(vcpu);
- if (pio_dev) {
- kernel_pio(pio_dev, vcpu);
- complete_pio(vcpu);
- return 1;
- }
- return 0;
- }
- /* TODO: String I/O for in kernel device */
- if (pio_dev)
- printk(KERN_ERR "kvm_setup_pio: no string io support\n");
-
if (!count) {
- kvm_arch_ops->skip_emulated_instruction(vcpu);
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
return 1;
}
- now = min(count, PAGE_SIZE / size);
-
if (!down)
in_page = PAGE_SIZE - offset_in_page(address);
else
@@ -1841,20 +1931,23 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
/*
* String I/O in reverse. Yuck. Kill the guest, fix later.
*/
- printk(KERN_ERR "kvm: guest string pio down\n");
+ pr_unimpl(vcpu, "guest string pio down\n");
inject_gp(vcpu);
return 1;
}
vcpu->run->io.count = now;
vcpu->pio.cur_count = now;
+ if (vcpu->pio.cur_count == vcpu->pio.count)
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+
for (i = 0; i < nr_pages; ++i) {
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
page = gva_to_page(vcpu, address + i * PAGE_SIZE);
if (page)
get_page(page);
vcpu->pio.guest_pages[i] = page;
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
if (!page) {
inject_gp(vcpu);
free_pio_guest_pages(vcpu);
@@ -1862,11 +1955,147 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
}
}
- if (!vcpu->pio.in)
- return pio_copy_data(vcpu);
- return 0;
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
+ if (!vcpu->pio.in) {
+ /* string PIO write */
+ ret = pio_copy_data(vcpu);
+ if (ret >= 0 && pio_dev) {
+ pio_string_write(pio_dev, vcpu);
+ complete_pio(vcpu);
+ if (vcpu->pio.count == 0)
+ ret = 1;
+ }
+ } else if (pio_dev)
+ pr_unimpl(vcpu, "no string pio read support yet, "
+ "port %x size %d count %ld\n",
+ port, size, count);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
+
+/*
+ * Check if userspace requested an interrupt window, and that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return (!vcpu->irq_summary &&
+ kvm_run->request_interrupt_window &&
+ vcpu->interrupt_window_open &&
+ (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
+}
+
+static void post_kvm_run_save(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+ kvm_run->cr8 = get_cr8(vcpu);
+ kvm_run->apic_base = kvm_get_apic_base(vcpu);
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_run->ready_for_interrupt_injection = 1;
+ else
+ kvm_run->ready_for_interrupt_injection =
+ (vcpu->interrupt_window_open &&
+ vcpu->irq_summary == 0);
+}
+
+static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ int r;
+
+ if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
+ printk("vcpu %d received sipi with vector # %x\n",
+ vcpu->vcpu_id, vcpu->sipi_vector);
+ kvm_lapic_reset(vcpu);
+ kvm_x86_ops->vcpu_reset(vcpu);
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ }
+
+preempted:
+ if (vcpu->guest_debug.enabled)
+ kvm_x86_ops->guest_debug_pre(vcpu);
+
+again:
+ r = kvm_mmu_reload(vcpu);
+ if (unlikely(r))
+ goto out;
+
+ preempt_disable();
+
+ kvm_x86_ops->prepare_guest_switch(vcpu);
+ kvm_load_guest_fpu(vcpu);
+
+ local_irq_disable();
+
+ if (signal_pending(current)) {
+ local_irq_enable();
+ preempt_enable();
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.signal_exits;
+ goto out;
+ }
+
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_x86_ops->inject_pending_irq(vcpu);
+ else if (!vcpu->mmio_read_completed)
+ kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
+
+ vcpu->guest_mode = 1;
+ kvm_guest_enter();
+
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+ kvm_x86_ops->tlb_flush(vcpu);
+
+ kvm_x86_ops->run(vcpu, kvm_run);
+
+ kvm_guest_exit();
+ vcpu->guest_mode = 0;
+ local_irq_enable();
+
+ ++vcpu->stat.exits;
+
+ preempt_enable();
+
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING)) {
+ kvm_x86_ops->cache_regs(vcpu);
+ profile_hit(KVM_PROFILING, (void *)vcpu->rip);
+ }
+
+ r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
+
+ if (r > 0) {
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.request_irq_exits;
+ goto out;
+ }
+ if (!need_resched()) {
+ ++vcpu->stat.light_exits;
+ goto again;
+ }
+ }
+
+out:
+ if (r > 0) {
+ kvm_resched(vcpu);
+ goto preempted;
+ }
+
+ post_kvm_run_save(vcpu, kvm_run);
+
+ return r;
}
-EXPORT_SYMBOL_GPL(kvm_setup_pio);
+
static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
@@ -1875,11 +2104,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load(vcpu);
+ if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) {
+ kvm_vcpu_block(vcpu);
+ vcpu_put(vcpu);
+ return -EAGAIN;
+ }
+
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
/* re-sync apic's tpr */
- vcpu->cr8 = kvm_run->cr8;
+ if (!irqchip_in_kernel(vcpu->kvm))
+ set_cr8(vcpu, kvm_run->cr8);
if (vcpu->pio.cur_count) {
r = complete_pio(vcpu);
@@ -1897,19 +2133,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
/*
* Read-modify-write. Back to userspace.
*/
- kvm_run->exit_reason = KVM_EXIT_MMIO;
r = 0;
goto out;
}
}
if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
}
- r = kvm_arch_ops->run(vcpu, kvm_run);
+ r = __vcpu_run(vcpu, kvm_run);
out:
if (vcpu->sigset_active)
@@ -1924,7 +2159,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
{
vcpu_load(vcpu);
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
regs->rax = vcpu->regs[VCPU_REGS_RAX];
regs->rbx = vcpu->regs[VCPU_REGS_RBX];
@@ -1946,7 +2181,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
#endif
regs->rip = vcpu->rip;
- regs->rflags = kvm_arch_ops->get_rflags(vcpu);
+ regs->rflags = kvm_x86_ops->get_rflags(vcpu);
/*
* Don't leak debug flags in case they were set for guest debugging
@@ -1984,9 +2219,9 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
#endif
vcpu->rip = regs->rip;
- kvm_arch_ops->set_rflags(vcpu, regs->rflags);
+ kvm_x86_ops->set_rflags(vcpu, regs->rflags);
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
vcpu_put(vcpu);
@@ -1996,13 +2231,14 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
static void get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_arch_ops->get_segment(vcpu, var, seg);
+ return kvm_x86_ops->get_segment(vcpu, var, seg);
}
static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
struct descriptor_table dt;
+ int pending_vec;
vcpu_load(vcpu);
@@ -2016,24 +2252,31 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
- kvm_arch_ops->get_idt(vcpu, &dt);
+ kvm_x86_ops->get_idt(vcpu, &dt);
sregs->idt.limit = dt.limit;
sregs->idt.base = dt.base;
- kvm_arch_ops->get_gdt(vcpu, &dt);
+ kvm_x86_ops->get_gdt(vcpu, &dt);
sregs->gdt.limit = dt.limit;
sregs->gdt.base = dt.base;
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
sregs->cr0 = vcpu->cr0;
sregs->cr2 = vcpu->cr2;
sregs->cr3 = vcpu->cr3;
sregs->cr4 = vcpu->cr4;
- sregs->cr8 = vcpu->cr8;
+ sregs->cr8 = get_cr8(vcpu);
sregs->efer = vcpu->shadow_efer;
- sregs->apic_base = vcpu->apic_base;
-
- memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
- sizeof sregs->interrupt_bitmap);
+ sregs->apic_base = kvm_get_apic_base(vcpu);
+
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ memset(sregs->interrupt_bitmap, 0,
+ sizeof sregs->interrupt_bitmap);
+ pending_vec = kvm_x86_ops->get_irq(vcpu);
+ if (pending_vec >= 0)
+ set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap);
+ } else
+ memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
+ sizeof sregs->interrupt_bitmap);
vcpu_put(vcpu);
@@ -2043,56 +2286,69 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
static void set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_arch_ops->set_segment(vcpu, var, seg);
+ return kvm_x86_ops->set_segment(vcpu, var, seg);
}
static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
int mmu_reset_needed = 0;
- int i;
+ int i, pending_vec, max_bits;
struct descriptor_table dt;
vcpu_load(vcpu);
dt.limit = sregs->idt.limit;
dt.base = sregs->idt.base;
- kvm_arch_ops->set_idt(vcpu, &dt);
+ kvm_x86_ops->set_idt(vcpu, &dt);
dt.limit = sregs->gdt.limit;
dt.base = sregs->gdt.base;
- kvm_arch_ops->set_gdt(vcpu, &dt);
+ kvm_x86_ops->set_gdt(vcpu, &dt);
vcpu->cr2 = sregs->cr2;
mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
vcpu->cr3 = sregs->cr3;
- vcpu->cr8 = sregs->cr8;
+ set_cr8(vcpu, sregs->cr8);
mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
#ifdef CONFIG_X86_64
- kvm_arch_ops->set_efer(vcpu, sregs->efer);
+ kvm_x86_ops->set_efer(vcpu, sregs->efer);
#endif
- vcpu->apic_base = sregs->apic_base;
+ kvm_set_apic_base(vcpu, sregs->apic_base);
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
- kvm_arch_ops->set_cr0(vcpu, sregs->cr0);
+ vcpu->cr0 = sregs->cr0;
+ kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
- kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
+ kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
if (!is_long_mode(vcpu) && is_pae(vcpu))
load_pdptrs(vcpu, vcpu->cr3);
if (mmu_reset_needed)
kvm_mmu_reset_context(vcpu);
- memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
- sizeof vcpu->irq_pending);
- vcpu->irq_summary = 0;
- for (i = 0; i < NR_IRQ_WORDS; ++i)
- if (vcpu->irq_pending[i])
- __set_bit(i, &vcpu->irq_summary);
+ if (!irqchip_in_kernel(vcpu->kvm)) {
+ memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
+ sizeof vcpu->irq_pending);
+ vcpu->irq_summary = 0;
+ for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
+ if (vcpu->irq_pending[i])
+ __set_bit(i, &vcpu->irq_summary);
+ } else {
+ max_bits = (sizeof sregs->interrupt_bitmap) << 3;
+ pending_vec = find_first_bit(
+ (const unsigned long *)sregs->interrupt_bitmap,
+ max_bits);
+ /* Only pending external irq is handled here */
+ if (pending_vec < max_bits) {
+ kvm_x86_ops->set_irq(vcpu, pending_vec);
+ printk("Set back pending irq %d\n", pending_vec);
+ }
+ }
set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -2109,6 +2365,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return 0;
}
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+ struct kvm_segment cs;
+
+ get_segment(vcpu, &cs, VCPU_SREG_CS);
+ *db = cs.db;
+ *l = cs.l;
+}
+EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
+
/*
* List of msr numbers which we expose to userspace through KVM_GET_MSRS
* and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
@@ -2236,13 +2502,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
gpa_t gpa;
vcpu_load(vcpu);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
tr->physical_address = gpa;
tr->valid = gpa != UNMAPPED_GVA;
tr->writeable = 1;
tr->usermode = 0;
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
vcpu_put(vcpu);
return 0;
@@ -2253,6 +2519,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
{
if (irq->irq < 0 || irq->irq >= 256)
return -EINVAL;
+ if (irqchip_in_kernel(vcpu->kvm))
+ return -ENXIO;
vcpu_load(vcpu);
set_bit(irq->irq, vcpu->irq_pending);
@@ -2270,7 +2538,7 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
vcpu_load(vcpu);
- r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
+ r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
vcpu_put(vcpu);
@@ -2285,7 +2553,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
unsigned long pgoff;
struct page *page;
- *type = VM_FAULT_MINOR;
pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (pgoff == 0)
page = virt_to_page(vcpu->run);
@@ -2294,6 +2561,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
else
return NOPAGE_SIGBUS;
get_page(page);
+ if (type != NULL)
+ *type = VM_FAULT_MINOR;
+
return page;
}
@@ -2346,74 +2616,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
{
int r;
struct kvm_vcpu *vcpu;
- struct page *page;
- r = -EINVAL;
if (!valid_vcpu(n))
- goto out;
-
- vcpu = &kvm->vcpus[n];
-
- mutex_lock(&vcpu->mutex);
-
- if (vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return -EEXIST;
- }
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_unlock;
- vcpu->run = page_address(page);
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_free_run;
- vcpu->pio_data = page_address(page);
+ return -EINVAL;
- vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
- FX_IMAGE_ALIGN);
- vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
- vcpu->cr0 = 0x10;
+ vcpu = kvm_x86_ops->vcpu_create(kvm, n);
+ if (IS_ERR(vcpu))
+ return PTR_ERR(vcpu);
- r = kvm_arch_ops->vcpu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
+ preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
- r = kvm_mmu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
+ /* We do fxsave: this must be aligned. */
+ BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
- kvm_arch_ops->vcpu_load(vcpu);
+ vcpu_load(vcpu);
r = kvm_mmu_setup(vcpu);
- if (r >= 0)
- r = kvm_arch_ops->vcpu_setup(vcpu);
vcpu_put(vcpu);
-
if (r < 0)
- goto out_free_vcpus;
+ goto free_vcpu;
+ mutex_lock(&kvm->lock);
+ if (kvm->vcpus[n]) {
+ r = -EEXIST;
+ mutex_unlock(&kvm->lock);
+ goto mmu_unload;
+ }
+ kvm->vcpus[n] = vcpu;
+ mutex_unlock(&kvm->lock);
+
+ /* Now it's all set up, let userspace reach it */
r = create_vcpu_fd(vcpu);
if (r < 0)
- goto out_free_vcpus;
+ goto unlink;
+ return r;
- spin_lock(&kvm_lock);
- if (n >= kvm->nvcpus)
- kvm->nvcpus = n + 1;
- spin_unlock(&kvm_lock);
+unlink:
+ mutex_lock(&kvm->lock);
+ kvm->vcpus[n] = NULL;
+ mutex_unlock(&kvm->lock);
- return r;
+mmu_unload:
+ vcpu_load(vcpu);
+ kvm_mmu_unload(vcpu);
+ vcpu_put(vcpu);
-out_free_vcpus:
- kvm_free_vcpu(vcpu);
-out_free_run:
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
-out_unlock:
- mutex_unlock(&vcpu->mutex);
-out:
+free_vcpu:
+ kvm_x86_ops->vcpu_free(vcpu);
return r;
}
@@ -2493,7 +2741,7 @@ struct fxsave {
static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
vcpu_load(vcpu);
@@ -2513,7 +2761,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
vcpu_load(vcpu);
@@ -2531,6 +2779,27 @@ static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
return 0;
}
+static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_state *s)
+{
+ vcpu_load(vcpu);
+ memcpy(s->regs, vcpu->apic->regs, sizeof *s);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_state *s)
+{
+ vcpu_load(vcpu);
+ memcpy(vcpu->apic->regs, s->regs, sizeof *s);
+ kvm_apic_post_state_restore(vcpu);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
static long kvm_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -2700,6 +2969,31 @@ static long kvm_vcpu_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_GET_LAPIC: {
+ struct kvm_lapic_state lapic;
+
+ memset(&lapic, 0, sizeof lapic);
+ r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &lapic, sizeof lapic))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_LAPIC: {
+ struct kvm_lapic_state lapic;
+
+ r = -EFAULT;
+ if (copy_from_user(&lapic, argp, sizeof lapic))
+ goto out;
+ r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);;
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -2753,6 +3047,75 @@ static long kvm_vm_ioctl(struct file *filp,
goto out;
break;
}
+ case KVM_CREATE_IRQCHIP:
+ r = -ENOMEM;
+ kvm->vpic = kvm_create_pic(kvm);
+ if (kvm->vpic) {
+ r = kvm_ioapic_init(kvm);
+ if (r) {
+ kfree(kvm->vpic);
+ kvm->vpic = NULL;
+ goto out;
+ }
+ }
+ else
+ goto out;
+ break;
+ case KVM_IRQ_LINE: {
+ struct kvm_irq_level irq_event;
+
+ r = -EFAULT;
+ if (copy_from_user(&irq_event, argp, sizeof irq_event))
+ goto out;
+ if (irqchip_in_kernel(kvm)) {
+ mutex_lock(&kvm->lock);
+ if (irq_event.irq < 16)
+ kvm_pic_set_irq(pic_irqchip(kvm),
+ irq_event.irq,
+ irq_event.level);
+ kvm_ioapic_set_irq(kvm->vioapic,
+ irq_event.irq,
+ irq_event.level);
+ mutex_unlock(&kvm->lock);
+ r = 0;
+ }
+ break;
+ }
+ case KVM_GET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &chip, sizeof chip))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -2768,12 +3131,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
unsigned long pgoff;
struct page *page;
- *type = VM_FAULT_MINOR;
pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
page = gfn_to_page(kvm, pgoff);
if (!page)
return NOPAGE_SIGBUS;
get_page(page);
+ if (type != NULL)
+ *type = VM_FAULT_MINOR;
+
return page;
}
@@ -2861,12 +3226,20 @@ static long kvm_dev_ioctl(struct file *filp,
r = 0;
break;
}
- case KVM_CHECK_EXTENSION:
- /*
- * No extensions defined at present.
- */
- r = 0;
+ case KVM_CHECK_EXTENSION: {
+ int ext = (long)argp;
+
+ switch (ext) {
+ case KVM_CAP_IRQCHIP:
+ case KVM_CAP_HLT:
+ r = 1;
+ break;
+ default:
+ r = 0;
+ break;
+ }
break;
+ }
case KVM_GET_VCPU_MMAP_SIZE:
r = -EINVAL;
if (arg)
@@ -2881,8 +3254,6 @@ out:
}
static struct file_operations kvm_chardev_ops = {
- .open = kvm_dev_open,
- .release = kvm_dev_release,
.unlocked_ioctl = kvm_dev_ioctl,
.compat_ioctl = kvm_dev_ioctl,
};
@@ -2893,25 +3264,6 @@ static struct miscdevice kvm_dev = {
&kvm_chardev_ops,
};
-static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
- void *v)
-{
- if (val == SYS_RESTART) {
- /*
- * Some (well, at least mine) BIOSes hang on reboot if
- * in vmx root mode.
- */
- printk(KERN_INFO "kvm: exiting hardware virtualization\n");
- on_each_cpu(hardware_disable, NULL, 0, 1);
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block kvm_reboot_notifier = {
- .notifier_call = kvm_reboot,
- .priority = 0,
-};
-
/*
* Make sure that a cpu that is being hot-unplugged does not have any vcpus
* cached on it.
@@ -2925,7 +3277,9 @@ static void decache_vcpus_on_cpu(int cpu)
spin_lock(&kvm_lock);
list_for_each_entry(vm, &vm_list, vm_list)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &vm->vcpus[i];
+ vcpu = vm->vcpus[i];
+ if (!vcpu)
+ continue;
/*
* If the vcpu is locked, then it is running on some
* other cpu and therefore it is not cached on the
@@ -2936,7 +3290,7 @@ static void decache_vcpus_on_cpu(int cpu)
*/
if (mutex_trylock(&vcpu->mutex)) {
if (vcpu->cpu == cpu) {
- kvm_arch_ops->vcpu_decache(vcpu);
+ kvm_x86_ops->vcpu_decache(vcpu);
vcpu->cpu = -1;
}
mutex_unlock(&vcpu->mutex);
@@ -2952,7 +3306,7 @@ static void hardware_enable(void *junk)
if (cpu_isset(cpu, cpus_hardware_enabled))
return;
cpu_set(cpu, cpus_hardware_enabled);
- kvm_arch_ops->hardware_enable(NULL);
+ kvm_x86_ops->hardware_enable(NULL);
}
static void hardware_disable(void *junk)
@@ -2963,7 +3317,7 @@ static void hardware_disable(void *junk)
return;
cpu_clear(cpu, cpus_hardware_enabled);
decache_vcpus_on_cpu(cpu);
- kvm_arch_ops->hardware_disable(NULL);
+ kvm_x86_ops->hardware_disable(NULL);
}
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
@@ -2994,6 +3348,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
return NOTIFY_OK;
}
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ if (val == SYS_RESTART) {
+ /*
+ * Some (well, at least mine) BIOSes hang on reboot if
+ * in vmx root mode.
+ */
+ printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+ on_each_cpu(hardware_disable, NULL, 0, 1);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+ .notifier_call = kvm_reboot,
+ .priority = 0,
+};
+
void kvm_io_bus_init(struct kvm_io_bus *bus)
{
memset(bus, 0, sizeof(*bus));
@@ -3047,18 +3420,15 @@ static u64 stat_get(void *_offset)
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &kvm->vcpus[i];
- total += *(u32 *)((void *)vcpu + offset);
+ vcpu = kvm->vcpus[i];
+ if (vcpu)
+ total += *(u32 *)((void *)vcpu + offset);
}
spin_unlock(&kvm_lock);
return total;
}
-static void stat_set(void *offset, u64 val)
-{
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n");
static __init void kvm_init_debug(void)
{
@@ -3105,11 +3475,34 @@ static struct sys_device kvm_sysdev = {
hpa_t bad_page_address;
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+static inline
+struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
+{
+ return container_of(pn, struct kvm_vcpu, preempt_notifier);
+}
+
+static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
+{
+ struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+ kvm_x86_ops->vcpu_load(vcpu, cpu);
+}
+
+static void kvm_sched_out(struct preempt_notifier *pn,
+ struct task_struct *next)
+{
+ struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+ kvm_x86_ops->vcpu_put(vcpu);
+}
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+ struct module *module)
{
int r;
+ int cpu;
- if (kvm_arch_ops) {
+ if (kvm_x86_ops) {
printk(KERN_ERR "kvm: already loaded the other module\n");
return -EEXIST;
}
@@ -3123,12 +3516,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
return -EOPNOTSUPP;
}
- kvm_arch_ops = ops;
+ kvm_x86_ops = ops;
- r = kvm_arch_ops->hardware_setup();
+ r = kvm_x86_ops->hardware_setup();
if (r < 0)
goto out;
+ for_each_online_cpu(cpu) {
+ smp_call_function_single(cpu,
+ kvm_x86_ops->check_processor_compatibility,
+ &r, 0, 1);
+ if (r < 0)
+ goto out_free_0;
+ }
+
on_each_cpu(hardware_enable, NULL, 0, 1);
r = register_cpu_notifier(&kvm_cpu_notifier);
if (r)
@@ -3143,6 +3544,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
if (r)
goto out_free_3;
+ /* A kmem cache lets us meet the alignment requirements of fx_save. */
+ kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
+ __alignof__(struct kvm_vcpu), 0, 0);
+ if (!kvm_vcpu_cache) {
+ r = -ENOMEM;
+ goto out_free_4;
+ }
+
kvm_chardev_ops.owner = module;
r = misc_register(&kvm_dev);
@@ -3151,9 +3560,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
goto out_free;
}
+ kvm_preempt_ops.sched_in = kvm_sched_in;
+ kvm_preempt_ops.sched_out = kvm_sched_out;
+
return r;
out_free:
+ kmem_cache_destroy(kvm_vcpu_cache);
+out_free_4:
sysdev_unregister(&kvm_sysdev);
out_free_3:
sysdev_class_unregister(&kvm_sysdev_class);
@@ -3162,22 +3576,24 @@ out_free_2:
unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_1:
on_each_cpu(hardware_disable, NULL, 0, 1);
- kvm_arch_ops->hardware_unsetup();
+out_free_0:
+ kvm_x86_ops->hardware_unsetup();
out:
- kvm_arch_ops = NULL;
+ kvm_x86_ops = NULL;
return r;
}
-void kvm_exit_arch(void)
+void kvm_exit_x86(void)
{
misc_deregister(&kvm_dev);
+ kmem_cache_destroy(kvm_vcpu_cache);
sysdev_unregister(&kvm_sysdev);
sysdev_class_unregister(&kvm_sysdev_class);
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
on_each_cpu(hardware_disable, NULL, 0, 1);
- kvm_arch_ops->hardware_unsetup();
- kvm_arch_ops = NULL;
+ kvm_x86_ops->hardware_unsetup();
+ kvm_x86_ops = NULL;
}
static __init int kvm_init(void)
@@ -3220,5 +3636,5 @@ static __exit void kvm_exit(void)
module_init(kvm_init)
module_exit(kvm_exit)
-EXPORT_SYMBOL_GPL(kvm_init_arch);
-EXPORT_SYMBOL_GPL(kvm_exit_arch);
+EXPORT_SYMBOL_GPL(kvm_init_x86);
+EXPORT_SYMBOL_GPL(kvm_exit_x86);
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
index a869983d683..a0e415daef5 100644
--- a/drivers/kvm/kvm_svm.h
+++ b/drivers/kvm/kvm_svm.h
@@ -20,7 +20,10 @@ static const u32 host_save_user_msrs[] = {
#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
#define NUM_DB_REGS 4
+struct kvm_vcpu;
+
struct vcpu_svm {
+ struct kvm_vcpu vcpu;
struct vmcb *vmcb;
unsigned long vmcb_pa;
struct svm_cpu_data *svm_data;
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
new file mode 100644
index 00000000000..a190587cf6a
--- /dev/null
+++ b/drivers/kvm/lapic.c
@@ -0,0 +1,1064 @@
+
+/*
+ * Local APIC virtualization
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright (C) 2007 Novell
+ * Copyright (C) 2007 Intel
+ *
+ * Authors:
+ * Dor Laor <dor.laor@qumranet.com>
+ * Gregory Haskins <ghaskins@novell.com>
+ * Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ *
+ * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/atomic.h>
+#include <asm/div64.h>
+#include "irq.h"
+
+#define PRId64 "d"
+#define PRIx64 "llx"
+#define PRIu64 "u"
+#define PRIo64 "o"
+
+#define APIC_BUS_CYCLE_NS 1
+
+/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define apic_debug(fmt, arg...)
+
+#define APIC_LVT_NUM 6
+/* 14 is the version for Xeon and Pentium 8.4.8*/
+#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16))
+#define LAPIC_MMIO_LENGTH (1 << 12)
+/* followed define is not in apicdef.h */
+#define APIC_SHORT_MASK 0xc0000
+#define APIC_DEST_NOSHORT 0x0
+#define APIC_DEST_MASK 0x800
+#define MAX_APIC_VECTOR 256
+
+#define VEC_POS(v) ((v) & (32 - 1))
+#define REG_POS(v) (((v) >> 5) << 4)
+static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
+{
+ return *((u32 *) (apic->regs + reg_off));
+}
+
+static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
+{
+ *((u32 *) (apic->regs + reg_off)) = val;
+}
+
+static inline int apic_test_and_set_vector(int vec, void *bitmap)
+{
+ return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_test_and_clear_vector(int vec, void *bitmap)
+{
+ return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_set_vector(int vec, void *bitmap)
+{
+ set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_clear_vector(int vec, void *bitmap)
+{
+ clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_hw_enabled(struct kvm_lapic *apic)
+{
+ return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE;
+}
+
+static inline int apic_sw_enabled(struct kvm_lapic *apic)
+{
+ return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+}
+
+static inline int apic_enabled(struct kvm_lapic *apic)
+{
+ return apic_sw_enabled(apic) && apic_hw_enabled(apic);
+}
+
+#define LVT_MASK \
+ (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
+
+#define LINT_MASK \
+ (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
+ APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
+
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+ return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
+static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
+{
+ return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+}
+
+static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
+{
+ return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+}
+
+static inline int apic_lvtt_period(struct kvm_lapic *apic)
+{
+ return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
+}
+
+static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
+ LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
+ LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
+ LVT_MASK | APIC_MODE_MASK, /* LVTPC */
+ LINT_MASK, LINT_MASK, /* LVT0-1 */
+ LVT_MASK /* LVTERR */
+};
+
+static int find_highest_vector(void *bitmap)
+{
+ u32 *word = bitmap;
+ int word_offset = MAX_APIC_VECTOR >> 5;
+
+ while ((word_offset != 0) && (word[(--word_offset) << 2] == 0))
+ continue;
+
+ if (likely(!word_offset && !word[0]))
+ return -1;
+ else
+ return fls(word[word_offset << 2]) - 1 + (word_offset << 5);
+}
+
+static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
+{
+ return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
+{
+ apic_clear_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline int apic_find_highest_irr(struct kvm_lapic *apic)
+{
+ int result;
+
+ result = find_highest_vector(apic->regs + APIC_IRR);
+ ASSERT(result == -1 || result >= 16);
+
+ return result;
+}
+
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ int highest_irr;
+
+ if (!apic)
+ return 0;
+ highest_irr = apic_find_highest_irr(apic);
+
+ return highest_irr;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
+
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
+{
+ if (!apic_test_and_set_irr(vec, apic)) {
+ /* a new pending irq is set in IRR */
+ if (trig)
+ apic_set_vector(vec, apic->regs + APIC_TMR);
+ else
+ apic_clear_vector(vec, apic->regs + APIC_TMR);
+ kvm_vcpu_kick(apic->vcpu);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int apic_find_highest_isr(struct kvm_lapic *apic)
+{
+ int result;
+
+ result = find_highest_vector(apic->regs + APIC_ISR);
+ ASSERT(result == -1 || result >= 16);
+
+ return result;
+}
+
+static void apic_update_ppr(struct kvm_lapic *apic)
+{
+ u32 tpr, isrv, ppr;
+ int isr;
+
+ tpr = apic_get_reg(apic, APIC_TASKPRI);
+ isr = apic_find_highest_isr(apic);
+ isrv = (isr != -1) ? isr : 0;
+
+ if ((tpr & 0xf0) >= (isrv & 0xf0))
+ ppr = tpr & 0xff;
+ else
+ ppr = isrv & 0xf0;
+
+ apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
+ apic, ppr, isr, isrv);
+
+ apic_set_reg(apic, APIC_PROCPRI, ppr);
+}
+
+static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
+{
+ apic_set_reg(apic, APIC_TASKPRI, tpr);
+ apic_update_ppr(apic);
+}
+
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
+{
+ return kvm_apic_id(apic) == dest;
+}
+
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
+{
+ int result = 0;
+ u8 logical_id;
+
+ logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
+
+ switch (apic_get_reg(apic, APIC_DFR)) {
+ case APIC_DFR_FLAT:
+ if (logical_id & mda)
+ result = 1;
+ break;
+ case APIC_DFR_CLUSTER:
+ if (((logical_id >> 4) == (mda >> 0x4))
+ && (logical_id & mda & 0xf))
+ result = 1;
+ break;
+ default:
+ printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n",
+ apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+ break;
+ }
+
+ return result;
+}
+
+static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+ int short_hand, int dest, int dest_mode)
+{
+ int result = 0;
+ struct kvm_lapic *target = vcpu->apic;
+
+ apic_debug("target %p, source %p, dest 0x%x, "
+ "dest_mode 0x%x, short_hand 0x%x",
+ target, source, dest, dest_mode, short_hand);
+
+ ASSERT(!target);
+ switch (short_hand) {
+ case APIC_DEST_NOSHORT:
+ if (dest_mode == 0) {
+ /* Physical mode. */
+ if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
+ result = 1;
+ } else
+ /* Logical mode. */
+ result = kvm_apic_match_logical_addr(target, dest);
+ break;
+ case APIC_DEST_SELF:
+ if (target == source)
+ result = 1;
+ break;
+ case APIC_DEST_ALLINC:
+ result = 1;
+ break;
+ case APIC_DEST_ALLBUT:
+ if (target != source)
+ result = 1;
+ break;
+ default:
+ printk(KERN_WARNING "Bad dest shorthand value %x\n",
+ short_hand);
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Add a pending IRQ into lapic.
+ * Return 1 if successfully added and 0 if discarded.
+ */
+static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
+ int vector, int level, int trig_mode)
+{
+ int orig_irr, result = 0;
+ struct kvm_vcpu *vcpu = apic->vcpu;
+
+ switch (delivery_mode) {
+ case APIC_DM_FIXED:
+ case APIC_DM_LOWEST:
+ /* FIXME add logic for vcpu on reset */
+ if (unlikely(!apic_enabled(apic)))
+ break;
+
+ orig_irr = apic_test_and_set_irr(vector, apic);
+ if (orig_irr && trig_mode) {
+ apic_debug("level trig mode repeatedly for vector %d",
+ vector);
+ break;
+ }
+
+ if (trig_mode) {
+ apic_debug("level trig mode for vector %d", vector);
+ apic_set_vector(vector, apic->regs + APIC_TMR);
+ } else
+ apic_clear_vector(vector, apic->regs + APIC_TMR);
+
+ if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+ kvm_vcpu_kick(vcpu);
+ else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) {
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+ }
+
+ result = (orig_irr == 0);
+ break;
+
+ case APIC_DM_REMRD:
+ printk(KERN_DEBUG "Ignoring delivery mode 3\n");
+ break;
+
+ case APIC_DM_SMI:
+ printk(KERN_DEBUG "Ignoring guest SMI\n");
+ break;
+ case APIC_DM_NMI:
+ printk(KERN_DEBUG "Ignoring guest NMI\n");
+ break;
+
+ case APIC_DM_INIT:
+ if (level) {
+ if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+ printk(KERN_DEBUG
+ "INIT on a runnable vcpu %d\n",
+ vcpu->vcpu_id);
+ vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED;
+ kvm_vcpu_kick(vcpu);
+ } else {
+ printk(KERN_DEBUG
+ "Ignoring de-assert INIT to vcpu %d\n",
+ vcpu->vcpu_id);
+ }
+
+ break;
+
+ case APIC_DM_STARTUP:
+ printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
+ vcpu->vcpu_id, vector);
+ if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
+ vcpu->sipi_vector = vector;
+ vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
+ delivery_mode);
+ break;
+ }
+ return result;
+}
+
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+ unsigned long bitmap)
+{
+ int vcpu_id;
+ int last;
+ int next;
+ struct kvm_lapic *apic;
+
+ last = kvm->round_robin_prev_vcpu;
+ next = last;
+
+ do {
+ if (++next == KVM_MAX_VCPUS)
+ next = 0;
+ if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
+ continue;
+ apic = kvm->vcpus[next]->apic;
+ if (apic && apic_enabled(apic))
+ break;
+ apic = NULL;
+ } while (next != last);
+ kvm->round_robin_prev_vcpu = next;
+
+ if (!apic) {
+ vcpu_id = ffs(bitmap) - 1;
+ if (vcpu_id < 0) {
+ vcpu_id = 0;
+ printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
+ }
+ apic = kvm->vcpus[vcpu_id]->apic;
+ }
+
+ return apic;
+}
+
+static void apic_set_eoi(struct kvm_lapic *apic)
+{
+ int vector = apic_find_highest_isr(apic);
+
+ /*
+ * Not every write EOI will has corresponding ISR,
+ * one example is when Kernel check timer on setup_IO_APIC
+ */
+ if (vector == -1)
+ return;
+
+ apic_clear_vector(vector, apic->regs + APIC_ISR);
+ apic_update_ppr(apic);
+
+ if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
+ kvm_ioapic_update_eoi(apic->vcpu->kvm, vector);
+}
+
+static void apic_send_ipi(struct kvm_lapic *apic)
+{
+ u32 icr_low = apic_get_reg(apic, APIC_ICR);
+ u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+
+ unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
+ unsigned int short_hand = icr_low & APIC_SHORT_MASK;
+ unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
+ unsigned int level = icr_low & APIC_INT_ASSERT;
+ unsigned int dest_mode = icr_low & APIC_DEST_MASK;
+ unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
+ unsigned int vector = icr_low & APIC_VECTOR_MASK;
+
+ struct kvm_lapic *target;
+ struct kvm_vcpu *vcpu;
+ unsigned long lpr_map = 0;
+ int i;
+
+ apic_debug("icr_high 0x%x, icr_low 0x%x, "
+ "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
+ "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
+ icr_high, icr_low, short_hand, dest,
+ trig_mode, level, dest_mode, delivery_mode, vector);
+
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
+ vcpu = apic->vcpu->kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+
+ if (vcpu->apic &&
+ apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
+ if (delivery_mode == APIC_DM_LOWEST)
+ set_bit(vcpu->vcpu_id, &lpr_map);
+ else
+ __apic_accept_irq(vcpu->apic, delivery_mode,
+ vector, level, trig_mode);
+ }
+ }
+
+ if (delivery_mode == APIC_DM_LOWEST) {
+ target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map);
+ if (target != NULL)
+ __apic_accept_irq(target, delivery_mode,
+ vector, level, trig_mode);
+ }
+}
+
+static u32 apic_get_tmcct(struct kvm_lapic *apic)
+{
+ u32 counter_passed;
+ ktime_t passed, now = apic->timer.dev.base->get_time();
+ u32 tmcct = apic_get_reg(apic, APIC_TMICT);
+
+ ASSERT(apic != NULL);
+
+ if (unlikely(ktime_to_ns(now) <=
+ ktime_to_ns(apic->timer.last_update))) {
+ /* Wrap around */
+ passed = ktime_add(( {
+ (ktime_t) {
+ .tv64 = KTIME_MAX -
+ (apic->timer.last_update).tv64}; }
+ ), now);
+ apic_debug("time elapsed\n");
+ } else
+ passed = ktime_sub(now, apic->timer.last_update);
+
+ counter_passed = div64_64(ktime_to_ns(passed),
+ (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+ tmcct -= counter_passed;
+
+ if (tmcct <= 0) {
+ if (unlikely(!apic_lvtt_period(apic)))
+ tmcct = 0;
+ else
+ do {
+ tmcct += apic_get_reg(apic, APIC_TMICT);
+ } while (tmcct <= 0);
+ }
+
+ return tmcct;
+}
+
+static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
+{
+ u32 val = 0;
+
+ if (offset >= LAPIC_MMIO_LENGTH)
+ return 0;
+
+ switch (offset) {
+ case APIC_ARBPRI:
+ printk(KERN_WARNING "Access APIC ARBPRI register "
+ "which is for P6\n");
+ break;
+
+ case APIC_TMCCT: /* Timer CCR */
+ val = apic_get_tmcct(apic);
+ break;
+
+ default:
+ apic_update_ppr(apic);
+ val = apic_get_reg(apic, offset);
+ break;
+ }
+
+ return val;
+}
+
+static void apic_mmio_read(struct kvm_io_device *this,
+ gpa_t address, int len, void *data)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ unsigned int offset = address - apic->base_address;
+ unsigned char alignment = offset & 0xf;
+ u32 result;
+
+ if ((alignment + len) > 4) {
+ printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
+ (unsigned long)address, len);
+ return;
+ }
+ result = __apic_read(apic, offset & ~0xf);
+
+ switch (len) {
+ case 1:
+ case 2:
+ case 4:
+ memcpy(data, (char *)&result + alignment, len);
+ break;
+ default:
+ printk(KERN_ERR "Local APIC read with len = %x, "
+ "should be 1,2, or 4 instead\n", len);
+ break;
+ }
+}
+
+static void update_divide_count(struct kvm_lapic *apic)
+{
+ u32 tmp1, tmp2, tdcr;
+
+ tdcr = apic_get_reg(apic, APIC_TDCR);
+ tmp1 = tdcr & 0xf;
+ tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
+ apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
+
+ apic_debug("timer divide count is 0x%x\n",
+ apic->timer.divide_count);
+}
+
+static void start_apic_timer(struct kvm_lapic *apic)
+{
+ ktime_t now = apic->timer.dev.base->get_time();
+
+ apic->timer.last_update = now;
+
+ apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
+ APIC_BUS_CYCLE_NS * apic->timer.divide_count;
+ atomic_set(&apic->timer.pending, 0);
+ hrtimer_start(&apic->timer.dev,
+ ktime_add_ns(now, apic->timer.period),
+ HRTIMER_MODE_ABS);
+
+ apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+ PRIx64 ", "
+ "timer initial count 0x%x, period %lldns, "
+ "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__,
+ APIC_BUS_CYCLE_NS, ktime_to_ns(now),
+ apic_get_reg(apic, APIC_TMICT),
+ apic->timer.period,
+ ktime_to_ns(ktime_add_ns(now,
+ apic->timer.period)));
+}
+
+static void apic_mmio_write(struct kvm_io_device *this,
+ gpa_t address, int len, const void *data)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ unsigned int offset = address - apic->base_address;
+ unsigned char alignment = offset & 0xf;
+ u32 val;
+
+ /*
+ * APIC register must be aligned on 128-bits boundary.
+ * 32/64/128 bits registers must be accessed thru 32 bits.
+ * Refer SDM 8.4.1
+ */
+ if (len != 4 || alignment) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "apic write: bad size=%d %lx\n",
+ len, (long)address);
+ return;
+ }
+
+ val = *(u32 *) data;
+
+ /* too common printing */
+ if (offset != APIC_EOI)
+ apic_debug("%s: offset 0x%x with length 0x%x, and value is "
+ "0x%x\n", __FUNCTION__, offset, len, val);
+
+ offset &= 0xff0;
+
+ switch (offset) {
+ case APIC_ID: /* Local APIC ID */
+ apic_set_reg(apic, APIC_ID, val);
+ break;
+
+ case APIC_TASKPRI:
+ apic_set_tpr(apic, val & 0xff);
+ break;
+
+ case APIC_EOI:
+ apic_set_eoi(apic);
+ break;
+
+ case APIC_LDR:
+ apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
+ break;
+
+ case APIC_DFR:
+ apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+ break;
+
+ case APIC_SPIV:
+ apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
+ if (!(val & APIC_SPIV_APIC_ENABLED)) {
+ int i;
+ u32 lvt_val;
+
+ for (i = 0; i < APIC_LVT_NUM; i++) {
+ lvt_val = apic_get_reg(apic,
+ APIC_LVTT + 0x10 * i);
+ apic_set_reg(apic, APIC_LVTT + 0x10 * i,
+ lvt_val | APIC_LVT_MASKED);
+ }
+ atomic_set(&apic->timer.pending, 0);
+
+ }
+ break;
+
+ case APIC_ICR:
+ /* No delay here, so we always clear the pending bit */
+ apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
+ apic_send_ipi(apic);
+ break;
+
+ case APIC_ICR2:
+ apic_set_reg(apic, APIC_ICR2, val & 0xff000000);
+ break;
+
+ case APIC_LVTT:
+ case APIC_LVTTHMR:
+ case APIC_LVTPC:
+ case APIC_LVT0:
+ case APIC_LVT1:
+ case APIC_LVTERR:
+ /* TODO: Check vector */
+ if (!apic_sw_enabled(apic))
+ val |= APIC_LVT_MASKED;
+
+ val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4];
+ apic_set_reg(apic, offset, val);
+
+ break;
+
+ case APIC_TMICT:
+ hrtimer_cancel(&apic->timer.dev);
+ apic_set_reg(apic, APIC_TMICT, val);
+ start_apic_timer(apic);
+ return;
+
+ case APIC_TDCR:
+ if (val & 4)
+ printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val);
+ apic_set_reg(apic, APIC_TDCR, val);
+ update_divide_count(apic);
+ break;
+
+ default:
+ apic_debug("Local APIC Write to read-only register %x\n",
+ offset);
+ break;
+ }
+
+}
+
+static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ int ret = 0;
+
+
+ if (apic_hw_enabled(apic) &&
+ (addr >= apic->base_address) &&
+ (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
+ ret = 1;
+
+ return ret;
+}
+
+void kvm_free_apic(struct kvm_lapic *apic)
+{
+ if (!apic)
+ return;
+
+ hrtimer_cancel(&apic->timer.dev);
+
+ if (apic->regs_page) {
+ __free_page(apic->regs_page);
+ apic->regs_page = 0;
+ }
+
+ kfree(apic);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * LAPIC interface
+ *----------------------------------------------------------------------
+ */
+
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+ if (!apic)
+ return;
+ apic_set_tpr(apic, ((cr8 & 0x0f) << 4));
+}
+
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ u64 tpr;
+
+ if (!apic)
+ return 0;
+ tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
+
+ return (tpr & 0xf0) >> 4;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
+
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+ if (!apic) {
+ value |= MSR_IA32_APICBASE_BSP;
+ vcpu->apic_base = value;
+ return;
+ }
+ if (apic->vcpu->vcpu_id)
+ value &= ~MSR_IA32_APICBASE_BSP;
+
+ vcpu->apic_base = value;
+ apic->base_address = apic->vcpu->apic_base &
+ MSR_IA32_APICBASE_BASE;
+
+ /* with FSB delivery interrupt, we can restart APIC functionality */
+ apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
+ "0x%lx.\n", apic->apic_base, apic->base_address);
+
+}
+
+u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
+{
+ return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
+
+void kvm_lapic_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic;
+ int i;
+
+ apic_debug("%s\n", __FUNCTION__);
+
+ ASSERT(vcpu);
+ apic = vcpu->apic;
+ ASSERT(apic != NULL);
+
+ /* Stop the timer in case it's a reset to an active apic */
+ hrtimer_cancel(&apic->timer.dev);
+
+ apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
+ apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+
+ for (i = 0; i < APIC_LVT_NUM; i++)
+ apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+ apic_set_reg(apic, APIC_LVT0,
+ SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
+
+ apic_set_reg(apic, APIC_DFR, 0xffffffffU);
+ apic_set_reg(apic, APIC_SPIV, 0xff);
+ apic_set_reg(apic, APIC_TASKPRI, 0);
+ apic_set_reg(apic, APIC_LDR, 0);
+ apic_set_reg(apic, APIC_ESR, 0);
+ apic_set_reg(apic, APIC_ICR, 0);
+ apic_set_reg(apic, APIC_ICR2, 0);
+ apic_set_reg(apic, APIC_TDCR, 0);
+ apic_set_reg(apic, APIC_TMICT, 0);
+ for (i = 0; i < 8; i++) {
+ apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
+ apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
+ apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
+ }
+ apic->timer.divide_count = 0;
+ atomic_set(&apic->timer.pending, 0);
+ if (vcpu->vcpu_id == 0)
+ vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ apic_update_ppr(apic);
+
+ apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
+ "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
+ vcpu, kvm_apic_id(apic),
+ vcpu->apic_base, apic->base_address);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_reset);
+
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ int ret = 0;
+
+ if (!apic)
+ return 0;
+ ret = apic_enabled(apic);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
+
+/*
+ *----------------------------------------------------------------------
+ * timer interface
+ *----------------------------------------------------------------------
+ */
+
+/* TODO: make sure __apic_timer_fn runs in current pCPU */
+static int __apic_timer_fn(struct kvm_lapic *apic)
+{
+ int result = 0;
+ wait_queue_head_t *q = &apic->vcpu->wq;
+
+ atomic_inc(&apic->timer.pending);
+ if (waitqueue_active(q))
+ {
+ apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ wake_up_interruptible(q);
+ }
+ if (apic_lvtt_period(apic)) {
+ result = 1;
+ apic->timer.dev.expires = ktime_add_ns(
+ apic->timer.dev.expires,
+ apic->timer.period);
+ }
+ return result;
+}
+
+static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+ int vector;
+
+ vector = apic_lvt_vector(apic, APIC_LVTT);
+ return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+}
+
+static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
+{
+ struct kvm_lapic *apic;
+ int restart_timer = 0;
+
+ apic = container_of(data, struct kvm_lapic, timer.dev);
+
+ restart_timer = __apic_timer_fn(apic);
+
+ if (restart_timer)
+ return HRTIMER_RESTART;
+ else
+ return HRTIMER_NORESTART;
+}
+
+int kvm_create_lapic(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic;
+
+ ASSERT(vcpu != NULL);
+ apic_debug("apic_init %d\n", vcpu->vcpu_id);
+
+ apic = kzalloc(sizeof(*apic), GFP_KERNEL);
+ if (!apic)
+ goto nomem;
+
+ vcpu->apic = apic;
+
+ apic->regs_page = alloc_page(GFP_KERNEL);
+ if (apic->regs_page == NULL) {
+ printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
+ vcpu->vcpu_id);
+ goto nomem;
+ }
+ apic->regs = page_address(apic->regs_page);
+ memset(apic->regs, 0, PAGE_SIZE);
+ apic->vcpu = vcpu;
+
+ hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ apic->timer.dev.function = apic_timer_fn;
+ apic->base_address = APIC_DEFAULT_PHYS_BASE;
+ vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
+
+ kvm_lapic_reset(vcpu);
+ apic->dev.read = apic_mmio_read;
+ apic->dev.write = apic_mmio_write;
+ apic->dev.in_range = apic_mmio_range;
+ apic->dev.private = apic;
+
+ return 0;
+nomem:
+ kvm_free_apic(apic);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_create_lapic);
+
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+ int highest_irr;
+
+ if (!apic || !apic_enabled(apic))
+ return -1;
+
+ apic_update_ppr(apic);
+ highest_irr = apic_find_highest_irr(apic);
+ if ((highest_irr == -1) ||
+ ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
+ return -1;
+ return highest_irr;
+}
+
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
+{
+ u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
+ int r = 0;
+
+ if (vcpu->vcpu_id == 0) {
+ if (!apic_hw_enabled(vcpu->apic))
+ r = 1;
+ if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+ GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+ r = 1;
+ }
+ return r;
+}
+
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (apic && apic_lvt_enabled(apic, APIC_LVTT) &&
+ atomic_read(&apic->timer.pending) > 0) {
+ if (__inject_apic_timer_irq(apic))
+ atomic_dec(&apic->timer.pending);
+ }
+}
+
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
+ apic->timer.last_update = ktime_add_ns(
+ apic->timer.last_update,
+ apic->timer.period);
+}
+
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
+{
+ int vector = kvm_apic_has_interrupt(vcpu);
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (vector == -1)
+ return -1;
+
+ apic_set_vector(vector, apic->regs + APIC_ISR);
+ apic_update_ppr(apic);
+ apic_clear_irr(vector, apic);
+ return vector;
+}
+
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ apic->base_address = vcpu->apic_base &
+ MSR_IA32_APICBASE_BASE;
+ apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+ apic_update_ppr(apic);
+ hrtimer_cancel(&apic->timer.dev);
+ update_divide_count(apic);
+ start_apic_timer(apic);
+}
+
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+ struct hrtimer *timer;
+
+ if (!apic)
+ return;
+
+ timer = &apic->timer.dev;
+ if (hrtimer_cancel(timer))
+ hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
+}
+EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer);
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 23965aa5ee7..6d84d30f5ed 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -158,7 +158,7 @@ static struct kmem_cache *mmu_page_header_cache;
static int is_write_protection(struct kvm_vcpu *vcpu)
{
- return vcpu->cr0 & CR0_WP_MASK;
+ return vcpu->cr0 & X86_CR0_WP;
}
static int is_cpuid_PSE36(void)
@@ -202,15 +202,14 @@ static void set_shadow_pte(u64 *sptep, u64 spte)
}
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
- struct kmem_cache *base_cache, int min,
- gfp_t gfp_flags)
+ struct kmem_cache *base_cache, int min)
{
void *obj;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- obj = kmem_cache_zalloc(base_cache, gfp_flags);
+ obj = kmem_cache_zalloc(base_cache, GFP_KERNEL);
if (!obj)
return -ENOMEM;
cache->objects[cache->nobjs++] = obj;
@@ -225,14 +224,14 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
}
static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
- int min, gfp_t gfp_flags)
+ int min)
{
struct page *page;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- page = alloc_page(gfp_flags);
+ page = alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
set_page_private(page, 0);
@@ -247,44 +246,28 @@ static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
free_page((unsigned long)mc->objects[--mc->nobjs]);
}
-static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
{
int r;
+ kvm_mmu_free_some_pages(vcpu);
r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
- pte_chain_cache, 4, gfp_flags);
+ pte_chain_cache, 4);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
- rmap_desc_cache, 1, gfp_flags);
+ rmap_desc_cache, 1);
if (r)
goto out;
- r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
+ r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
- mmu_page_header_cache, 4, gfp_flags);
+ mmu_page_header_cache, 4);
out:
return r;
}
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
-{
- int r;
-
- r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
- kvm_mmu_free_some_pages(vcpu);
- if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
- kvm_arch_ops->vcpu_put(vcpu);
- r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
- kvm_arch_ops->vcpu_load(vcpu);
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_free_some_pages(vcpu);
- }
- return r;
-}
-
static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
@@ -969,7 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
{
++vcpu->stat.tlb_flush;
- kvm_arch_ops->tlb_flush(vcpu);
+ kvm_x86_ops->tlb_flush(vcpu);
}
static void paging_new_cr3(struct kvm_vcpu *vcpu)
@@ -982,7 +965,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
u64 addr,
u32 err_code)
{
- kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
+ kvm_x86_ops->inject_page_fault(vcpu, addr, err_code);
}
static void paging_free(struct kvm_vcpu *vcpu)
@@ -1071,15 +1054,15 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
{
int r;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
r = mmu_topup_memory_caches(vcpu);
if (r)
goto out;
mmu_alloc_roots(vcpu);
- kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+ kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
kvm_mmu_flush_tlb(vcpu);
out:
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return r;
}
EXPORT_SYMBOL_GPL(kvm_mmu_load);
@@ -1124,7 +1107,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
}
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
- const u8 *old, const u8 *new, int bytes)
+ const u8 *new, int bytes)
{
gfn_t gfn = gpa >> PAGE_SHIFT;
struct kvm_mmu_page *page;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 4b5391c717f..6b094b44f8f 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -58,7 +58,10 @@ struct guest_walker {
int level;
gfn_t table_gfn[PT_MAX_FULL_LEVELS];
pt_element_t *table;
+ pt_element_t pte;
pt_element_t *ptep;
+ struct page *page;
+ int index;
pt_element_t inherited_ar;
gfn_t gfn;
u32 error_code;
@@ -80,11 +83,14 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
walker->level = vcpu->mmu.root_level;
walker->table = NULL;
+ walker->page = NULL;
+ walker->ptep = NULL;
root = vcpu->cr3;
#if PTTYPE == 64
if (!is_long_mode(vcpu)) {
walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3];
root = *walker->ptep;
+ walker->pte = root;
if (!(root & PT_PRESENT_MASK))
goto not_present;
--walker->level;
@@ -96,10 +102,11 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
walker->level - 1, table_gfn);
slot = gfn_to_memslot(vcpu->kvm, table_gfn);
hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK);
- walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
+ walker->page = pfn_to_page(hpa >> PAGE_SHIFT);
+ walker->table = kmap_atomic(walker->page, KM_USER0);
ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
- (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
+ (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
@@ -108,6 +115,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
hpa_t paddr;
ptep = &walker->table[index];
+ walker->index = index;
ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
((unsigned long)ptep & PAGE_MASK));
@@ -148,16 +156,20 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
walker->inherited_ar &= walker->table[index];
table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
- paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
kunmap_atomic(walker->table, KM_USER0);
- walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT),
- KM_USER0);
+ paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT);
+ walker->page = pfn_to_page(paddr >> PAGE_SHIFT);
+ walker->table = kmap_atomic(walker->page, KM_USER0);
--walker->level;
walker->table_gfn[walker->level - 1 ] = table_gfn;
pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
walker->level - 1, table_gfn);
}
- walker->ptep = ptep;
+ walker->pte = *ptep;
+ if (walker->page)
+ walker->ptep = NULL;
+ if (walker->table)
+ kunmap_atomic(walker->table, KM_USER0);
pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep);
return 1;
@@ -175,13 +187,9 @@ err:
walker->error_code |= PFERR_USER_MASK;
if (fetch_fault)
walker->error_code |= PFERR_FETCH_MASK;
- return 0;
-}
-
-static void FNAME(release_walker)(struct guest_walker *walker)
-{
if (walker->table)
kunmap_atomic(walker->table, KM_USER0);
+ return 0;
}
static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
@@ -193,7 +201,7 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
u64 *shadow_pte,
gpa_t gaddr,
- pt_element_t *gpte,
+ pt_element_t gpte,
u64 access_bits,
int user_fault,
int write_fault,
@@ -202,23 +210,34 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
gfn_t gfn)
{
hpa_t paddr;
- int dirty = *gpte & PT_DIRTY_MASK;
+ int dirty = gpte & PT_DIRTY_MASK;
u64 spte = *shadow_pte;
int was_rmapped = is_rmap_pte(spte);
pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
" user_fault %d gfn %lx\n",
- __FUNCTION__, spte, (u64)*gpte, access_bits,
+ __FUNCTION__, spte, (u64)gpte, access_bits,
write_fault, user_fault, gfn);
if (write_fault && !dirty) {
- *gpte |= PT_DIRTY_MASK;
+ pt_element_t *guest_ent, *tmp = NULL;
+
+ if (walker->ptep)
+ guest_ent = walker->ptep;
+ else {
+ tmp = kmap_atomic(walker->page, KM_USER0);
+ guest_ent = &tmp[walker->index];
+ }
+
+ *guest_ent |= PT_DIRTY_MASK;
+ if (!walker->ptep)
+ kunmap_atomic(tmp, KM_USER0);
dirty = 1;
FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
}
spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
- spte |= *gpte & PT64_NX_MASK;
+ spte |= gpte & PT64_NX_MASK;
if (!dirty)
access_bits &= ~PT_WRITABLE_MASK;
@@ -255,7 +274,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
access_bits &= ~PT_WRITABLE_MASK;
if (is_writeble_pte(spte)) {
spte &= ~PT_WRITABLE_MASK;
- kvm_arch_ops->tlb_flush(vcpu);
+ kvm_x86_ops->tlb_flush(vcpu);
}
if (write_fault)
*ptwrite = 1;
@@ -273,13 +292,13 @@ unshadowed:
rmap_add(vcpu, shadow_pte);
}
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte,
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
u64 *shadow_pte, u64 access_bits,
int user_fault, int write_fault, int *ptwrite,
struct guest_walker *walker, gfn_t gfn)
{
- access_bits &= *gpte;
- FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK,
+ access_bits &= gpte;
+ FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK,
gpte, access_bits, user_fault, write_fault,
ptwrite, walker, gfn);
}
@@ -295,22 +314,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
return;
pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
- FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
+ FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
0, NULL, NULL,
(gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
}
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde,
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde,
u64 *shadow_pte, u64 access_bits,
int user_fault, int write_fault, int *ptwrite,
struct guest_walker *walker, gfn_t gfn)
{
gpa_t gaddr;
- access_bits &= *gpde;
+ access_bits &= gpde;
gaddr = (gpa_t)gfn << PAGE_SHIFT;
if (PTTYPE == 32 && is_cpuid_PSE36())
- gaddr |= (*gpde & PT32_DIR_PSE36_MASK) <<
+ gaddr |= (gpde & PT32_DIR_PSE36_MASK) <<
(32 - PT32_DIR_PSE36_SHIFT);
FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
gpde, access_bits, user_fault, write_fault,
@@ -328,9 +347,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
int level;
u64 *shadow_ent;
u64 *prev_shadow_ent = NULL;
- pt_element_t *guest_ent = walker->ptep;
- if (!is_present_pte(*guest_ent))
+ if (!is_present_pte(walker->pte))
return NULL;
shadow_addr = vcpu->mmu.root_hpa;
@@ -364,12 +382,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
if (level - 1 == PT_PAGE_TABLE_LEVEL
&& walker->level == PT_DIRECTORY_LEVEL) {
metaphysical = 1;
- hugepage_access = *guest_ent;
+ hugepage_access = walker->pte;
hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
- if (*guest_ent & PT64_NX_MASK)
+ if (walker->pte & PT64_NX_MASK)
hugepage_access |= (1 << 2);
hugepage_access >>= PT_WRITABLE_SHIFT;
- table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
+ table_gfn = (walker->pte & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
} else {
metaphysical = 0;
@@ -386,12 +404,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
}
if (walker->level == PT_DIRECTORY_LEVEL) {
- FNAME(set_pde)(vcpu, guest_ent, shadow_ent,
+ FNAME(set_pde)(vcpu, walker->pte, shadow_ent,
walker->inherited_ar, user_fault, write_fault,
ptwrite, walker, walker->gfn);
} else {
ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
- FNAME(set_pte)(vcpu, guest_ent, shadow_ent,
+ FNAME(set_pte)(vcpu, walker->pte, shadow_ent,
walker->inherited_ar, user_fault, write_fault,
ptwrite, walker, walker->gfn);
}
@@ -442,7 +460,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
if (!r) {
pgprintk("%s: guest page fault\n", __FUNCTION__);
inject_page_fault(vcpu, addr, walker.error_code);
- FNAME(release_walker)(&walker);
vcpu->last_pt_write_count = 0; /* reset fork detector */
return 0;
}
@@ -452,8 +469,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
shadow_pte, *shadow_pte, write_pt);
- FNAME(release_walker)(&walker);
-
if (!write_pt)
vcpu->last_pt_write_count = 0; /* reset fork detector */
@@ -482,7 +497,6 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
gpa |= vaddr & ~PAGE_MASK;
}
- FNAME(release_walker)(&walker);
return gpa;
}
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index bc818cc126e..729f1cd9360 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -16,12 +16,12 @@
#include "kvm_svm.h"
#include "x86_emulate.h"
+#include "irq.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
-#include <linux/profile.h>
#include <linux/sched.h>
#include <asm/desc.h>
@@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
#define DR7_GD_MASK (1 << 13)
#define DR6_BD_MASK (1 << 13)
-#define CR4_DE_MASK (1UL << 3)
#define SEG_TYPE_LDT 2
#define SEG_TYPE_BUSY_TSS16 3
@@ -50,6 +49,13 @@ MODULE_LICENSE("GPL");
#define SVM_FEATURE_LBRV (1 << 1)
#define SVM_DEATURE_SVML (1 << 2)
+static void kvm_reput_irq(struct vcpu_svm *svm);
+
+static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+{
+ return container_of(vcpu, struct vcpu_svm, vcpu);
+}
+
unsigned long iopm_base;
unsigned long msrpm_base;
@@ -94,20 +100,6 @@ static inline u32 svm_has(u32 feat)
return svm_features & feat;
}
-static unsigned get_addr_size(struct kvm_vcpu *vcpu)
-{
- struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
- u16 cs_attrib;
-
- if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM))
- return 2;
-
- cs_attrib = sa->cs.attrib;
-
- return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
- (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
-}
-
static inline u8 pop_irq(struct kvm_vcpu *vcpu)
{
int word_index = __ffs(vcpu->irq_summary);
@@ -182,7 +174,7 @@ static inline void write_dr7(unsigned long val)
static inline void force_new_asid(struct kvm_vcpu *vcpu)
{
- vcpu->svm->asid_generation--;
+ to_svm(vcpu)->asid_generation--;
}
static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
@@ -195,22 +187,24 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
if (!(efer & KVM_EFER_LMA))
efer &= ~KVM_EFER_LME;
- vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
+ to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
vcpu->shadow_efer = efer;
}
static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
{
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
SVM_EVTINJ_VALID_ERR |
SVM_EVTINJ_TYPE_EXEPT |
GP_VECTOR;
- vcpu->svm->vmcb->control.event_inj_err = error_code;
+ svm->vmcb->control.event_inj_err = error_code;
}
static void inject_ud(struct kvm_vcpu *vcpu)
{
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID |
SVM_EVTINJ_TYPE_EXEPT |
UD_VECTOR;
}
@@ -229,19 +223,21 @@ static int is_external_interrupt(u32 info)
static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
{
- if (!vcpu->svm->next_rip) {
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!svm->next_rip) {
printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
return;
}
- if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) {
+ if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) {
printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
__FUNCTION__,
- vcpu->svm->vmcb->save.rip,
- vcpu->svm->next_rip);
+ svm->vmcb->save.rip,
+ svm->next_rip);
}
- vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
- vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+ vcpu->rip = svm->vmcb->save.rip = svm->next_rip;
+ svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
vcpu->interrupt_window_open = 1;
}
@@ -351,8 +347,8 @@ err_1:
}
-static int set_msr_interception(u32 *msrpm, unsigned msr,
- int read, int write)
+static void set_msr_interception(u32 *msrpm, unsigned msr,
+ int read, int write)
{
int i;
@@ -367,11 +363,10 @@ static int set_msr_interception(u32 *msrpm, unsigned msr,
u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
*base = (*base & ~(0x3 << msr_shift)) |
(mask << msr_shift);
- return 1;
+ return;
}
}
- printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr);
- return 0;
+ BUG();
}
static __init int svm_hardware_setup(void)
@@ -382,8 +377,6 @@ static __init int svm_hardware_setup(void)
void *iopm_va, *msrpm_va;
int r;
- kvm_emulator_want_group7_invlpg();
-
iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
if (!iopm_pages)
@@ -458,11 +451,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
-static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
-{
- return 0;
-}
-
static void init_vmcb(struct vmcb *vmcb)
{
struct vmcb_control_area *control = &vmcb->control;
@@ -563,59 +551,83 @@ static void init_vmcb(struct vmcb *vmcb)
* cr0 val on cpu init should be 0x60000010, we enable cpu
* cache by default. the orderly way is to enable cache in bios.
*/
- save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK;
- save->cr4 = CR4_PAE_MASK;
+ save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
+ save->cr4 = X86_CR4_PAE;
/* rdx = ?? */
}
-static int svm_create_vcpu(struct kvm_vcpu *vcpu)
+static void svm_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ init_vmcb(svm->vmcb);
+}
+
+static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
{
+ struct vcpu_svm *svm;
struct page *page;
- int r;
+ int err;
+
+ svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ if (!svm) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = kvm_vcpu_init(&svm->vcpu, kvm, id);
+ if (err)
+ goto free_svm;
+
+ if (irqchip_in_kernel(kvm)) {
+ err = kvm_create_lapic(&svm->vcpu);
+ if (err < 0)
+ goto free_svm;
+ }
- r = -ENOMEM;
- vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
- if (!vcpu->svm)
- goto out1;
page = alloc_page(GFP_KERNEL);
- if (!page)
- goto out2;
-
- vcpu->svm->vmcb = page_address(page);
- clear_page(vcpu->svm->vmcb);
- vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
- vcpu->svm->asid_generation = 0;
- memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
- init_vmcb(vcpu->svm->vmcb);
-
- fx_init(vcpu);
- vcpu->fpu_active = 1;
- vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (vcpu == &vcpu->kvm->vcpus[0])
- vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ if (!page) {
+ err = -ENOMEM;
+ goto uninit;
+ }
- return 0;
+ svm->vmcb = page_address(page);
+ clear_page(svm->vmcb);
+ svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
+ svm->asid_generation = 0;
+ memset(svm->db_regs, 0, sizeof(svm->db_regs));
+ init_vmcb(svm->vmcb);
-out2:
- kfree(vcpu->svm);
-out1:
- return r;
+ fx_init(&svm->vcpu);
+ svm->vcpu.fpu_active = 1;
+ svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (svm->vcpu.vcpu_id == 0)
+ svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
+
+ return &svm->vcpu;
+
+uninit:
+ kvm_vcpu_uninit(&svm->vcpu);
+free_svm:
+ kmem_cache_free(kvm_vcpu_cache, svm);
+out:
+ return ERR_PTR(err);
}
static void svm_free_vcpu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->svm)
- return;
- if (vcpu->svm->vmcb)
- __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
- kfree(vcpu->svm);
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
+ kvm_vcpu_uninit(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, svm);
}
-static void svm_vcpu_load(struct kvm_vcpu *vcpu)
+static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
- int cpu, i;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int i;
- cpu = get_cpu();
if (unlikely(cpu != vcpu->cpu)) {
u64 tsc_this, delta;
@@ -625,23 +637,24 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu)
*/
rdtscll(tsc_this);
delta = vcpu->host_tsc - tsc_this;
- vcpu->svm->vmcb->control.tsc_offset += delta;
+ svm->vmcb->control.tsc_offset += delta;
vcpu->cpu = cpu;
+ kvm_migrate_apic_timer(vcpu);
}
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
- rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+ rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
int i;
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
- wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+ wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
rdtscll(vcpu->host_tsc);
- put_cpu();
}
static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
@@ -650,31 +663,34 @@ static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
static void svm_cache_regs(struct kvm_vcpu *vcpu)
{
- vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
- vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp;
- vcpu->rip = vcpu->svm->vmcb->save.rip;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
+ vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
+ vcpu->rip = svm->vmcb->save.rip;
}
static void svm_decache_regs(struct kvm_vcpu *vcpu)
{
- vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
- vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
- vcpu->svm->vmcb->save.rip = vcpu->rip;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
+ svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
+ svm->vmcb->save.rip = vcpu->rip;
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
{
- return vcpu->svm->vmcb->save.rflags;
+ return to_svm(vcpu)->vmcb->save.rflags;
}
static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
- vcpu->svm->vmcb->save.rflags = rflags;
+ to_svm(vcpu)->vmcb->save.rflags = rflags;
}
static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
{
- struct vmcb_save_area *save = &vcpu->svm->vmcb->save;
+ struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
switch (seg) {
case VCPU_SREG_CS: return &save->cs;
@@ -716,36 +732,36 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
var->unusable = !var->present;
}
-static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
- struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
-
- *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
- *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
-}
-
static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- dt->limit = vcpu->svm->vmcb->save.idtr.limit;
- dt->base = vcpu->svm->vmcb->save.idtr.base;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ dt->limit = svm->vmcb->save.idtr.limit;
+ dt->base = svm->vmcb->save.idtr.base;
}
static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- vcpu->svm->vmcb->save.idtr.limit = dt->limit;
- vcpu->svm->vmcb->save.idtr.base = dt->base ;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.idtr.limit = dt->limit;
+ svm->vmcb->save.idtr.base = dt->base ;
}
static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- dt->limit = vcpu->svm->vmcb->save.gdtr.limit;
- dt->base = vcpu->svm->vmcb->save.gdtr.base;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ dt->limit = svm->vmcb->save.gdtr.limit;
+ dt->base = svm->vmcb->save.gdtr.base;
}
static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- vcpu->svm->vmcb->save.gdtr.limit = dt->limit;
- vcpu->svm->vmcb->save.gdtr.base = dt->base ;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.gdtr.limit = dt->limit;
+ svm->vmcb->save.gdtr.base = dt->base ;
}
static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
@@ -754,39 +770,42 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
#ifdef CONFIG_X86_64
if (vcpu->shadow_efer & KVM_EFER_LME) {
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
vcpu->shadow_efer |= KVM_EFER_LMA;
- vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
+ svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
}
- if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
+ if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) {
vcpu->shadow_efer &= ~KVM_EFER_LMA;
- vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
+ svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
}
}
#endif
- if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
- vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
+ svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
vcpu->fpu_active = 1;
}
vcpu->cr0 = cr0;
- cr0 |= CR0_PG_MASK | CR0_WP_MASK;
- cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
- vcpu->svm->vmcb->save.cr0 = cr0;
+ cr0 |= X86_CR0_PG | X86_CR0_WP;
+ cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
+ svm->vmcb->save.cr0 = cr0;
}
static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
vcpu->cr4 = cr4;
- vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK;
+ to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE;
}
static void svm_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb_seg *s = svm_seg(vcpu, seg);
s->base = var->base;
@@ -805,16 +824,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
}
if (seg == VCPU_SREG_CS)
- vcpu->svm->vmcb->save.cpl
- = (vcpu->svm->vmcb->save.cs.attrib
+ svm->vmcb->save.cpl
+ = (svm->vmcb->save.cs.attrib
>> SVM_SELECTOR_DPL_SHIFT) & 3;
}
/* FIXME:
- vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
- vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
+ svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK;
+ svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
*/
@@ -823,61 +842,68 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
return -EOPNOTSUPP;
}
+static int svm_get_irq(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 exit_int_info = svm->vmcb->control.exit_int_info;
+
+ if (is_external_interrupt(exit_int_info))
+ return exit_int_info & SVM_EVTINJ_VEC_MASK;
+ return -1;
+}
+
static void load_host_msrs(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
- wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+ wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
#endif
}
static void save_host_msrs(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
- rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+ rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
#endif
}
-static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
+static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
{
if (svm_data->next_asid > svm_data->max_asid) {
++svm_data->asid_generation;
svm_data->next_asid = 1;
- vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
+ svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
}
- vcpu->cpu = svm_data->cpu;
- vcpu->svm->asid_generation = svm_data->asid_generation;
- vcpu->svm->vmcb->control.asid = svm_data->next_asid++;
-}
-
-static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
-{
- invlpga(address, vcpu->svm->vmcb->control.asid); // is needed?
+ svm->vcpu.cpu = svm_data->cpu;
+ svm->asid_generation = svm_data->asid_generation;
+ svm->vmcb->control.asid = svm_data->next_asid++;
}
static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
{
- return vcpu->svm->db_regs[dr];
+ return to_svm(vcpu)->db_regs[dr];
}
static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
int *exception)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
*exception = 0;
- if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) {
- vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
- vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK;
+ if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
+ svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
+ svm->vmcb->save.dr6 |= DR6_BD_MASK;
*exception = DB_VECTOR;
return;
}
switch (dr) {
case 0 ... 3:
- vcpu->svm->db_regs[dr] = value;
+ svm->db_regs[dr] = value;
return;
case 4 ... 5:
- if (vcpu->cr4 & CR4_DE_MASK) {
+ if (vcpu->cr4 & X86_CR4_DE) {
*exception = UD_VECTOR;
return;
}
@@ -886,7 +912,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
*exception = GP_VECTOR;
return;
}
- vcpu->svm->vmcb->save.dr7 = value;
+ svm->vmcb->save.dr7 = value;
return;
}
default:
@@ -897,42 +923,44 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
}
}
-static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+ u32 exit_int_info = svm->vmcb->control.exit_int_info;
+ struct kvm *kvm = svm->vcpu.kvm;
u64 fault_address;
u32 error_code;
enum emulation_result er;
int r;
- if (is_external_interrupt(exit_int_info))
- push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+ if (!irqchip_in_kernel(kvm) &&
+ is_external_interrupt(exit_int_info))
+ push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&kvm->lock);
- fault_address = vcpu->svm->vmcb->control.exit_info_2;
- error_code = vcpu->svm->vmcb->control.exit_info_1;
- r = kvm_mmu_page_fault(vcpu, fault_address, error_code);
+ fault_address = svm->vmcb->control.exit_info_2;
+ error_code = svm->vmcb->control.exit_info_1;
+ r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&kvm->lock);
return r;
}
if (!r) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&kvm->lock);
return 1;
}
- er = emulate_instruction(vcpu, kvm_run, fault_address, error_code);
- spin_unlock(&vcpu->kvm->lock);
+ er = emulate_instruction(&svm->vcpu, kvm_run, fault_address,
+ error_code);
+ mutex_unlock(&kvm->lock);
switch (er) {
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
- ++vcpu->stat.mmio_exits;
- kvm_run->exit_reason = KVM_EXIT_MMIO;
+ ++svm->vcpu.stat.mmio_exits;
return 0;
case EMULATE_FAIL:
- vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ kvm_report_emulation_failure(&svm->vcpu, "pagetable");
break;
default:
BUG();
@@ -942,252 +970,142 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
- if (!(vcpu->cr0 & CR0_TS_MASK))
- vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
- vcpu->fpu_active = 1;
+ svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ if (!(svm->vcpu.cr0 & X86_CR0_TS))
+ svm->vmcb->save.cr0 &= ~X86_CR0_TS;
+ svm->vcpu.fpu_active = 1;
- return 1;
+ return 1;
}
-static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
/*
* VMCB is undefined after a SHUTDOWN intercept
* so reinitialize it.
*/
- clear_page(vcpu->svm->vmcb);
- init_vmcb(vcpu->svm->vmcb);
+ clear_page(svm->vmcb);
+ init_vmcb(svm->vmcb);
kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
return 0;
}
-static int io_get_override(struct kvm_vcpu *vcpu,
- struct vmcb_seg **seg,
- int *addr_override)
-{
- u8 inst[MAX_INST_SIZE];
- unsigned ins_length;
- gva_t rip;
- int i;
-
- rip = vcpu->svm->vmcb->save.rip;
- ins_length = vcpu->svm->next_rip - rip;
- rip += vcpu->svm->vmcb->save.cs.base;
-
- if (ins_length > MAX_INST_SIZE)
- printk(KERN_DEBUG
- "%s: inst length err, cs base 0x%llx rip 0x%llx "
- "next rip 0x%llx ins_length %u\n",
- __FUNCTION__,
- vcpu->svm->vmcb->save.cs.base,
- vcpu->svm->vmcb->save.rip,
- vcpu->svm->vmcb->control.exit_info_2,
- ins_length);
-
- if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length)
- /* #PF */
- return 0;
-
- *addr_override = 0;
- *seg = NULL;
- for (i = 0; i < ins_length; i++)
- switch (inst[i]) {
- case 0xf0:
- case 0xf2:
- case 0xf3:
- case 0x66:
- continue;
- case 0x67:
- *addr_override = 1;
- continue;
- case 0x2e:
- *seg = &vcpu->svm->vmcb->save.cs;
- continue;
- case 0x36:
- *seg = &vcpu->svm->vmcb->save.ss;
- continue;
- case 0x3e:
- *seg = &vcpu->svm->vmcb->save.ds;
- continue;
- case 0x26:
- *seg = &vcpu->svm->vmcb->save.es;
- continue;
- case 0x64:
- *seg = &vcpu->svm->vmcb->save.fs;
- continue;
- case 0x65:
- *seg = &vcpu->svm->vmcb->save.gs;
- continue;
- default:
- return 1;
- }
- printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
- return 0;
-}
-
-static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address)
+static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- unsigned long addr_mask;
- unsigned long *reg;
- struct vmcb_seg *seg;
- int addr_override;
- struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save;
- u16 cs_attrib = save_area->cs.attrib;
- unsigned addr_size = get_addr_size(vcpu);
-
- if (!io_get_override(vcpu, &seg, &addr_override))
- return 0;
-
- if (addr_override)
- addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
+ u32 io_info = svm->vmcb->control.exit_info_1; //address size bug?
+ int size, down, in, string, rep;
+ unsigned port;
- if (ins) {
- reg = &vcpu->regs[VCPU_REGS_RDI];
- seg = &vcpu->svm->vmcb->save.es;
- } else {
- reg = &vcpu->regs[VCPU_REGS_RSI];
- seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds;
- }
+ ++svm->vcpu.stat.io_exits;
- addr_mask = ~0ULL >> (64 - (addr_size * 8));
+ svm->next_rip = svm->vmcb->control.exit_info_2;
- if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
- !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
- *address = (*reg & addr_mask);
- return addr_mask;
- }
+ string = (io_info & SVM_IOIO_STR_MASK) != 0;
- if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
- svm_inject_gp(vcpu, 0);
- return 0;
+ if (string) {
+ if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+ return 0;
+ return 1;
}
- *address = (*reg & addr_mask) + seg->base;
- return addr_mask;
-}
-
-static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
- u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
- int size, down, in, string, rep;
- unsigned port;
- unsigned long count;
- gva_t address = 0;
-
- ++vcpu->stat.io_exits;
-
- vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
-
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
port = io_info >> 16;
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
- string = (io_info & SVM_IOIO_STR_MASK) != 0;
rep = (io_info & SVM_IOIO_REP_MASK) != 0;
- count = 1;
- down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
+ down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
- if (string) {
- unsigned addr_mask;
-
- addr_mask = io_adress(vcpu, in, &address);
- if (!addr_mask) {
- printk(KERN_DEBUG "%s: get io address failed\n",
- __FUNCTION__);
- return 1;
- }
-
- if (rep)
- count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
- }
- return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
- address, rep, port);
+ return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
}
-static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
return 1;
}
-static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
- skip_emulated_instruction(vcpu);
- return kvm_emulate_halt(vcpu);
+ svm->next_rip = svm->vmcb->save.rip + 1;
+ skip_emulated_instruction(&svm->vcpu);
+ return kvm_emulate_halt(&svm->vcpu);
}
-static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3;
- skip_emulated_instruction(vcpu);
- return kvm_hypercall(vcpu, kvm_run);
+ svm->next_rip = svm->vmcb->save.rip + 3;
+ skip_emulated_instruction(&svm->vcpu);
+ return kvm_hypercall(&svm->vcpu, kvm_run);
}
-static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int invalid_op_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- inject_ud(vcpu);
+ inject_ud(&svm->vcpu);
return 1;
}
-static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int task_switch_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__);
+ pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__);
kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
return 0;
}
-static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- kvm_emulate_cpuid(vcpu);
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ kvm_emulate_cpuid(&svm->vcpu);
return 1;
}
-static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int emulate_on_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
- printk(KERN_ERR "%s: failed\n", __FUNCTION__);
+ if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE)
+ pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__);
return 1;
}
static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER: {
u64 tsc;
rdtscll(tsc);
- *data = vcpu->svm->vmcb->control.tsc_offset + tsc;
+ *data = svm->vmcb->control.tsc_offset + tsc;
break;
}
case MSR_K6_STAR:
- *data = vcpu->svm->vmcb->save.star;
+ *data = svm->vmcb->save.star;
break;
#ifdef CONFIG_X86_64
case MSR_LSTAR:
- *data = vcpu->svm->vmcb->save.lstar;
+ *data = svm->vmcb->save.lstar;
break;
case MSR_CSTAR:
- *data = vcpu->svm->vmcb->save.cstar;
+ *data = svm->vmcb->save.cstar;
break;
case MSR_KERNEL_GS_BASE:
- *data = vcpu->svm->vmcb->save.kernel_gs_base;
+ *data = svm->vmcb->save.kernel_gs_base;
break;
case MSR_SYSCALL_MASK:
- *data = vcpu->svm->vmcb->save.sfmask;
+ *data = svm->vmcb->save.sfmask;
break;
#endif
case MSR_IA32_SYSENTER_CS:
- *data = vcpu->svm->vmcb->save.sysenter_cs;
+ *data = svm->vmcb->save.sysenter_cs;
break;
case MSR_IA32_SYSENTER_EIP:
- *data = vcpu->svm->vmcb->save.sysenter_eip;
+ *data = svm->vmcb->save.sysenter_eip;
break;
case MSR_IA32_SYSENTER_ESP:
- *data = vcpu->svm->vmcb->save.sysenter_esp;
+ *data = svm->vmcb->save.sysenter_esp;
break;
default:
return kvm_get_msr_common(vcpu, ecx, data);
@@ -1195,57 +1113,59 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
return 0;
}
-static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
u64 data;
- if (svm_get_msr(vcpu, ecx, &data))
- svm_inject_gp(vcpu, 0);
+ if (svm_get_msr(&svm->vcpu, ecx, &data))
+ svm_inject_gp(&svm->vcpu, 0);
else {
- vcpu->svm->vmcb->save.rax = data & 0xffffffff;
- vcpu->regs[VCPU_REGS_RDX] = data >> 32;
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- skip_emulated_instruction(vcpu);
+ svm->vmcb->save.rax = data & 0xffffffff;
+ svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32;
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ skip_emulated_instruction(&svm->vcpu);
}
return 1;
}
static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER: {
u64 tsc;
rdtscll(tsc);
- vcpu->svm->vmcb->control.tsc_offset = data - tsc;
+ svm->vmcb->control.tsc_offset = data - tsc;
break;
}
case MSR_K6_STAR:
- vcpu->svm->vmcb->save.star = data;
+ svm->vmcb->save.star = data;
break;
#ifdef CONFIG_X86_64
case MSR_LSTAR:
- vcpu->svm->vmcb->save.lstar = data;
+ svm->vmcb->save.lstar = data;
break;
case MSR_CSTAR:
- vcpu->svm->vmcb->save.cstar = data;
+ svm->vmcb->save.cstar = data;
break;
case MSR_KERNEL_GS_BASE:
- vcpu->svm->vmcb->save.kernel_gs_base = data;
+ svm->vmcb->save.kernel_gs_base = data;
break;
case MSR_SYSCALL_MASK:
- vcpu->svm->vmcb->save.sfmask = data;
+ svm->vmcb->save.sfmask = data;
break;
#endif
case MSR_IA32_SYSENTER_CS:
- vcpu->svm->vmcb->save.sysenter_cs = data;
+ svm->vmcb->save.sysenter_cs = data;
break;
case MSR_IA32_SYSENTER_EIP:
- vcpu->svm->vmcb->save.sysenter_eip = data;
+ svm->vmcb->save.sysenter_eip = data;
break;
case MSR_IA32_SYSENTER_ESP:
- vcpu->svm->vmcb->save.sysenter_esp = data;
+ svm->vmcb->save.sysenter_esp = data;
break;
default:
return kvm_set_msr_common(vcpu, ecx, data);
@@ -1253,37 +1173,39 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
return 0;
}
-static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 ecx = vcpu->regs[VCPU_REGS_RCX];
- u64 data = (vcpu->svm->vmcb->save.rax & -1u)
- | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- if (svm_set_msr(vcpu, ecx, data))
- svm_inject_gp(vcpu, 0);
+ u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
+ u64 data = (svm->vmcb->save.rax & -1u)
+ | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32);
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ if (svm_set_msr(&svm->vcpu, ecx, data))
+ svm_inject_gp(&svm->vcpu, 0);
else
- skip_emulated_instruction(vcpu);
+ skip_emulated_instruction(&svm->vcpu);
return 1;
}
-static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- if (vcpu->svm->vmcb->control.exit_info_1)
- return wrmsr_interception(vcpu, kvm_run);
+ if (svm->vmcb->control.exit_info_1)
+ return wrmsr_interception(svm, kvm_run);
else
- return rdmsr_interception(vcpu, kvm_run);
+ return rdmsr_interception(svm, kvm_run);
}
-static int interrupt_window_interception(struct kvm_vcpu *vcpu,
+static int interrupt_window_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
+ svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
+ svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
*/
if (kvm_run->request_interrupt_window &&
- !vcpu->irq_summary) {
- ++vcpu->stat.irq_window_exits;
+ !svm->vcpu.irq_summary) {
+ ++svm->vcpu.stat.irq_window_exits;
kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
return 0;
}
@@ -1291,7 +1213,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
return 1;
}
-static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
+static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
struct kvm_run *kvm_run) = {
[SVM_EXIT_READ_CR0] = emulate_on_interception,
[SVM_EXIT_READ_CR3] = emulate_on_interception,
@@ -1338,15 +1260,25 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
};
-static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
- u32 exit_code = vcpu->svm->vmcb->control.exit_code;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 exit_code = svm->vmcb->control.exit_code;
+
+ kvm_reput_irq(svm);
- if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
+ if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = svm->vmcb->control.exit_code;
+ return 0;
+ }
+
+ if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
"exit_code 0x%x\n",
- __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
+ __FUNCTION__, svm->vmcb->control.exit_int_info,
exit_code);
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
@@ -1356,7 +1288,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
- return svm_exit_handlers[exit_code](vcpu, kvm_run);
+ return svm_exit_handlers[exit_code](svm, kvm_run);
}
static void reload_tss(struct kvm_vcpu *vcpu)
@@ -1368,93 +1300,126 @@ static void reload_tss(struct kvm_vcpu *vcpu)
load_TR_desc();
}
-static void pre_svm_run(struct kvm_vcpu *vcpu)
+static void pre_svm_run(struct vcpu_svm *svm)
{
int cpu = raw_smp_processor_id();
struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
- vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
- if (vcpu->cpu != cpu ||
- vcpu->svm->asid_generation != svm_data->asid_generation)
- new_asid(vcpu, svm_data);
+ svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+ if (svm->vcpu.cpu != cpu ||
+ svm->asid_generation != svm_data->asid_generation)
+ new_asid(svm, svm_data);
}
-static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
{
struct vmcb_control_area *control;
- control = &vcpu->svm->vmcb->control;
- control->int_vector = pop_irq(vcpu);
+ control = &svm->vmcb->control;
+ control->int_vector = irq;
control->int_ctl &= ~V_INTR_PRIO_MASK;
control->int_ctl |= V_IRQ_MASK |
((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
}
-static void kvm_reput_irq(struct kvm_vcpu *vcpu)
+static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm_inject_irq(svm, irq);
+}
+
+static void svm_intr_assist(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb *vmcb = svm->vmcb;
+ int intr_vector = -1;
+
+ kvm_inject_pending_timer_irqs(vcpu);
+ if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
+ ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
+ intr_vector = vmcb->control.exit_int_info &
+ SVM_EVTINJ_VEC_MASK;
+ vmcb->control.exit_int_info = 0;
+ svm_inject_irq(svm, intr_vector);
+ return;
+ }
+
+ if (vmcb->control.int_ctl & V_IRQ_MASK)
+ return;
+
+ if (!kvm_cpu_has_interrupt(vcpu))
+ return;
+
+ if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
+ (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
+ (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+ /* unable to deliver irq, set pending irq */
+ vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
+ svm_inject_irq(svm, 0x0);
+ return;
+ }
+ /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+ intr_vector = kvm_cpu_get_interrupt(vcpu);
+ svm_inject_irq(svm, intr_vector);
+ kvm_timer_intr_post(vcpu, intr_vector);
+}
+
+static void kvm_reput_irq(struct vcpu_svm *svm)
{
- struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+ struct vmcb_control_area *control = &svm->vmcb->control;
- if (control->int_ctl & V_IRQ_MASK) {
+ if ((control->int_ctl & V_IRQ_MASK)
+ && !irqchip_in_kernel(svm->vcpu.kvm)) {
control->int_ctl &= ~V_IRQ_MASK;
- push_irq(vcpu, control->int_vector);
+ push_irq(&svm->vcpu, control->int_vector);
}
- vcpu->interrupt_window_open =
+ svm->vcpu.interrupt_window_open =
!(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
}
+static void svm_do_inject_vector(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ int word_index = __ffs(vcpu->irq_summary);
+ int bit_index = __ffs(vcpu->irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+ svm_inject_irq(svm, irq);
+}
+
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
- struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb_control_area *control = &svm->vmcb->control;
- vcpu->interrupt_window_open =
+ svm->vcpu.interrupt_window_open =
(!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
- (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
+ (svm->vmcb->save.rflags & X86_EFLAGS_IF));
- if (vcpu->interrupt_window_open && vcpu->irq_summary)
+ if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary)
/*
* If interrupts enabled, and not blocked by sti or mov ss. Good.
*/
- kvm_do_inject_irq(vcpu);
+ svm_do_inject_vector(svm);
/*
* Interrupts blocked. Wait for unblock.
*/
- if (!vcpu->interrupt_window_open &&
- (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
+ if (!svm->vcpu.interrupt_window_open &&
+ (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) {
control->intercept |= 1ULL << INTERCEPT_VINTR;
} else
control->intercept &= ~(1ULL << INTERCEPT_VINTR);
}
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
-{
- kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
- vcpu->irq_summary == 0);
- kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
- kvm_run->cr8 = vcpu->cr8;
- kvm_run->apic_base = vcpu->apic_base;
-}
-
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
-{
- return (!vcpu->irq_summary &&
- kvm_run->request_interrupt_window &&
- vcpu->interrupt_window_open &&
- (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
-}
-
static void save_db_regs(unsigned long *db_regs)
{
asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
@@ -1476,49 +1441,37 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu)
force_new_asid(vcpu);
}
-static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
+{
+}
+
+static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
u16 fs_selector;
u16 gs_selector;
u16 ldt_selector;
- int r;
-
-again:
- r = kvm_mmu_reload(vcpu);
- if (unlikely(r))
- return r;
-
- if (!vcpu->mmio_read_completed)
- do_interrupt_requests(vcpu, kvm_run);
- clgi();
-
- vcpu->guest_mode = 1;
- if (vcpu->requests)
- if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
- svm_flush_tlb(vcpu);
-
- pre_svm_run(vcpu);
+ pre_svm_run(svm);
save_host_msrs(vcpu);
fs_selector = read_fs();
gs_selector = read_gs();
ldt_selector = read_ldt();
- vcpu->svm->host_cr2 = kvm_read_cr2();
- vcpu->svm->host_dr6 = read_dr6();
- vcpu->svm->host_dr7 = read_dr7();
- vcpu->svm->vmcb->save.cr2 = vcpu->cr2;
+ svm->host_cr2 = kvm_read_cr2();
+ svm->host_dr6 = read_dr6();
+ svm->host_dr7 = read_dr7();
+ svm->vmcb->save.cr2 = vcpu->cr2;
- if (vcpu->svm->vmcb->save.dr7 & 0xff) {
+ if (svm->vmcb->save.dr7 & 0xff) {
write_dr7(0);
- save_db_regs(vcpu->svm->host_db_regs);
- load_db_regs(vcpu->svm->db_regs);
+ save_db_regs(svm->host_db_regs);
+ load_db_regs(svm->db_regs);
}
- if (vcpu->fpu_active) {
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
- }
+ clgi();
+
+ local_irq_enable();
asm volatile (
#ifdef CONFIG_X86_64
@@ -1532,34 +1485,33 @@ again:
#endif
#ifdef CONFIG_X86_64
- "mov %c[rbx](%[vcpu]), %%rbx \n\t"
- "mov %c[rcx](%[vcpu]), %%rcx \n\t"
- "mov %c[rdx](%[vcpu]), %%rdx \n\t"
- "mov %c[rsi](%[vcpu]), %%rsi \n\t"
- "mov %c[rdi](%[vcpu]), %%rdi \n\t"
- "mov %c[rbp](%[vcpu]), %%rbp \n\t"
- "mov %c[r8](%[vcpu]), %%r8 \n\t"
- "mov %c[r9](%[vcpu]), %%r9 \n\t"
- "mov %c[r10](%[vcpu]), %%r10 \n\t"
- "mov %c[r11](%[vcpu]), %%r11 \n\t"
- "mov %c[r12](%[vcpu]), %%r12 \n\t"
- "mov %c[r13](%[vcpu]), %%r13 \n\t"
- "mov %c[r14](%[vcpu]), %%r14 \n\t"
- "mov %c[r15](%[vcpu]), %%r15 \n\t"
+ "mov %c[rbx](%[svm]), %%rbx \n\t"
+ "mov %c[rcx](%[svm]), %%rcx \n\t"
+ "mov %c[rdx](%[svm]), %%rdx \n\t"
+ "mov %c[rsi](%[svm]), %%rsi \n\t"
+ "mov %c[rdi](%[svm]), %%rdi \n\t"
+ "mov %c[rbp](%[svm]), %%rbp \n\t"
+ "mov %c[r8](%[svm]), %%r8 \n\t"
+ "mov %c[r9](%[svm]), %%r9 \n\t"
+ "mov %c[r10](%[svm]), %%r10 \n\t"
+ "mov %c[r11](%[svm]), %%r11 \n\t"
+ "mov %c[r12](%[svm]), %%r12 \n\t"
+ "mov %c[r13](%[svm]), %%r13 \n\t"
+ "mov %c[r14](%[svm]), %%r14 \n\t"
+ "mov %c[r15](%[svm]), %%r15 \n\t"
#else
- "mov %c[rbx](%[vcpu]), %%ebx \n\t"
- "mov %c[rcx](%[vcpu]), %%ecx \n\t"
- "mov %c[rdx](%[vcpu]), %%edx \n\t"
- "mov %c[rsi](%[vcpu]), %%esi \n\t"
- "mov %c[rdi](%[vcpu]), %%edi \n\t"
- "mov %c[rbp](%[vcpu]), %%ebp \n\t"
+ "mov %c[rbx](%[svm]), %%ebx \n\t"
+ "mov %c[rcx](%[svm]), %%ecx \n\t"
+ "mov %c[rdx](%[svm]), %%edx \n\t"
+ "mov %c[rsi](%[svm]), %%esi \n\t"
+ "mov %c[rdi](%[svm]), %%edi \n\t"
+ "mov %c[rbp](%[svm]), %%ebp \n\t"
#endif
#ifdef CONFIG_X86_64
/* Enter guest mode */
"push %%rax \n\t"
- "mov %c[svm](%[vcpu]), %%rax \n\t"
- "mov %c[vmcb](%%rax), %%rax \n\t"
+ "mov %c[vmcb](%[svm]), %%rax \n\t"
SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t"
@@ -1567,8 +1519,7 @@ again:
#else
/* Enter guest mode */
"push %%eax \n\t"
- "mov %c[svm](%[vcpu]), %%eax \n\t"
- "mov %c[vmcb](%%eax), %%eax \n\t"
+ "mov %c[vmcb](%[svm]), %%eax \n\t"
SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t"
@@ -1577,73 +1528,69 @@ again:
/* Save guest registers, load host registers */
#ifdef CONFIG_X86_64
- "mov %%rbx, %c[rbx](%[vcpu]) \n\t"
- "mov %%rcx, %c[rcx](%[vcpu]) \n\t"
- "mov %%rdx, %c[rdx](%[vcpu]) \n\t"
- "mov %%rsi, %c[rsi](%[vcpu]) \n\t"
- "mov %%rdi, %c[rdi](%[vcpu]) \n\t"
- "mov %%rbp, %c[rbp](%[vcpu]) \n\t"
- "mov %%r8, %c[r8](%[vcpu]) \n\t"
- "mov %%r9, %c[r9](%[vcpu]) \n\t"
- "mov %%r10, %c[r10](%[vcpu]) \n\t"
- "mov %%r11, %c[r11](%[vcpu]) \n\t"
- "mov %%r12, %c[r12](%[vcpu]) \n\t"
- "mov %%r13, %c[r13](%[vcpu]) \n\t"
- "mov %%r14, %c[r14](%[vcpu]) \n\t"
- "mov %%r15, %c[r15](%[vcpu]) \n\t"
+ "mov %%rbx, %c[rbx](%[svm]) \n\t"
+ "mov %%rcx, %c[rcx](%[svm]) \n\t"
+ "mov %%rdx, %c[rdx](%[svm]) \n\t"
+ "mov %%rsi, %c[rsi](%[svm]) \n\t"
+ "mov %%rdi, %c[rdi](%[svm]) \n\t"
+ "mov %%rbp, %c[rbp](%[svm]) \n\t"
+ "mov %%r8, %c[r8](%[svm]) \n\t"
+ "mov %%r9, %c[r9](%[svm]) \n\t"
+ "mov %%r10, %c[r10](%[svm]) \n\t"
+ "mov %%r11, %c[r11](%[svm]) \n\t"
+ "mov %%r12, %c[r12](%[svm]) \n\t"
+ "mov %%r13, %c[r13](%[svm]) \n\t"
+ "mov %%r14, %c[r14](%[svm]) \n\t"
+ "mov %%r15, %c[r15](%[svm]) \n\t"
"pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
"pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
"pop %%rbp; pop %%rdi; pop %%rsi;"
"pop %%rdx; pop %%rcx; pop %%rbx; \n\t"
#else
- "mov %%ebx, %c[rbx](%[vcpu]) \n\t"
- "mov %%ecx, %c[rcx](%[vcpu]) \n\t"
- "mov %%edx, %c[rdx](%[vcpu]) \n\t"
- "mov %%esi, %c[rsi](%[vcpu]) \n\t"
- "mov %%edi, %c[rdi](%[vcpu]) \n\t"
- "mov %%ebp, %c[rbp](%[vcpu]) \n\t"
+ "mov %%ebx, %c[rbx](%[svm]) \n\t"
+ "mov %%ecx, %c[rcx](%[svm]) \n\t"
+ "mov %%edx, %c[rdx](%[svm]) \n\t"
+ "mov %%esi, %c[rsi](%[svm]) \n\t"
+ "mov %%edi, %c[rdi](%[svm]) \n\t"
+ "mov %%ebp, %c[rbp](%[svm]) \n\t"
"pop %%ebp; pop %%edi; pop %%esi;"
"pop %%edx; pop %%ecx; pop %%ebx; \n\t"
#endif
:
- : [vcpu]"a"(vcpu),
- [svm]"i"(offsetof(struct kvm_vcpu, svm)),
+ : [svm]"a"(svm),
[vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
- [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
- [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
- [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
- [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
- [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
- [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP]))
+ [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])),
+ [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])),
+ [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])),
+ [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])),
+ [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])),
+ [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP]))
#ifdef CONFIG_X86_64
- ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
- [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
- [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
- [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
- [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
- [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
- [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
- [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15]))
+ ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])),
+ [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])),
+ [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])),
+ [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])),
+ [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])),
+ [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])),
+ [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])),
+ [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15]))
#endif
: "cc", "memory" );
- vcpu->guest_mode = 0;
+ local_irq_disable();
- if (vcpu->fpu_active) {
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
- }
+ stgi();
- if ((vcpu->svm->vmcb->save.dr7 & 0xff))
- load_db_regs(vcpu->svm->host_db_regs);
+ if ((svm->vmcb->save.dr7 & 0xff))
+ load_db_regs(svm->host_db_regs);
- vcpu->cr2 = vcpu->svm->vmcb->save.cr2;
+ vcpu->cr2 = svm->vmcb->save.cr2;
- write_dr6(vcpu->svm->host_dr6);
- write_dr7(vcpu->svm->host_dr7);
- kvm_write_cr2(vcpu->svm->host_cr2);
+ write_dr6(svm->host_dr6);
+ write_dr7(svm->host_dr7);
+ kvm_write_cr2(svm->host_cr2);
load_fs(fs_selector);
load_gs(gs_selector);
@@ -1652,57 +1599,19 @@ again:
reload_tss(vcpu);
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING,
- (void *)(unsigned long)vcpu->svm->vmcb->save.rip);
-
- stgi();
-
- kvm_reput_irq(vcpu);
-
- vcpu->svm->next_rip = 0;
-
- if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
- kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
- kvm_run->fail_entry.hardware_entry_failure_reason
- = vcpu->svm->vmcb->control.exit_code;
- post_kvm_run_save(vcpu, kvm_run);
- return 0;
- }
-
- r = handle_exit(vcpu, kvm_run);
- if (r > 0) {
- if (signal_pending(current)) {
- ++vcpu->stat.signal_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
-
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- ++vcpu->stat.request_irq_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
- kvm_resched(vcpu);
- goto again;
- }
- post_kvm_run_save(vcpu, kvm_run);
- return r;
+ svm->next_rip = 0;
}
static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
- vcpu->svm->vmcb->save.cr3 = root;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.cr3 = root;
force_new_asid(vcpu);
if (vcpu->fpu_active) {
- vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
- vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
+ svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
+ svm->vmcb->save.cr0 |= X86_CR0_TS;
vcpu->fpu_active = 0;
}
}
@@ -1711,26 +1620,27 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
unsigned long addr,
uint32_t err_code)
{
- uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ uint32_t exit_int_info = svm->vmcb->control.exit_int_info;
++vcpu->stat.pf_guest;
if (is_page_fault(exit_int_info)) {
- vcpu->svm->vmcb->control.event_inj_err = 0;
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
- SVM_EVTINJ_VALID_ERR |
- SVM_EVTINJ_TYPE_EXEPT |
- DF_VECTOR;
+ svm->vmcb->control.event_inj_err = 0;
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ DF_VECTOR;
return;
}
vcpu->cr2 = addr;
- vcpu->svm->vmcb->save.cr2 = addr;
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
- SVM_EVTINJ_VALID_ERR |
- SVM_EVTINJ_TYPE_EXEPT |
- PF_VECTOR;
- vcpu->svm->vmcb->control.event_inj_err = err_code;
+ svm->vmcb->save.cr2 = addr;
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ PF_VECTOR;
+ svm->vmcb->control.event_inj_err = err_code;
}
@@ -1757,17 +1667,25 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[3] = 0xc3;
}
-static struct kvm_arch_ops svm_arch_ops = {
+static void svm_check_processor_compat(void *rtn)
+{
+ *(int *)rtn = 0;
+}
+
+static struct kvm_x86_ops svm_x86_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
.hardware_setup = svm_hardware_setup,
.hardware_unsetup = svm_hardware_unsetup,
+ .check_processor_compatibility = svm_check_processor_compat,
.hardware_enable = svm_hardware_enable,
.hardware_disable = svm_hardware_disable,
.vcpu_create = svm_create_vcpu,
.vcpu_free = svm_free_vcpu,
+ .vcpu_reset = svm_vcpu_reset,
+ .prepare_guest_switch = svm_prepare_guest_switch,
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
.vcpu_decache = svm_vcpu_decache,
@@ -1778,7 +1696,7 @@ static struct kvm_arch_ops svm_arch_ops = {
.get_segment_base = svm_get_segment_base,
.get_segment = svm_get_segment,
.set_segment = svm_set_segment,
- .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+ .get_cs_db_l_bits = kvm_get_cs_db_l_bits,
.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
.set_cr0 = svm_set_cr0,
.set_cr3 = svm_set_cr3,
@@ -1795,26 +1713,30 @@ static struct kvm_arch_ops svm_arch_ops = {
.get_rflags = svm_get_rflags,
.set_rflags = svm_set_rflags,
- .invlpg = svm_invlpg,
.tlb_flush = svm_flush_tlb,
.inject_page_fault = svm_inject_page_fault,
.inject_gp = svm_inject_gp,
.run = svm_vcpu_run,
+ .handle_exit = handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = svm_vcpu_setup,
.patch_hypercall = svm_patch_hypercall,
+ .get_irq = svm_get_irq,
+ .set_irq = svm_set_irq,
+ .inject_pending_irq = svm_intr_assist,
+ .inject_pending_vectors = do_interrupt_requests,
};
static int __init svm_init(void)
{
- return kvm_init_arch(&svm_arch_ops, THIS_MODULE);
+ return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm),
+ THIS_MODULE);
}
static void __exit svm_exit(void)
{
- kvm_exit_arch();
+ kvm_exit_x86();
}
module_init(svm_init)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 80628f69916..4f115a8e45e 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -16,6 +16,8 @@
*/
#include "kvm.h"
+#include "x86_emulate.h"
+#include "irq.h"
#include "vmx.h"
#include "segment_descriptor.h"
@@ -23,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/highmem.h>
-#include <linux/profile.h>
#include <linux/sched.h>
#include <asm/io.h>
@@ -32,6 +33,39 @@
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
+struct vmcs {
+ u32 revision_id;
+ u32 abort;
+ char data[0];
+};
+
+struct vcpu_vmx {
+ struct kvm_vcpu vcpu;
+ int launched;
+ u8 fail;
+ struct kvm_msr_entry *guest_msrs;
+ struct kvm_msr_entry *host_msrs;
+ int nmsrs;
+ int save_nmsrs;
+ int msr_offset_efer;
+#ifdef CONFIG_X86_64
+ int msr_offset_kernel_gs_base;
+#endif
+ struct vmcs *vmcs;
+ struct {
+ int loaded;
+ u16 fs_sel, gs_sel, ldt_sel;
+ int gs_ldt_reload_needed;
+ int fs_reload_needed;
+ }host_state;
+
+};
+
+static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
+{
+ return container_of(vcpu, struct vcpu_vmx, vcpu);
+}
+
static int init_rmode_tss(struct kvm *kvm);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
@@ -40,18 +74,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
static struct page *vmx_io_bitmap_a;
static struct page *vmx_io_bitmap_b;
-#ifdef CONFIG_X86_64
-#define HOST_IS_64 1
-#else
-#define HOST_IS_64 0
-#endif
#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
-static struct vmcs_descriptor {
+static struct vmcs_config {
int size;
int order;
u32 revision_id;
-} vmcs_descriptor;
+ u32 pin_based_exec_ctrl;
+ u32 cpu_based_exec_ctrl;
+ u32 vmexit_ctrl;
+ u32 vmentry_ctrl;
+} vmcs_config;
#define VMX_SEGMENT_FIELD(seg) \
[VCPU_SREG_##seg] = { \
@@ -89,16 +122,32 @@ static const u32 vmx_msr_index[] = {
};
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
-static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
+static void load_msrs(struct kvm_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ wrmsrl(e[i].index, e[i].data);
+}
+
+static void save_msrs(struct kvm_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ rdmsrl(e[i].index, e[i].data);
+}
+
+static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr)
{
return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
}
-static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
+static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx)
{
- int efer_offset = vcpu->msr_offset_efer;
- return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
- msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
+ int efer_offset = vmx->msr_offset_efer;
+ return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) !=
+ msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
}
static inline int is_page_fault(u32 intr_info)
@@ -121,23 +170,33 @@ static inline int is_external_interrupt(u32 intr_info)
== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
-static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr)
+static inline int cpu_has_vmx_tpr_shadow(void)
+{
+ return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
+}
+
+static inline int vm_need_tpr_shadow(struct kvm *kvm)
+{
+ return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
+}
+
+static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
{
int i;
- for (i = 0; i < vcpu->nmsrs; ++i)
- if (vcpu->guest_msrs[i].index == msr)
+ for (i = 0; i < vmx->nmsrs; ++i)
+ if (vmx->guest_msrs[i].index == msr)
return i;
return -1;
}
-static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
{
int i;
- i = __find_msr_index(vcpu, msr);
+ i = __find_msr_index(vmx, msr);
if (i >= 0)
- return &vcpu->guest_msrs[i];
+ return &vmx->guest_msrs[i];
return NULL;
}
@@ -156,23 +215,24 @@ static void vmcs_clear(struct vmcs *vmcs)
static void __vcpu_clear(void *arg)
{
- struct kvm_vcpu *vcpu = arg;
+ struct vcpu_vmx *vmx = arg;
int cpu = raw_smp_processor_id();
- if (vcpu->cpu == cpu)
- vmcs_clear(vcpu->vmcs);
- if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
+ if (vmx->vcpu.cpu == cpu)
+ vmcs_clear(vmx->vmcs);
+ if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
per_cpu(current_vmcs, cpu) = NULL;
- rdtscll(vcpu->host_tsc);
+ rdtscll(vmx->vcpu.host_tsc);
}
-static void vcpu_clear(struct kvm_vcpu *vcpu)
+static void vcpu_clear(struct vcpu_vmx *vmx)
{
- if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1)
- smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1);
+ if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1)
+ smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear,
+ vmx, 0, 1);
else
- __vcpu_clear(vcpu);
- vcpu->launched = 0;
+ __vcpu_clear(vmx);
+ vmx->launched = 0;
}
static unsigned long vmcs_readl(unsigned long field)
@@ -282,121 +342,122 @@ static void reload_tss(void)
#endif
}
-static void load_transition_efer(struct kvm_vcpu *vcpu)
+static void load_transition_efer(struct vcpu_vmx *vmx)
{
u64 trans_efer;
- int efer_offset = vcpu->msr_offset_efer;
+ int efer_offset = vmx->msr_offset_efer;
- trans_efer = vcpu->host_msrs[efer_offset].data;
+ trans_efer = vmx->host_msrs[efer_offset].data;
trans_efer &= ~EFER_SAVE_RESTORE_BITS;
- trans_efer |= msr_efer_save_restore_bits(
- vcpu->guest_msrs[efer_offset]);
+ trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
wrmsrl(MSR_EFER, trans_efer);
- vcpu->stat.efer_reload++;
+ vmx->vcpu.stat.efer_reload++;
}
static void vmx_save_host_state(struct kvm_vcpu *vcpu)
{
- struct vmx_host_state *hs = &vcpu->vmx_host_state;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (hs->loaded)
+ if (vmx->host_state.loaded)
return;
- hs->loaded = 1;
+ vmx->host_state.loaded = 1;
/*
* Set host fs and gs selectors. Unfortunately, 22.2.3 does not
* allow segment selectors with cpl > 0 or ti == 1.
*/
- hs->ldt_sel = read_ldt();
- hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
- hs->fs_sel = read_fs();
- if (!(hs->fs_sel & 7))
- vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
- else {
+ vmx->host_state.ldt_sel = read_ldt();
+ vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
+ vmx->host_state.fs_sel = read_fs();
+ if (!(vmx->host_state.fs_sel & 7)) {
+ vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
+ vmx->host_state.fs_reload_needed = 0;
+ } else {
vmcs_write16(HOST_FS_SELECTOR, 0);
- hs->fs_gs_ldt_reload_needed = 1;
+ vmx->host_state.fs_reload_needed = 1;
}
- hs->gs_sel = read_gs();
- if (!(hs->gs_sel & 7))
- vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
+ vmx->host_state.gs_sel = read_gs();
+ if (!(vmx->host_state.gs_sel & 7))
+ vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
else {
vmcs_write16(HOST_GS_SELECTOR, 0);
- hs->fs_gs_ldt_reload_needed = 1;
+ vmx->host_state.gs_ldt_reload_needed = 1;
}
#ifdef CONFIG_X86_64
vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
#else
- vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
- vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
+ vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel));
+ vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel));
#endif
#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
- save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1);
+ if (is_long_mode(&vmx->vcpu)) {
+ save_msrs(vmx->host_msrs +
+ vmx->msr_offset_kernel_gs_base, 1);
}
#endif
- load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
- if (msr_efer_need_save_restore(vcpu))
- load_transition_efer(vcpu);
+ load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+ if (msr_efer_need_save_restore(vmx))
+ load_transition_efer(vmx);
}
-static void vmx_load_host_state(struct kvm_vcpu *vcpu)
+static void vmx_load_host_state(struct vcpu_vmx *vmx)
{
- struct vmx_host_state *hs = &vcpu->vmx_host_state;
+ unsigned long flags;
- if (!hs->loaded)
+ if (!vmx->host_state.loaded)
return;
- hs->loaded = 0;
- if (hs->fs_gs_ldt_reload_needed) {
- load_ldt(hs->ldt_sel);
- load_fs(hs->fs_sel);
+ vmx->host_state.loaded = 0;
+ if (vmx->host_state.fs_reload_needed)
+ load_fs(vmx->host_state.fs_sel);
+ if (vmx->host_state.gs_ldt_reload_needed) {
+ load_ldt(vmx->host_state.ldt_sel);
/*
* If we have to reload gs, we must take care to
* preserve our gs base.
*/
- local_irq_disable();
- load_gs(hs->gs_sel);
+ local_irq_save(flags);
+ load_gs(vmx->host_state.gs_sel);
#ifdef CONFIG_X86_64
wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
#endif
- local_irq_enable();
-
- reload_tss();
+ local_irq_restore(flags);
}
- save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
- load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
- if (msr_efer_need_save_restore(vcpu))
- load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
+ reload_tss();
+ save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+ load_msrs(vmx->host_msrs, vmx->save_nmsrs);
+ if (msr_efer_need_save_restore(vmx))
+ load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
}
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
*/
-static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
- u64 phys_addr = __pa(vcpu->vmcs);
- int cpu;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ u64 phys_addr = __pa(vmx->vmcs);
u64 tsc_this, delta;
- cpu = get_cpu();
-
- if (vcpu->cpu != cpu)
- vcpu_clear(vcpu);
+ if (vcpu->cpu != cpu) {
+ vcpu_clear(vmx);
+ kvm_migrate_apic_timer(vcpu);
+ }
- if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+ if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
u8 error;
- per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+ per_cpu(current_vmcs, cpu) = vmx->vmcs;
asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
: "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
: "cc");
if (error)
printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
- vcpu->vmcs, phys_addr);
+ vmx->vmcs, phys_addr);
}
if (vcpu->cpu != cpu) {
@@ -426,9 +487,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
{
- vmx_load_host_state(vcpu);
+ vmx_load_host_state(to_vmx(vcpu));
kvm_put_guest_fpu(vcpu);
- put_cpu();
}
static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -436,9 +496,9 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
if (vcpu->fpu_active)
return;
vcpu->fpu_active = 1;
- vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
- if (vcpu->cr0 & CR0_TS_MASK)
- vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ vmcs_clear_bits(GUEST_CR0, X86_CR0_TS);
+ if (vcpu->cr0 & X86_CR0_TS)
+ vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
update_exception_bitmap(vcpu);
}
@@ -447,13 +507,13 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
if (!vcpu->fpu_active)
return;
vcpu->fpu_active = 0;
- vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
update_exception_bitmap(vcpu);
}
static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
{
- vcpu_clear(vcpu);
+ vcpu_clear(to_vmx(vcpu));
}
static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
@@ -501,59 +561,62 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
/*
* Swap MSR entry in host/guest MSR entry array.
*/
-void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
+#ifdef CONFIG_X86_64
+static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
{
- struct vmx_msr_entry tmp;
- tmp = vcpu->guest_msrs[to];
- vcpu->guest_msrs[to] = vcpu->guest_msrs[from];
- vcpu->guest_msrs[from] = tmp;
- tmp = vcpu->host_msrs[to];
- vcpu->host_msrs[to] = vcpu->host_msrs[from];
- vcpu->host_msrs[from] = tmp;
+ struct kvm_msr_entry tmp;
+
+ tmp = vmx->guest_msrs[to];
+ vmx->guest_msrs[to] = vmx->guest_msrs[from];
+ vmx->guest_msrs[from] = tmp;
+ tmp = vmx->host_msrs[to];
+ vmx->host_msrs[to] = vmx->host_msrs[from];
+ vmx->host_msrs[from] = tmp;
}
+#endif
/*
* Set up the vmcs to automatically save and restore system
* msrs. Don't touch the 64-bit msrs if the guest is in legacy
* mode, as fiddling with msrs is very expensive.
*/
-static void setup_msrs(struct kvm_vcpu *vcpu)
+static void setup_msrs(struct vcpu_vmx *vmx)
{
int save_nmsrs;
save_nmsrs = 0;
#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
+ if (is_long_mode(&vmx->vcpu)) {
int index;
- index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
+ index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_LSTAR);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_LSTAR);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_CSTAR);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_CSTAR);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
+ move_msr_up(vmx, index, save_nmsrs++);
/*
* MSR_K6_STAR is only needed on long mode guests, and only
* if efer.sce is enabled.
*/
- index = __find_msr_index(vcpu, MSR_K6_STAR);
- if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE))
- move_msr_up(vcpu, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_K6_STAR);
+ if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE))
+ move_msr_up(vmx, index, save_nmsrs++);
}
#endif
- vcpu->save_nmsrs = save_nmsrs;
+ vmx->save_nmsrs = save_nmsrs;
#ifdef CONFIG_X86_64
- vcpu->msr_offset_kernel_gs_base =
- __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+ vmx->msr_offset_kernel_gs_base =
+ __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
#endif
- vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
+ vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
}
/*
@@ -589,7 +652,7 @@ static void guest_write_tsc(u64 guest_tsc)
static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
u64 data;
- struct vmx_msr_entry *msr;
+ struct kvm_msr_entry *msr;
if (!pdata) {
printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
@@ -620,7 +683,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
default:
- msr = find_msr_entry(vcpu, msr_index);
+ msr = find_msr_entry(to_vmx(vcpu), msr_index);
if (msr) {
data = msr->data;
break;
@@ -639,15 +702,16 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
*/
static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
- struct vmx_msr_entry *msr;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct kvm_msr_entry *msr;
int ret = 0;
switch (msr_index) {
#ifdef CONFIG_X86_64
case MSR_EFER:
ret = kvm_set_msr_common(vcpu, msr_index, data);
- if (vcpu->vmx_host_state.loaded)
- load_transition_efer(vcpu);
+ if (vmx->host_state.loaded)
+ load_transition_efer(vmx);
break;
case MSR_FS_BASE:
vmcs_writel(GUEST_FS_BASE, data);
@@ -669,11 +733,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
guest_write_tsc(data);
break;
default:
- msr = find_msr_entry(vcpu, msr_index);
+ msr = find_msr_entry(vmx, msr_index);
if (msr) {
msr->data = data;
- if (vcpu->vmx_host_state.loaded)
- load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+ if (vmx->host_state.loaded)
+ load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
break;
}
ret = kvm_set_msr_common(vcpu, msr_index, data);
@@ -740,6 +804,20 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
return 0;
}
+static int vmx_get_irq(struct kvm_vcpu *vcpu)
+{
+ u32 idtv_info_field;
+
+ idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ if (is_external_interrupt(idtv_info_field))
+ return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
+ else
+ printk("pending exception: not handled yet\n");
+ }
+ return -1;
+}
+
static __init int cpu_has_kvm_support(void)
{
unsigned long ecx = cpuid_ecx(1);
@@ -751,7 +829,10 @@ static __init int vmx_disabled_by_bios(void)
u64 msr;
rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
- return (msr & 5) == 1; /* locked but not enabled */
+ return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+ == MSR_IA32_FEATURE_CONTROL_LOCKED;
+ /* locked but not enabled */
}
static void hardware_enable(void *garbage)
@@ -761,10 +842,15 @@ static void hardware_enable(void *garbage)
u64 old;
rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
- if ((old & 5) != 5)
+ if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+ != (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
/* enable and lock */
- wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
- write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+ wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
+ MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED);
+ write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
: "memory", "cc");
}
@@ -774,14 +860,102 @@ static void hardware_disable(void *garbage)
asm volatile (ASM_VMX_VMXOFF : : : "cc");
}
-static __init void setup_vmcs_descriptor(void)
+static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
+ u32 msr, u32* result)
+{
+ u32 vmx_msr_low, vmx_msr_high;
+ u32 ctl = ctl_min | ctl_opt;
+
+ rdmsr(msr, vmx_msr_low, vmx_msr_high);
+
+ ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
+ ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */
+
+ /* Ensure minimum (required) set of control bits are supported. */
+ if (ctl_min & ~ctl)
+ return -EIO;
+
+ *result = ctl;
+ return 0;
+}
+
+static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
{
u32 vmx_msr_low, vmx_msr_high;
+ u32 min, opt;
+ u32 _pin_based_exec_control = 0;
+ u32 _cpu_based_exec_control = 0;
+ u32 _vmexit_control = 0;
+ u32 _vmentry_control = 0;
+
+ min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
+ opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
+ &_pin_based_exec_control) < 0)
+ return -EIO;
+
+ min = CPU_BASED_HLT_EXITING |
+#ifdef CONFIG_X86_64
+ CPU_BASED_CR8_LOAD_EXITING |
+ CPU_BASED_CR8_STORE_EXITING |
+#endif
+ CPU_BASED_USE_IO_BITMAPS |
+ CPU_BASED_MOV_DR_EXITING |
+ CPU_BASED_USE_TSC_OFFSETING;
+#ifdef CONFIG_X86_64
+ opt = CPU_BASED_TPR_SHADOW;
+#else
+ opt = 0;
+#endif
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
+ &_cpu_based_exec_control) < 0)
+ return -EIO;
+#ifdef CONFIG_X86_64
+ if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
+ _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
+ ~CPU_BASED_CR8_STORE_EXITING;
+#endif
+
+ min = 0;
+#ifdef CONFIG_X86_64
+ min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
+#endif
+ opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
+ &_vmexit_control) < 0)
+ return -EIO;
+
+ min = opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
+ &_vmentry_control) < 0)
+ return -EIO;
rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
- vmcs_descriptor.size = vmx_msr_high & 0x1fff;
- vmcs_descriptor.order = get_order(vmcs_descriptor.size);
- vmcs_descriptor.revision_id = vmx_msr_low;
+
+ /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
+ if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
+ return -EIO;
+
+#ifdef CONFIG_X86_64
+ /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
+ if (vmx_msr_high & (1u<<16))
+ return -EIO;
+#endif
+
+ /* Require Write-Back (WB) memory type for VMCS accesses. */
+ if (((vmx_msr_high >> 18) & 15) != 6)
+ return -EIO;
+
+ vmcs_conf->size = vmx_msr_high & 0x1fff;
+ vmcs_conf->order = get_order(vmcs_config.size);
+ vmcs_conf->revision_id = vmx_msr_low;
+
+ vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
+ vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
+ vmcs_conf->vmexit_ctrl = _vmexit_control;
+ vmcs_conf->vmentry_ctrl = _vmentry_control;
+
+ return 0;
}
static struct vmcs *alloc_vmcs_cpu(int cpu)
@@ -790,12 +964,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu)
struct page *pages;
struct vmcs *vmcs;
- pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order);
+ pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order);
if (!pages)
return NULL;
vmcs = page_address(pages);
- memset(vmcs, 0, vmcs_descriptor.size);
- vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */
+ memset(vmcs, 0, vmcs_config.size);
+ vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */
return vmcs;
}
@@ -806,7 +980,7 @@ static struct vmcs *alloc_vmcs(void)
static void free_vmcs(struct vmcs *vmcs)
{
- free_pages((unsigned long)vmcs, vmcs_descriptor.order);
+ free_pages((unsigned long)vmcs, vmcs_config.order);
}
static void free_kvm_area(void)
@@ -817,8 +991,6 @@ static void free_kvm_area(void)
free_vmcs(per_cpu(vmxarea, cpu));
}
-extern struct vmcs *alloc_vmcs_cpu(int cpu);
-
static __init int alloc_kvm_area(void)
{
int cpu;
@@ -839,7 +1011,8 @@ static __init int alloc_kvm_area(void)
static __init int hardware_setup(void)
{
- setup_vmcs_descriptor();
+ if (setup_vmcs_config(&vmcs_config) < 0)
+ return -EIO;
return alloc_kvm_area();
}
@@ -879,8 +1052,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
vmcs_writel(GUEST_RFLAGS, flags);
- vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) |
- (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK));
+ vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
+ (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME));
update_exception_bitmap(vcpu);
@@ -897,7 +1070,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
}
-static int rmode_tss_base(struct kvm* kvm)
+static gva_t rmode_tss_base(struct kvm* kvm)
{
gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
return base_gfn << PAGE_SHIFT;
@@ -937,7 +1110,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
flags |= IOPL_MASK | X86_EFLAGS_VM;
vmcs_writel(GUEST_RFLAGS, flags);
- vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK);
+ vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
update_exception_bitmap(vcpu);
vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
@@ -975,10 +1148,10 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
vcpu->shadow_efer |= EFER_LMA;
- find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME;
+ find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME;
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS)
- | VM_ENTRY_CONTROLS_IA32E_MASK);
+ | VM_ENTRY_IA32E_MODE);
}
static void exit_lmode(struct kvm_vcpu *vcpu)
@@ -987,7 +1160,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS)
- & ~VM_ENTRY_CONTROLS_IA32E_MASK);
+ & ~VM_ENTRY_IA32E_MODE);
}
#endif
@@ -1002,17 +1175,17 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
vmx_fpu_deactivate(vcpu);
- if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
+ if (vcpu->rmode.active && (cr0 & X86_CR0_PE))
enter_pmode(vcpu);
- if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+ if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE))
enter_rmode(vcpu);
#ifdef CONFIG_X86_64
if (vcpu->shadow_efer & EFER_LME) {
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG))
enter_lmode(vcpu);
- if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
+ if (is_paging(vcpu) && !(cr0 & X86_CR0_PG))
exit_lmode(vcpu);
}
#endif
@@ -1022,14 +1195,14 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
(cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
vcpu->cr0 = cr0;
- if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK))
+ if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE))
vmx_fpu_activate(vcpu);
}
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
vmcs_writel(GUEST_CR3, cr3);
- if (vcpu->cr0 & CR0_PE_MASK)
+ if (vcpu->cr0 & X86_CR0_PE)
vmx_fpu_deactivate(vcpu);
}
@@ -1045,23 +1218,24 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
- struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
vcpu->shadow_efer = efer;
if (efer & EFER_LMA) {
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS) |
- VM_ENTRY_CONTROLS_IA32E_MASK);
+ VM_ENTRY_IA32E_MODE);
msr->data = efer;
} else {
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS) &
- ~VM_ENTRY_CONTROLS_IA32E_MASK);
+ ~VM_ENTRY_IA32E_MODE);
msr->data = efer & ~EFER_LME;
}
- setup_msrs(vcpu);
+ setup_msrs(vmx);
}
#endif
@@ -1210,17 +1384,6 @@ static int init_rmode_tss(struct kvm* kvm)
return 1;
}
-static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val)
-{
- u32 msr_high, msr_low;
-
- rdmsr(msr, msr_low, msr_high);
-
- val &= msr_high;
- val |= msr_low;
- vmcs_write32(vmcs_field, val);
-}
-
static void seg_setup(int seg)
{
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -1234,7 +1397,7 @@ static void seg_setup(int seg)
/*
* Sets up the vmcs for emulated real mode.
*/
-static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
+static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
{
u32 host_sysenter_cs;
u32 junk;
@@ -1243,27 +1406,36 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
int i;
int ret = 0;
unsigned long kvm_vmx_return;
+ u64 msr;
+ u32 exec_control;
- if (!init_rmode_tss(vcpu->kvm)) {
+ if (!init_rmode_tss(vmx->vcpu.kvm)) {
ret = -ENOMEM;
goto out;
}
- memset(vcpu->regs, 0, sizeof(vcpu->regs));
- vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
- vcpu->cr8 = 0;
- vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (vcpu == &vcpu->kvm->vcpus[0])
- vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ vmx->vcpu.rmode.active = 0;
- fx_init(vcpu);
+ vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
+ set_cr8(&vmx->vcpu, 0);
+ msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (vmx->vcpu.vcpu_id == 0)
+ msr |= MSR_IA32_APICBASE_BSP;
+ kvm_set_apic_base(&vmx->vcpu, msr);
+
+ fx_init(&vmx->vcpu);
/*
* GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
* insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh.
*/
- vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
- vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+ if (vmx->vcpu.vcpu_id == 0) {
+ vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+ vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+ } else {
+ vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8);
+ vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12);
+ }
vmcs_write32(GUEST_CS_LIMIT, 0xffff);
vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
@@ -1288,7 +1460,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_SYSENTER_EIP, 0);
vmcs_writel(GUEST_RFLAGS, 0x02);
- vmcs_writel(GUEST_RIP, 0xfff0);
+ if (vmx->vcpu.vcpu_id == 0)
+ vmcs_writel(GUEST_RIP, 0xfff0);
+ else
+ vmcs_writel(GUEST_RIP, 0);
vmcs_writel(GUEST_RSP, 0);
//todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
@@ -1316,20 +1491,18 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
/* Control */
- vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS,
- PIN_BASED_VM_EXEC_CONTROL,
- PIN_BASED_EXT_INTR_MASK /* 20.6.1 */
- | PIN_BASED_NMI_EXITING /* 20.6.1 */
- );
- vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS,
- CPU_BASED_VM_EXEC_CONTROL,
- CPU_BASED_HLT_EXITING /* 20.6.2 */
- | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */
- | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */
- | CPU_BASED_ACTIVATE_IO_BITMAP /* 20.6.2 */
- | CPU_BASED_MOV_DR_EXITING
- | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */
- );
+ vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
+ vmcs_config.pin_based_exec_ctrl);
+
+ exec_control = vmcs_config.cpu_based_exec_ctrl;
+ if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
+ exec_control &= ~CPU_BASED_TPR_SHADOW;
+#ifdef CONFIG_X86_64
+ exec_control |= CPU_BASED_CR8_STORE_EXITING |
+ CPU_BASED_CR8_LOAD_EXITING;
+#endif
+ }
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
@@ -1377,46 +1550,48 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
u32 index = vmx_msr_index[i];
u32 data_low, data_high;
u64 data;
- int j = vcpu->nmsrs;
+ int j = vmx->nmsrs;
if (rdmsr_safe(index, &data_low, &data_high) < 0)
continue;
if (wrmsr_safe(index, data_low, data_high) < 0)
continue;
data = data_low | ((u64)data_high << 32);
- vcpu->host_msrs[j].index = index;
- vcpu->host_msrs[j].reserved = 0;
- vcpu->host_msrs[j].data = data;
- vcpu->guest_msrs[j] = vcpu->host_msrs[j];
- ++vcpu->nmsrs;
+ vmx->host_msrs[j].index = index;
+ vmx->host_msrs[j].reserved = 0;
+ vmx->host_msrs[j].data = data;
+ vmx->guest_msrs[j] = vmx->host_msrs[j];
+ ++vmx->nmsrs;
}
- setup_msrs(vcpu);
+ setup_msrs(vmx);
- vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
- (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */
+ vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
/* 22.2.1, 20.8.1 */
- vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
- VM_ENTRY_CONTROLS, 0);
+ vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
+
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
#ifdef CONFIG_X86_64
- vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
- vmcs_writel(TPR_THRESHOLD, 0);
+ vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
+ if (vm_need_tpr_shadow(vmx->vcpu.kvm))
+ vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
+ page_to_phys(vmx->vcpu.apic->regs_page));
+ vmcs_write32(TPR_THRESHOLD, 0);
#endif
vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
- vcpu->cr0 = 0x60000010;
- vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
- vmx_set_cr4(vcpu, 0);
+ vmx->vcpu.cr0 = 0x60000010;
+ vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode
+ vmx_set_cr4(&vmx->vcpu, 0);
#ifdef CONFIG_X86_64
- vmx_set_efer(vcpu, 0);
+ vmx_set_efer(&vmx->vcpu, 0);
#endif
- vmx_fpu_activate(vcpu);
- update_exception_bitmap(vcpu);
+ vmx_fpu_activate(&vmx->vcpu);
+ update_exception_bitmap(&vmx->vcpu);
return 0;
@@ -1424,6 +1599,13 @@ out:
return ret;
}
+static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ vmx_vcpu_setup(vmx);
+}
+
static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
{
u16 ent[2];
@@ -1443,8 +1625,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
return;
}
- if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) !=
- sizeof(ent)) {
+ if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) !=
+ X86EMUL_CONTINUE) {
vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
return;
}
@@ -1454,9 +1636,9 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
ip = vmcs_readl(GUEST_RIP);
- if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 ||
- kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 ||
- kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) {
+ if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE ||
+ emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE ||
+ emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) {
vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
return;
}
@@ -1469,6 +1651,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
}
+static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
+{
+ if (vcpu->rmode.active) {
+ inject_rmode_irq(vcpu, irq);
+ return;
+ }
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
{
int word_index = __ffs(vcpu->irq_summary);
@@ -1478,13 +1670,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
clear_bit(bit_index, &vcpu->irq_pending[word_index]);
if (!vcpu->irq_pending[word_index])
clear_bit(word_index, &vcpu->irq_summary);
-
- if (vcpu->rmode.active) {
- inject_rmode_irq(vcpu, irq);
- return;
- }
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
- irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+ vmx_inject_irq(vcpu, irq);
}
@@ -1568,7 +1754,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
"intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
}
- if (is_external_interrupt(vect_info)) {
+ if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
set_bit(irq, vcpu->irq_pending);
set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
@@ -1591,29 +1777,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (is_page_fault(intr_info)) {
cr2 = vmcs_readl(EXIT_QUALIFICATION);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
r = kvm_mmu_page_fault(vcpu, cr2, error_code);
if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return r;
}
if (!r) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return 1;
}
er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
switch (er) {
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
++vcpu->stat.mmio_exits;
- kvm_run->exit_reason = KVM_EXIT_MMIO;
return 0;
case EMULATE_FAIL:
- vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ kvm_report_emulation_failure(vcpu, "pagetable");
break;
default:
BUG();
@@ -1653,80 +1838,29 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count)
-{
- u64 inst;
- gva_t rip;
- int countr_size;
- int i, n;
-
- if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) {
- countr_size = 2;
- } else {
- u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
-
- countr_size = (cs_ar & AR_L_MASK) ? 8:
- (cs_ar & AR_DB_MASK) ? 4: 2;
- }
-
- rip = vmcs_readl(GUEST_RIP);
- if (countr_size != 8)
- rip += vmcs_readl(GUEST_CS_BASE);
-
- n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst);
-
- for (i = 0; i < n; i++) {
- switch (((u8*)&inst)[i]) {
- case 0xf0:
- case 0xf2:
- case 0xf3:
- case 0x2e:
- case 0x36:
- case 0x3e:
- case 0x26:
- case 0x64:
- case 0x65:
- case 0x66:
- break;
- case 0x67:
- countr_size = (countr_size == 2) ? 4: (countr_size >> 1);
- default:
- goto done;
- }
- }
- return 0;
-done:
- countr_size *= 8;
- *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
- //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]);
- return 1;
-}
-
static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
int size, down, in, string, rep;
unsigned port;
- unsigned long count;
- gva_t address;
++vcpu->stat.io_exits;
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
- in = (exit_qualification & 8) != 0;
- size = (exit_qualification & 7) + 1;
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
string = (exit_qualification & 16) != 0;
+
+ if (string) {
+ if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+ return 0;
+ return 1;
+ }
+
+ size = (exit_qualification & 7) + 1;
+ in = (exit_qualification & 8) != 0;
down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
- count = 1;
rep = (exit_qualification & 32) != 0;
port = exit_qualification >> 16;
- address = 0;
- if (string) {
- if (rep && !get_io_count(vcpu, &count))
- return 1;
- address = vmcs_readl(GUEST_LINEAR_ADDRESS);
- }
- return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
- address, rep, port);
+
+ return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
}
static void
@@ -1743,11 +1877,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
int cr;
int reg;
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
cr = exit_qualification & 15;
reg = (exit_qualification >> 8) & 15;
switch ((exit_qualification >> 4) & 3) {
@@ -1772,13 +1906,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load_rsp_rip(vcpu);
set_cr8(vcpu, vcpu->regs[reg]);
skip_emulated_instruction(vcpu);
- return 1;
+ kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+ return 0;
};
break;
case 2: /* clts */
vcpu_load_rsp_rip(vcpu);
vmx_fpu_deactivate(vcpu);
- vcpu->cr0 &= ~CR0_TS_MASK;
+ vcpu->cr0 &= ~X86_CR0_TS;
vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
vmx_fpu_activate(vcpu);
skip_emulated_instruction(vcpu);
@@ -1793,7 +1928,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
case 8:
vcpu_load_rsp_rip(vcpu);
- vcpu->regs[reg] = vcpu->cr8;
+ vcpu->regs[reg] = get_cr8(vcpu);
vcpu_put_rsp_rip(vcpu);
skip_emulated_instruction(vcpu);
return 1;
@@ -1808,14 +1943,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
break;
}
kvm_run->exit_reason = 0;
- printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n",
+ pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
(int)(exit_qualification >> 4) & 3, cr);
return 0;
}
static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
unsigned long val;
int dr, reg;
@@ -1823,7 +1958,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
* FIXME: this code assumes the host is debugging the guest.
* need to deal with guest debugging itself too.
*/
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
dr = exit_qualification & 7;
reg = (exit_qualification >> 8) & 15;
vcpu_load_rsp_rip(vcpu);
@@ -1886,19 +2021,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
{
- kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
- kvm_run->cr8 = vcpu->cr8;
- kvm_run->apic_base = vcpu->apic_base;
- kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
- vcpu->irq_summary == 0);
+ return 1;
}
static int handle_interrupt_window(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
+ u32 cpu_based_vm_exec_control;
+
+ /* clear pending irq */
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
@@ -1943,6 +2080,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
[EXIT_REASON_HLT] = handle_halt,
[EXIT_REASON_VMCALL] = handle_vmcall,
+ [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold
};
static const int kvm_vmx_max_exit_handlers =
@@ -1956,6 +2094,14 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (unlikely(vmx->fail)) {
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = vmcs_read32(VM_INSTRUCTION_ERROR);
+ return 0;
+ }
if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
exit_reason != EXIT_REASON_EXCEPTION_NMI )
@@ -1971,57 +2117,91 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
return 0;
}
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
{
- return (!vcpu->irq_summary &&
- kvm_run->request_interrupt_window &&
- vcpu->interrupt_window_open &&
- (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
}
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+static void update_tpr_threshold(struct kvm_vcpu *vcpu)
{
+ int max_irr, tpr;
+
+ if (!vm_need_tpr_shadow(vcpu->kvm))
+ return;
+
+ if (!kvm_lapic_enabled(vcpu) ||
+ ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
+ vmcs_write32(TPR_THRESHOLD, 0);
+ return;
+ }
+
+ tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
+ vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
}
-static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
- u8 fail;
- int r;
+ u32 cpu_based_vm_exec_control;
-preempted:
- if (vcpu->guest_debug.enabled)
- kvm_guest_debug_pre(vcpu);
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
-again:
- if (!vcpu->mmio_read_completed)
- do_interrupt_requests(vcpu, kvm_run);
+static void vmx_intr_assist(struct kvm_vcpu *vcpu)
+{
+ u32 idtv_info_field, intr_info_field;
+ int has_ext_irq, interrupt_window_open;
+ int vector;
- vmx_save_host_state(vcpu);
- kvm_load_guest_fpu(vcpu);
+ kvm_inject_pending_timer_irqs(vcpu);
+ update_tpr_threshold(vcpu);
- r = kvm_mmu_reload(vcpu);
- if (unlikely(r))
- goto out;
+ has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+ intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+ idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ if (intr_info_field & INTR_INFO_VALID_MASK) {
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ /* TODO: fault when IDT_Vectoring */
+ printk(KERN_ERR "Fault when IDT_Vectoring\n");
+ }
+ if (has_ext_irq)
+ enable_irq_window(vcpu);
+ return;
+ }
+ if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+ vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+ vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+
+ if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ vmcs_read32(IDT_VECTORING_ERROR_CODE));
+ if (unlikely(has_ext_irq))
+ enable_irq_window(vcpu);
+ return;
+ }
+ if (!has_ext_irq)
+ return;
+ interrupt_window_open =
+ ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
+ if (interrupt_window_open) {
+ vector = kvm_cpu_get_interrupt(vcpu);
+ vmx_inject_irq(vcpu, vector);
+ kvm_timer_intr_post(vcpu, vector);
+ } else
+ enable_irq_window(vcpu);
+}
+
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
/*
* Loading guest fpu may have cleared host cr0.ts
*/
vmcs_writel(HOST_CR0, read_cr0());
- local_irq_disable();
-
- vcpu->guest_mode = 1;
- if (vcpu->requests)
- if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
- vmx_flush_tlb(vcpu);
-
asm (
/* Store host registers */
#ifdef CONFIG_X86_64
@@ -2115,8 +2295,8 @@ again:
"pop %%ecx; popa \n\t"
#endif
"setbe %0 \n\t"
- : "=q" (fail)
- : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
+ : "=q" (vmx->fail)
+ : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
"c"(vcpu),
[rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
[rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
@@ -2138,59 +2318,10 @@ again:
[cr2]"i"(offsetof(struct kvm_vcpu, cr2))
: "cc", "memory" );
- vcpu->guest_mode = 0;
- local_irq_enable();
-
- ++vcpu->stat.exits;
-
vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
-
- if (unlikely(fail)) {
- kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
- kvm_run->fail_entry.hardware_entry_failure_reason
- = vmcs_read32(VM_INSTRUCTION_ERROR);
- r = 0;
- goto out;
- }
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
- vcpu->launched = 1;
- r = kvm_handle_exit(kvm_run, vcpu);
- if (r > 0) {
- /* Give scheduler a change to reschedule. */
- if (signal_pending(current)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.signal_exits;
- goto out;
- }
-
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.request_irq_exits;
- goto out;
- }
- if (!need_resched()) {
- ++vcpu->stat.light_exits;
- goto again;
- }
- }
-
-out:
- if (r > 0) {
- kvm_resched(vcpu);
- goto preempted;
- }
-
- post_kvm_run_save(vcpu, kvm_run);
- return r;
+ vmx->launched = 1;
}
static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
@@ -2225,67 +2356,118 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
{
- if (vcpu->vmcs) {
- on_each_cpu(__vcpu_clear, vcpu, 0, 1);
- free_vmcs(vcpu->vmcs);
- vcpu->vmcs = NULL;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (vmx->vmcs) {
+ on_each_cpu(__vcpu_clear, vmx, 0, 1);
+ free_vmcs(vmx->vmcs);
+ vmx->vmcs = NULL;
}
}
static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
vmx_free_vmcs(vcpu);
+ kfree(vmx->host_msrs);
+ kfree(vmx->guest_msrs);
+ kvm_vcpu_uninit(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vmx);
}
-static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
+static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
{
- struct vmcs *vmcs;
+ int err;
+ struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ int cpu;
- vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!vcpu->guest_msrs)
- return -ENOMEM;
+ if (!vmx)
+ return ERR_PTR(-ENOMEM);
- vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!vcpu->host_msrs)
- goto out_free_guest_msrs;
+ err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
- vmcs = alloc_vmcs();
- if (!vmcs)
- goto out_free_msrs;
+ if (irqchip_in_kernel(kvm)) {
+ err = kvm_create_lapic(&vmx->vcpu);
+ if (err < 0)
+ goto free_vcpu;
+ }
- vmcs_clear(vmcs);
- vcpu->vmcs = vmcs;
- vcpu->launched = 0;
+ vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vmx->guest_msrs) {
+ err = -ENOMEM;
+ goto uninit_vcpu;
+ }
- return 0;
+ vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vmx->host_msrs)
+ goto free_guest_msrs;
-out_free_msrs:
- kfree(vcpu->host_msrs);
- vcpu->host_msrs = NULL;
+ vmx->vmcs = alloc_vmcs();
+ if (!vmx->vmcs)
+ goto free_msrs;
-out_free_guest_msrs:
- kfree(vcpu->guest_msrs);
- vcpu->guest_msrs = NULL;
+ vmcs_clear(vmx->vmcs);
- return -ENOMEM;
+ cpu = get_cpu();
+ vmx_vcpu_load(&vmx->vcpu, cpu);
+ err = vmx_vcpu_setup(vmx);
+ vmx_vcpu_put(&vmx->vcpu);
+ put_cpu();
+ if (err)
+ goto free_vmcs;
+
+ return &vmx->vcpu;
+
+free_vmcs:
+ free_vmcs(vmx->vmcs);
+free_msrs:
+ kfree(vmx->host_msrs);
+free_guest_msrs:
+ kfree(vmx->guest_msrs);
+uninit_vcpu:
+ kvm_vcpu_uninit(&vmx->vcpu);
+free_vcpu:
+ kmem_cache_free(kvm_vcpu_cache, vmx);
+ return ERR_PTR(err);
+}
+
+static void __init vmx_check_processor_compat(void *rtn)
+{
+ struct vmcs_config vmcs_conf;
+
+ *(int *)rtn = 0;
+ if (setup_vmcs_config(&vmcs_conf) < 0)
+ *(int *)rtn = -EIO;
+ if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
+ printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
+ smp_processor_id());
+ *(int *)rtn = -EIO;
+ }
}
-static struct kvm_arch_ops vmx_arch_ops = {
+static struct kvm_x86_ops vmx_x86_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios,
.hardware_setup = hardware_setup,
.hardware_unsetup = hardware_unsetup,
+ .check_processor_compatibility = vmx_check_processor_compat,
.hardware_enable = hardware_enable,
.hardware_disable = hardware_disable,
.vcpu_create = vmx_create_vcpu,
.vcpu_free = vmx_free_vcpu,
+ .vcpu_reset = vmx_vcpu_reset,
+ .prepare_guest_switch = vmx_save_host_state,
.vcpu_load = vmx_vcpu_load,
.vcpu_put = vmx_vcpu_put,
.vcpu_decache = vmx_vcpu_decache,
.set_guest_debug = set_guest_debug,
+ .guest_debug_pre = kvm_guest_debug_pre,
.get_msr = vmx_get_msr,
.set_msr = vmx_set_msr,
.get_segment_base = vmx_get_segment_base,
@@ -2314,9 +2496,13 @@ static struct kvm_arch_ops vmx_arch_ops = {
.inject_gp = vmx_inject_gp,
.run = vmx_vcpu_run,
+ .handle_exit = kvm_handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = vmx_vcpu_setup,
.patch_hypercall = vmx_patch_hypercall,
+ .get_irq = vmx_get_irq,
+ .set_irq = vmx_inject_irq,
+ .inject_pending_irq = vmx_intr_assist,
+ .inject_pending_vectors = do_interrupt_requests,
};
static int __init vmx_init(void)
@@ -2347,7 +2533,7 @@ static int __init vmx_init(void)
memset(iova, 0xff, PAGE_SIZE);
kunmap(vmx_io_bitmap_b);
- r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+ r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
if (r)
goto out1;
@@ -2365,7 +2551,7 @@ static void __exit vmx_exit(void)
__free_page(vmx_io_bitmap_b);
__free_page(vmx_io_bitmap_a);
- kvm_exit_arch();
+ kvm_exit_x86();
}
module_init(vmx_init)
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index d0dc93df411..fd4e1466608 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -25,29 +25,36 @@
*
*/
-#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
-#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
-#define CPU_BASED_HLT_EXITING 0x00000080
-#define CPU_BASED_INVDPG_EXITING 0x00000200
-#define CPU_BASED_MWAIT_EXITING 0x00000400
-#define CPU_BASED_RDPMC_EXITING 0x00000800
-#define CPU_BASED_RDTSC_EXITING 0x00001000
-#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
-#define CPU_BASED_CR8_STORE_EXITING 0x00100000
-#define CPU_BASED_TPR_SHADOW 0x00200000
-#define CPU_BASED_MOV_DR_EXITING 0x00800000
-#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
-#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
-#define CPU_BASED_MSR_BITMAPS 0x10000000
-#define CPU_BASED_MONITOR_EXITING 0x20000000
-#define CPU_BASED_PAUSE_EXITING 0x40000000
+#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
+#define CPU_BASED_HLT_EXITING 0x00000080
+#define CPU_BASED_INVLPG_EXITING 0x00000200
+#define CPU_BASED_MWAIT_EXITING 0x00000400
+#define CPU_BASED_RDPMC_EXITING 0x00000800
+#define CPU_BASED_RDTSC_EXITING 0x00001000
+#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
+#define CPU_BASED_CR8_STORE_EXITING 0x00100000
+#define CPU_BASED_TPR_SHADOW 0x00200000
+#define CPU_BASED_MOV_DR_EXITING 0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
+#define CPU_BASED_USE_IO_BITMAPS 0x02000000
+#define CPU_BASED_USE_MSR_BITMAPS 0x10000000
+#define CPU_BASED_MONITOR_EXITING 0x20000000
+#define CPU_BASED_PAUSE_EXITING 0x40000000
+#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000
-#define PIN_BASED_EXT_INTR_MASK 0x1
-#define PIN_BASED_NMI_EXITING 0x8
+#define PIN_BASED_EXT_INTR_MASK 0x00000001
+#define PIN_BASED_NMI_EXITING 0x00000008
+#define PIN_BASED_VIRTUAL_NMIS 0x00000020
-#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
-#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200
+#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200
+#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
+#define VM_ENTRY_IA32E_MODE 0x00000200
+#define VM_ENTRY_SMM 0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
+
+#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
/* VMCS Encodings */
enum vmcs_field {
@@ -206,6 +213,7 @@ enum vmcs_field {
#define EXIT_REASON_MSR_READ 31
#define EXIT_REASON_MSR_WRITE 32
#define EXIT_REASON_MWAIT_INSTRUCTION 36
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
/*
* Interruption-information format
@@ -261,9 +269,6 @@ enum vmcs_field {
/* segment AR */
#define SEGMENT_AR_L_MASK (1 << 13)
-/* entry controls */
-#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9)
-
#define AR_TYPE_ACCESSES_MASK 1
#define AR_TYPE_READABLE_MASK (1 << 1)
#define AR_TYPE_WRITEABLE_MASK (1 << 2)
@@ -285,13 +290,21 @@ enum vmcs_field {
#define AR_RESERVD_MASK 0xfffe0f00
-#define CR4_VMXE 0x2000
+#define MSR_IA32_VMX_BASIC 0x480
+#define MSR_IA32_VMX_PINBASED_CTLS 0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS 0x482
+#define MSR_IA32_VMX_EXIT_CTLS 0x483
+#define MSR_IA32_VMX_ENTRY_CTLS 0x484
+#define MSR_IA32_VMX_MISC 0x485
+#define MSR_IA32_VMX_CR0_FIXED0 0x486
+#define MSR_IA32_VMX_CR0_FIXED1 0x487
+#define MSR_IA32_VMX_CR4_FIXED0 0x488
+#define MSR_IA32_VMX_CR4_FIXED1 0x489
+#define MSR_IA32_VMX_VMCS_ENUM 0x48a
+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b
-#define MSR_IA32_VMX_BASIC 0x480
-#define MSR_IA32_FEATURE_CONTROL 0x03a
-#define MSR_IA32_VMX_PINBASED_CTLS 0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS 0x482
-#define MSR_IA32_VMX_EXIT_CTLS 0x483
-#define MSR_IA32_VMX_ENTRY_CTLS 0x484
+#define MSR_IA32_FEATURE_CONTROL 0x3a
+#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1
+#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4
#endif
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 4b8a0cc9665..9737c3b2f48 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -6,7 +6,7 @@
* Copyright (c) 2005 Keir Fraser
*
* Linux coding style, mod r/m decoder, segment base fixes, real-mode
- * privieged instructions:
+ * privileged instructions:
*
* Copyright (C) 2006 Qumranet
*
@@ -83,7 +83,7 @@ static u8 opcode_table[256] = {
/* 0x20 - 0x27 */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- 0, 0, 0, 0,
+ SrcImmByte, SrcImm, 0, 0,
/* 0x28 - 0x2F */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -99,15 +99,24 @@ static u8 opcode_table[256] = {
/* 0x40 - 0x4F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x50 - 0x57 */
- 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x58 - 0x5F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- /* 0x60 - 0x6F */
+ /* 0x60 - 0x67 */
0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* 0x68 - 0x6F */
+ 0, 0, ImplicitOps|Mov, 0,
+ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */
+ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */
+ /* 0x70 - 0x77 */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ /* 0x78 - 0x7F */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x80 - 0x87 */
ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
@@ -116,9 +125,9 @@ static u8 opcode_table[256] = {
/* 0x88 - 0x8F */
ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- 0, 0, 0, DstMem | SrcNone | ModRM | Mov,
+ 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov,
/* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0,
/* 0xA0 - 0xA7 */
ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
@@ -142,8 +151,10 @@ static u8 opcode_table[256] = {
0, 0, 0, 0,
/* 0xD8 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xEF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xE7 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE8 - 0xEF */
+ ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
ImplicitOps, 0,
@@ -181,7 +192,10 @@ static u16 twobyte_table[256] = {
/* 0x70 - 0x7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 - 0x8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xA0 - 0xA7 */
@@ -207,19 +221,6 @@ static u16 twobyte_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-/*
- * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we
- * are interested only in invlpg and not in any of the rest.
- *
- * invlpg is a special instruction in that the data it references may not
- * be mapped.
- */
-void kvm_emulator_want_group7_invlpg(void)
-{
- twobyte_table[1] &= ~SrcMem;
-}
-EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg);
-
/* Type, address-of, and value of an instruction's operand. */
struct operand {
enum { OP_REG, OP_MEM, OP_IMM } type;
@@ -420,7 +421,7 @@ struct operand {
#define insn_fetch(_type, _size, _eip) \
({ unsigned long _x; \
rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \
- (_size), ctxt); \
+ (_size), ctxt->vcpu); \
if ( rc != 0 ) \
goto done; \
(_eip) += (_size); \
@@ -428,10 +429,11 @@ struct operand {
})
/* Access/update address held in a register, based on addressing mode. */
+#define address_mask(reg) \
+ ((ad_bytes == sizeof(unsigned long)) ? \
+ (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1)))
#define register_address(base, reg) \
- ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \
- ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
-
+ ((base) + address_mask(reg))
#define register_address_increment(reg, inc) \
do { \
/* signed type ensures sign extension to long */ \
@@ -443,8 +445,19 @@ struct operand {
(((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
} while (0)
-void *decode_register(u8 modrm_reg, unsigned long *regs,
- int highbyte_regs)
+#define JMP_REL(rel) \
+ do { \
+ _eip += (int)(rel); \
+ _eip = ((op_bytes == 2) ? (uint16_t)_eip : (uint32_t)_eip); \
+ } while (0)
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+static void *decode_register(u8 modrm_reg, unsigned long *regs,
+ int highbyte_regs)
{
void *p;
@@ -464,13 +477,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
if (op_bytes == 2)
op_bytes = 3;
*address = 0;
- rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt);
+ rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
+ ctxt->vcpu);
if (rc)
return rc;
- rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt);
+ rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
+ ctxt->vcpu);
return rc;
}
+static int test_cc(unsigned int condition, unsigned int flags)
+{
+ int rc = 0;
+
+ switch ((condition & 15) >> 1) {
+ case 0: /* o */
+ rc |= (flags & EFLG_OF);
+ break;
+ case 1: /* b/c/nae */
+ rc |= (flags & EFLG_CF);
+ break;
+ case 2: /* z/e */
+ rc |= (flags & EFLG_ZF);
+ break;
+ case 3: /* be/na */
+ rc |= (flags & (EFLG_CF|EFLG_ZF));
+ break;
+ case 4: /* s */
+ rc |= (flags & EFLG_SF);
+ break;
+ case 5: /* p/pe */
+ rc |= (flags & EFLG_PF);
+ break;
+ case 7: /* le/ng */
+ rc |= (flags & EFLG_ZF);
+ /* fall through */
+ case 6: /* l/nge */
+ rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
+ break;
+ }
+
+ /* Odd condition identifiers (lsb == 1) have inverted sense. */
+ return (!!rc ^ (condition & 1));
+}
+
int
x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
@@ -771,11 +821,15 @@ done_prefixes:
goto srcmem_common;
case SrcMem:
src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ /* Don't fetch the address for invlpg: it could be unmapped. */
+ if (twobyte && b == 0x01 && modrm_reg == 7)
+ break;
srcmem_common:
src.type = OP_MEM;
src.ptr = (unsigned long *)cr2;
+ src.val = 0;
if ((rc = ops->read_emulated((unsigned long)src.ptr,
- &src.val, src.bytes, ctxt)) != 0)
+ &src.val, src.bytes, ctxt->vcpu)) != 0)
goto done;
src.orig_val = src.val;
break;
@@ -814,7 +868,7 @@ done_prefixes:
case DstReg:
dst.type = OP_REG;
if ((d & ByteOp)
- && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+ && !(twobyte && (b == 0xb6 || b == 0xb7))) {
dst.ptr = decode_register(modrm_reg, _regs,
(rex_prefix == 0));
dst.val = *(u8 *) dst.ptr;
@@ -838,6 +892,7 @@ done_prefixes:
dst.type = OP_MEM;
dst.ptr = (unsigned long *)cr2;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.val = 0;
if (d & BitOp) {
unsigned long mask = ~(dst.bytes * 8 - 1);
@@ -845,7 +900,7 @@ done_prefixes:
}
if (!(d & Mov) && /* optimisation - avoid slow emulated read */
((rc = ops->read_emulated((unsigned long)dst.ptr,
- &dst.val, dst.bytes, ctxt)) != 0))
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0))
goto done;
break;
}
@@ -871,10 +926,27 @@ done_prefixes:
sbb: /* sbb */
emulate_2op_SrcV("sbb", src, dst, _eflags);
break;
- case 0x20 ... 0x25:
+ case 0x20 ... 0x23:
and: /* and */
emulate_2op_SrcV("and", src, dst, _eflags);
break;
+ case 0x24: /* and al imm8 */
+ dst.type = OP_REG;
+ dst.ptr = &_regs[VCPU_REGS_RAX];
+ dst.val = *(u8 *)dst.ptr;
+ dst.bytes = 1;
+ dst.orig_val = dst.val;
+ goto and;
+ case 0x25: /* and ax imm16, or eax imm32 */
+ dst.type = OP_REG;
+ dst.bytes = op_bytes;
+ dst.ptr = &_regs[VCPU_REGS_RAX];
+ if (op_bytes == 2)
+ dst.val = *(u16 *)dst.ptr;
+ else
+ dst.val = *(u32 *)dst.ptr;
+ dst.orig_val = dst.val;
+ goto and;
case 0x28 ... 0x2d:
sub: /* sub */
emulate_2op_SrcV("sub", src, dst, _eflags);
@@ -892,6 +964,17 @@ done_prefixes:
goto cannot_emulate;
dst.val = (s32) src.val;
break;
+ case 0x6a: /* push imm8 */
+ src.val = 0L;
+ src.val = insn_fetch(s8, 1, _eip);
+push:
+ dst.type = OP_MEM;
+ dst.bytes = op_bytes;
+ dst.val = src.val;
+ register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+ dst.ptr = (void *) register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]);
+ break;
case 0x80 ... 0x83: /* Grp1 */
switch (modrm_reg) {
case 0:
@@ -939,18 +1022,10 @@ done_prefixes:
dst.val = src.val;
lock_prefix = 1;
break;
- case 0xa0 ... 0xa1: /* mov */
- dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
- dst.val = src.val;
- _eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2 ... 0xa3: /* mov */
- dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
- _eip += ad_bytes; /* skip dst displacement */
- break;
case 0x88 ... 0x8b: /* mov */
- case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
- dst.val = src.val;
+ goto mov;
+ case 0x8d: /* lea r16/r32, m */
+ dst.val = modrm_val;
break;
case 0x8f: /* pop (sole member of Grp1a) */
/* 64-bit mode: POP always pops a 64-bit operand. */
@@ -958,10 +1033,19 @@ done_prefixes:
dst.bytes = 8;
if ((rc = ops->read_std(register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]),
- &dst.val, dst.bytes, ctxt)) != 0)
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
break;
+ case 0xa0 ... 0xa1: /* mov */
+ dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+ dst.val = src.val;
+ _eip += ad_bytes; /* skip src displacement */
+ break;
+ case 0xa2 ... 0xa3: /* mov */
+ dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
+ _eip += ad_bytes; /* skip dst displacement */
+ break;
case 0xc0 ... 0xc1:
grp2: /* Grp2 */
switch (modrm_reg) {
@@ -989,12 +1073,41 @@ done_prefixes:
break;
}
break;
+ case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
+ mov:
+ dst.val = src.val;
+ break;
case 0xd0 ... 0xd1: /* Grp2 */
src.val = 1;
goto grp2;
case 0xd2 ... 0xd3: /* Grp2 */
src.val = _regs[VCPU_REGS_RCX];
goto grp2;
+ case 0xe8: /* call (near) */ {
+ long int rel;
+ switch (op_bytes) {
+ case 2:
+ rel = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ rel = insn_fetch(s32, 4, _eip);
+ break;
+ case 8:
+ rel = insn_fetch(s64, 8, _eip);
+ break;
+ default:
+ DPRINTF("Call: Invalid op_bytes\n");
+ goto cannot_emulate;
+ }
+ src.val = (unsigned long) _eip;
+ JMP_REL(rel);
+ goto push;
+ }
+ case 0xe9: /* jmp rel */
+ case 0xeb: /* jmp rel short */
+ JMP_REL(src.val);
+ no_wb = 1; /* Disable writeback. */
+ break;
case 0xf6 ... 0xf7: /* Grp3 */
switch (modrm_reg) {
case 0 ... 1: /* test */
@@ -1037,13 +1150,19 @@ done_prefixes:
case 1: /* dec */
emulate_1op("dec", dst, _eflags);
break;
+ case 4: /* jmp abs */
+ if (b == 0xff)
+ _eip = dst.val;
+ else
+ goto cannot_emulate;
+ break;
case 6: /* push */
/* 64-bit mode: PUSH always pushes a 64-bit operand. */
if (mode == X86EMUL_MODE_PROT64) {
dst.bytes = 8;
if ((rc = ops->read_std((unsigned long)dst.ptr,
&dst.val, 8,
- ctxt)) != 0)
+ ctxt->vcpu)) != 0)
goto done;
}
register_address_increment(_regs[VCPU_REGS_RSP],
@@ -1051,7 +1170,7 @@ done_prefixes:
if ((rc = ops->write_std(
register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]),
- &dst.val, dst.bytes, ctxt)) != 0)
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
no_wb = 1;
break;
@@ -1086,11 +1205,11 @@ writeback:
rc = ops->cmpxchg_emulated((unsigned long)dst.
ptr, &dst.orig_val,
&dst.val, dst.bytes,
- ctxt);
+ ctxt->vcpu);
else
rc = ops->write_emulated((unsigned long)dst.ptr,
&dst.val, dst.bytes,
- ctxt);
+ ctxt->vcpu);
if (rc != 0)
goto done;
default:
@@ -1109,6 +1228,81 @@ done:
special_insn:
if (twobyte)
goto twobyte_special_insn;
+ switch(b) {
+ case 0x50 ... 0x57: /* push reg */
+ if (op_bytes == 2)
+ src.val = (u16) _regs[b & 0x7];
+ else
+ src.val = (u32) _regs[b & 0x7];
+ dst.type = OP_MEM;
+ dst.bytes = op_bytes;
+ dst.val = src.val;
+ register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+ dst.ptr = (void *) register_address(
+ ctxt->ss_base, _regs[VCPU_REGS_RSP]);
+ break;
+ case 0x58 ... 0x5f: /* pop reg */
+ dst.ptr = (unsigned long *)&_regs[b & 0x7];
+ pop_instruction:
+ if ((rc = ops->read_std(register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu))
+ != 0)
+ goto done;
+
+ register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+ no_wb = 1; /* Disable writeback. */
+ break;
+ case 0x6c: /* insb */
+ case 0x6d: /* insw/insd */
+ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 1, /* in */
+ (d & ByteOp) ? 1 : op_bytes, /* size */
+ rep_prefix ?
+ address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+ (_eflags & EFLG_DF), /* down */
+ register_address(ctxt->es_base,
+ _regs[VCPU_REGS_RDI]), /* address */
+ rep_prefix,
+ _regs[VCPU_REGS_RDX] /* port */
+ ) == 0)
+ return -1;
+ return 0;
+ case 0x6e: /* outsb */
+ case 0x6f: /* outsw/outsd */
+ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 0, /* in */
+ (d & ByteOp) ? 1 : op_bytes, /* size */
+ rep_prefix ?
+ address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+ (_eflags & EFLG_DF), /* down */
+ register_address(override_base ?
+ *override_base : ctxt->ds_base,
+ _regs[VCPU_REGS_RSI]), /* address */
+ rep_prefix,
+ _regs[VCPU_REGS_RDX] /* port */
+ ) == 0)
+ return -1;
+ return 0;
+ case 0x70 ... 0x7f: /* jcc (short) */ {
+ int rel = insn_fetch(s8, 1, _eip);
+
+ if (test_cc(b, _eflags))
+ JMP_REL(rel);
+ break;
+ }
+ case 0x9c: /* pushf */
+ src.val = (unsigned long) _eflags;
+ goto push;
+ case 0x9d: /* popf */
+ dst.ptr = (unsigned long *) &_eflags;
+ goto pop_instruction;
+ case 0xc3: /* ret */
+ dst.ptr = &_eip;
+ goto pop_instruction;
+ case 0xf4: /* hlt */
+ ctxt->vcpu->halt_request = 1;
+ goto done;
+ }
if (rep_prefix) {
if (_regs[VCPU_REGS_RCX] == 0) {
ctxt->vcpu->rip = _eip;
@@ -1125,7 +1319,7 @@ special_insn:
_regs[VCPU_REGS_RDI]);
if ((rc = ops->read_emulated(register_address(
override_base ? *override_base : ctxt->ds_base,
- _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0)
+ _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSI],
(_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1147,7 +1341,8 @@ special_insn:
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
- if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0)
+ if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes,
+ ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSI],
(_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1155,23 +1350,7 @@ special_insn:
case 0xae ... 0xaf: /* scas */
DPRINTF("Urk! I don't handle SCAS.\n");
goto cannot_emulate;
- case 0xf4: /* hlt */
- ctxt->vcpu->halt_request = 1;
- goto done;
- case 0xc3: /* ret */
- dst.ptr = &_eip;
- goto pop_instruction;
- case 0x58 ... 0x5f: /* pop reg */
- dst.ptr = (unsigned long *)&_regs[b & 0x7];
-pop_instruction:
- if ((rc = ops->read_std(register_address(ctxt->ss_base,
- _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0)
- goto done;
-
- register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
- no_wb = 1; /* Disable writeback. */
- break;
}
goto writeback;
@@ -1230,40 +1409,50 @@ twobyte_insn:
break;
case 0x40 ... 0x4f: /* cmov */
dst.val = dst.orig_val = src.val;
- d &= ~Mov; /* default to no move */
+ no_wb = 1;
/*
* First, assume we're decoding an even cmov opcode
* (lsb == 0).
*/
switch ((b & 15) >> 1) {
case 0: /* cmovo */
- d |= (_eflags & EFLG_OF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_OF) ? 0 : 1;
break;
case 1: /* cmovb/cmovc/cmovnae */
- d |= (_eflags & EFLG_CF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_CF) ? 0 : 1;
break;
case 2: /* cmovz/cmove */
- d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
break;
case 3: /* cmovbe/cmovna */
- d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+ no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1;
break;
case 4: /* cmovs */
- d |= (_eflags & EFLG_SF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_SF) ? 0 : 1;
break;
case 5: /* cmovp/cmovpe */
- d |= (_eflags & EFLG_PF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_PF) ? 0 : 1;
break;
case 7: /* cmovle/cmovng */
- d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
/* fall through */
case 6: /* cmovl/cmovnge */
- d |= (!(_eflags & EFLG_SF) !=
- !(_eflags & EFLG_OF)) ? Mov : 0;
+ no_wb &= (!(_eflags & EFLG_SF) !=
+ !(_eflags & EFLG_OF)) ? 0 : 1;
break;
}
/* Odd cmov opcodes (lsb == 1) have inverted sense. */
- d ^= (b & 1) ? Mov : 0;
+ no_wb ^= b & 1;
+ break;
+ case 0xa3:
+ bt: /* bt */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
+ break;
+ case 0xab:
+ bts: /* bts */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
break;
case 0xb0 ... 0xb1: /* cmpxchg */
/*
@@ -1273,8 +1462,6 @@ twobyte_insn:
src.orig_val = src.val;
src.val = _regs[VCPU_REGS_RAX];
emulate_2op_SrcV("cmp", src, dst, _eflags);
- /* Always write back. The question is: where to? */
- d |= Mov;
if (_eflags & EFLG_ZF) {
/* Success: write back to memory. */
dst.val = src.orig_val;
@@ -1284,30 +1471,15 @@ twobyte_insn:
dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
}
break;
- case 0xa3:
- bt: /* bt */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
- break;
case 0xb3:
btr: /* btr */
src.val &= (dst.bytes << 3) - 1; /* only subword offset */
emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
break;
- case 0xab:
- bts: /* bts */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
- break;
case 0xb6 ... 0xb7: /* movzx */
dst.bytes = op_bytes;
dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
break;
- case 0xbb:
- btc: /* btc */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
- break;
case 0xba: /* Grp8 */
switch (modrm_reg & 3) {
case 0:
@@ -1320,6 +1492,11 @@ twobyte_insn:
goto btc;
}
break;
+ case 0xbb:
+ btc: /* btc */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
+ break;
case 0xbe ... 0xbf: /* movsx */
dst.bytes = op_bytes;
dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
@@ -1331,14 +1508,14 @@ twobyte_special_insn:
/* Disable writeback. */
no_wb = 1;
switch (b) {
+ case 0x06:
+ emulate_clts(ctxt->vcpu);
+ break;
case 0x09: /* wbinvd */
break;
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
break;
- case 0x06:
- emulate_clts(ctxt->vcpu);
- break;
case 0x20: /* mov cr, reg */
if (modrm_mod != 3)
goto cannot_emulate;
@@ -1355,7 +1532,7 @@ twobyte_special_insn:
| ((u64)_regs[VCPU_REGS_RDX] << 32);
rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
if (rc) {
- kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
_eip = ctxt->vcpu->rip;
}
rc = X86EMUL_CONTINUE;
@@ -1364,7 +1541,7 @@ twobyte_special_insn:
/* rdmsr */
rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
if (rc) {
- kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
_eip = ctxt->vcpu->rip;
} else {
_regs[VCPU_REGS_RAX] = (u32)msr_data;
@@ -1372,10 +1549,32 @@ twobyte_special_insn:
}
rc = X86EMUL_CONTINUE;
break;
+ case 0x80 ... 0x8f: /* jnz rel, etc*/ {
+ long int rel;
+
+ switch (op_bytes) {
+ case 2:
+ rel = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ rel = insn_fetch(s32, 4, _eip);
+ break;
+ case 8:
+ rel = insn_fetch(s64, 8, _eip);
+ break;
+ default:
+ DPRINTF("jnz: Invalid op_bytes\n");
+ goto cannot_emulate;
+ }
+ if (test_cc(b, _eflags))
+ JMP_REL(rel);
+ break;
+ }
case 0xc7: /* Grp9 (cmpxchg8b) */
{
u64 old, new;
- if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
+ if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu))
+ != 0)
goto done;
if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
@@ -1386,7 +1585,7 @@ twobyte_special_insn:
new = ((u64)_regs[VCPU_REGS_RCX] << 32)
| (u32) _regs[VCPU_REGS_RBX];
if ((rc = ops->cmpxchg_emulated(cr2, &old,
- &new, 8, ctxt)) != 0)
+ &new, 8, ctxt->vcpu)) != 0)
goto done;
_eflags |= EFLG_ZF;
}
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
index ea3407d7fee..92c73aa7f9a 100644
--- a/drivers/kvm/x86_emulate.h
+++ b/drivers/kvm/x86_emulate.h
@@ -60,7 +60,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to read from memory.
*/
int (*read_std)(unsigned long addr, void *val,
- unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+ unsigned int bytes, struct kvm_vcpu *vcpu);
/*
* write_std: Write bytes of standard (non-emulated/special) memory.
@@ -71,7 +71,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to write to memory.
*/
int (*write_std)(unsigned long addr, const void *val,
- unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+ unsigned int bytes, struct kvm_vcpu *vcpu);
/*
* read_emulated: Read bytes from emulated/special memory area.
@@ -82,7 +82,7 @@ struct x86_emulate_ops {
int (*read_emulated) (unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
/*
* write_emulated: Read bytes from emulated/special memory area.
@@ -94,7 +94,7 @@ struct x86_emulate_ops {
int (*write_emulated) (unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
/*
* cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
@@ -108,12 +108,10 @@ struct x86_emulate_ops {
const void *old,
const void *new,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
};
-struct cpu_user_regs;
-
struct x86_emulate_ctxt {
/* Register state before/after emulation. */
struct kvm_vcpu *vcpu;
@@ -154,12 +152,4 @@ struct x86_emulate_ctxt {
int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops);
-/*
- * Given the 'reg' portion of a ModRM byte, and a register block, return a
- * pointer into the block that addresses the relevant register.
- * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
- */
-void *decode_register(u8 modrm_reg, unsigned long *regs,
- int highbyte_regs);
-
#endif /* __X86_EMULATE_H__ */
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 56cd8998fe4..77f50b63a97 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -172,6 +172,7 @@ config INPUT_ADBHID
config MAC_EMUMOUSEBTN
bool "Support for mouse button 2+3 emulation"
+ select INPUT
help
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 48d17bf6c92..8cce016b3d0 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -52,6 +52,11 @@
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+static int restore_capslock_events;
+module_param(restore_capslock_events, int, 0644);
+MODULE_PARM_DESC(restore_capslock_events,
+ "Produce keypress events for capslock on both keyup and keydown.");
+
#define KEYB_KEYREG 0 /* register # for key up/down data */
#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
@@ -217,6 +222,8 @@ struct adbhid {
#define FLAG_FN_KEY_PRESSED 0x00000001
#define FLAG_POWER_FROM_FN 0x00000002
#define FLAG_EMU_FWDEL_DOWN 0x00000004
+#define FLAG_CAPSLOCK_TRANSLATE 0x00000008
+#define FLAG_CAPSLOCK_DOWN 0x00000010
static struct adbhid *adbhid[16];
@@ -272,19 +279,50 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
}
static void
-adbhid_input_keycode(int id, int keycode, int repeat)
+adbhid_input_keycode(int id, int scancode, int repeat)
{
struct adbhid *ahid = adbhid[id];
- int up_flag, key;
-
- up_flag = (keycode & 0x80);
- keycode &= 0x7f;
+ int keycode, up_flag;
+
+ keycode = scancode & 0x7f;
+ up_flag = scancode & 0x80;
+
+ if (restore_capslock_events) {
+ if (keycode == ADB_KEY_CAPSLOCK && !up_flag) {
+ /* Key pressed, turning on the CapsLock LED.
+ * The next 0xff will be interpreted as a release. */
+ ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
+ | FLAG_CAPSLOCK_DOWN;
+ } else if (scancode == 0xff) {
+ /* Scancode 0xff usually signifies that the capslock
+ * key was either pressed or released. */
+ if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
+ keycode = ADB_KEY_CAPSLOCK;
+ if (ahid->flags & FLAG_CAPSLOCK_DOWN) {
+ /* Key released */
+ up_flag = 1;
+ ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
+ } else {
+ /* Key pressed */
+ up_flag = 0;
+ ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
+ }
+ } else {
+ printk(KERN_INFO "Spurious caps lock event "
+ "(scancode 0xff).");
+ }
+ }
+ }
switch (keycode) {
- case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
- input_report_key(ahid->input, KEY_CAPSLOCK, 1);
- input_report_key(ahid->input, KEY_CAPSLOCK, 0);
- input_sync(ahid->input);
+ case ADB_KEY_CAPSLOCK:
+ if (!restore_capslock_events) {
+ /* Generate down/up events for CapsLock everytime. */
+ input_report_key(ahid->input, KEY_CAPSLOCK, 1);
+ input_sync(ahid->input);
+ input_report_key(ahid->input, KEY_CAPSLOCK, 0);
+ input_sync(ahid->input);
+ }
return;
#ifdef CONFIG_PPC_PMAC
case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
@@ -296,7 +334,7 @@ adbhid_input_keycode(int id, int keycode, int repeat)
keycode = ADB_KEY_POWER;
}
break;
- case ADB_KEY_POWER:
+ case ADB_KEY_POWER:
/* Fn + Command will produce a bogus "power" keycode */
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
keycode = ADB_KEY_CMD;
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index a2191a4fcf7..342517261ec 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -54,8 +54,6 @@ static void emc_endio(struct bio *bio, int error)
/* request is freed in block layer */
free_bio(bio);
-
- return 0;
}
static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e8f102ea9b0..acf1b81b47c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
mddev->gendisk = disk;
mutex_unlock(&disks_mutex);
mddev->kobj.parent = &disk->kobj;
- mddev->kobj.k_name = NULL;
- snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+ kobject_set_name(&mddev->kobj, "%s", "md");
mddev->kobj.ktype = &md_ktype;
if (kobject_register(&mddev->kobj))
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 56231d8edc0..18738faecbb 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops =
.open = dvb_device_open,
};
-static struct cdev dvb_device_cdev = {
- .kobj = {.name = "dvb", },
- .owner = THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
int dvb_generic_open(struct inode *inode, struct file *file)
{
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 844f1762c45..4d5b8035e46 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -124,12 +124,6 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = {
/* ----------------------------------------------------------------------- */
/* I2C functions - hardware i2c */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL;
@@ -278,7 +272,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
static struct i2c_algorithm bttv_algo = {
.master_xfer = bttv_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index b517c8b5a56..71da528932d 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -272,12 +272,6 @@ void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
i2c_clients_command(&bus->i2c_adap, cmd, arg);
}
-static int cx23885_algo_control(struct i2c_adapter *adap,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 cx23885_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -285,7 +279,6 @@ static u32 cx23885_functionality(struct i2c_adapter *adap)
static struct i2c_algorithm cx23885_i2c_algo_template = {
.master_xfer = i2c_xfer,
- .algo_control = cx23885_algo_control,
.functionality = cx23885_functionality,
};
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 54ccc6e1f92..997d067e32e 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -383,15 +383,6 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
/* ----------------------------------------------------------- */
/*
- * algo_control()
- */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-/*
* functionality()
*/
static u32 functionality(struct i2c_adapter *adap)
@@ -475,7 +466,6 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm em28xx_algo = {
.master_xfer = em28xx_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 511a6625241..fd7a932e1d3 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -98,9 +98,9 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned int cardtype_c = 1;
+static unsigned int tuner_c = 1;
+static unsigned int radio_c = 1;
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 9eb2562347a..b8d4ac0d938 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -181,7 +181,7 @@ module_param(force_palette, int, 0);
MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
module_param(backlight, int, 0);
MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static int num_uv;
+static unsigned int num_uv;
module_param_array(unit_video, int, &num_uv, 0);
MODULE_PARM_DESC(unit_video,
"Force use of specific minor number(s). 0 is not allowed.");
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 898c9d2e4cd..c817c864e6a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -520,12 +520,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
return ret;
}
-static int pvr2_i2c_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -942,7 +936,6 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
static struct i2c_algorithm pvr2_i2c_algo_template = {
.master_xfer = pvr2_i2c_xfer,
- .algo_control = pvr2_i2c_control,
.functionality = pvr2_i2c_functionality,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7a78d6b3473..2ee3c3049e8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
}
-static int pvr2_sysfs_hotplug(struct device *cd,char **envp,
- int numenvp,char *buf,int size)
+static int pvr2_sysfs_hotplug(struct device *d,
+ struct kobj_uevent_env *env)
{
/* Even though we don't do anything here, we still need this function
because sysfs will still try to call it. */
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 0b67d4ec031..950da254214 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1903,9 +1903,9 @@ static int fbufs;
static int mbufs;
static int compression = -1;
static int leds[2] = { -1, -1 };
-static int leds_nargs;
+static unsigned int leds_nargs;
static char *dev_hint[MAX_DEV_HINTS];
-static int dev_hint_nargs;
+static unsigned int dev_hint_nargs;
module_param(size, charp, 0444);
module_param(fps, int, 0444);
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index cc87f5855a2..6deaad1a548 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -314,12 +314,6 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
/* ----------------------------------------------------------- */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL;
@@ -387,7 +381,6 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm saa7134_algo = {
.master_xfer = saa7134_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index c66aef63916..aabc42cae9c 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -183,11 +183,6 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
return num;
}
-static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
@@ -199,7 +194,6 @@ static u32 functionality(struct i2c_adapter *adap)
static struct i2c_algorithm usbvision_algo = {
.master_xfer = usbvision_i2c_xfer,
.smbus_xfer = NULL,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index c606332512b..5599a36490f 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -674,7 +674,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
/* Copy to userspace */
- retval=CALL(q,copy_to_user,q,data,count,nonblocking);
+ retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
if (retval<0)
goto done;
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 8bb7fdd306d..3eb6123227b 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -670,7 +670,7 @@ static struct videobuf_qtype_ops pci_ops = {
.sync = __videobuf_sync,
.mmap_free = __videobuf_mmap_free,
.mmap_mapper = __videobuf_mmap_mapper,
- .copy_to_user = __videobuf_copy_to_user,
+ .video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
};
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 2e3689a12a2..cd74341c984 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -320,7 +320,7 @@ static struct videobuf_qtype_ops qops = {
.sync = __videobuf_sync,
.mmap_free = __videobuf_mmap_free,
.mmap_mapper = __videobuf_mmap_mapper,
- .copy_to_user = __videobuf_copy_to_user,
+ .video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
};
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 5a1b5f5a7d4..9e7f3e685d7 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -444,8 +444,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
static u32 w9968cf_i2c_func(struct i2c_adapter*);
static int w9968cf_i2c_attach_inform(struct i2c_client*);
static int w9968cf_i2c_detach_inform(struct i2c_client*);
-static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
- unsigned long arg);
/* Memory management */
static void* rvmalloc(unsigned long size);
@@ -1543,21 +1541,12 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client)
}
-static int
-w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
-
static int w9968cf_i2c_init(struct w9968cf_device* cam)
{
int err = 0;
static struct i2c_algorithm algo = {
.smbus_xfer = w9968cf_i2c_smbus_xfer,
- .algo_control = w9968cf_i2c_control,
.functionality = w9968cf_i2c_func,
};
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index f55cc03a75c..a34a11d2fef 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -1,15 +1,19 @@
-menu "Fusion MPT device support"
+menuconfig FUSION
+ bool "Fusion MPT device support"
depends on PCI
+ ---help---
+ Say Y here to get to see options for Fusion Message
+ Passing Technology (MPT) drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
-config FUSION
- bool
- default n
+if FUSION
config FUSION_SPI
tristate "Fusion MPT ScsiHost drivers for SPI"
depends on PCI && SCSI
- select FUSION
select SCSI_SPI_ATTRS
---help---
SCSI HOST support for a parallel SCSI host adapters.
@@ -20,11 +24,11 @@ config FUSION_SPI
LSI53C1020A
LSI53C1030
LSI53C1035
+ ATTO UL4D
config FUSION_FC
tristate "Fusion MPT ScsiHost drivers for FC"
depends on PCI && SCSI
- select FUSION
select SCSI_FC_ATTRS
---help---
SCSI HOST support for a Fiber Channel host adapters.
@@ -37,12 +41,13 @@ config FUSION_FC
LSIFC929
LSIFC929X
LSIFC929XL
+ LSIFC949X
+ LSIFC949E
Brocade FC 410/420
config FUSION_SAS
tristate "Fusion MPT ScsiHost drivers for SAS"
depends on PCI && SCSI
- select FUSION
select SCSI_SAS_ATTRS
---help---
SCSI HOST support for a SAS host adapters.
@@ -53,10 +58,10 @@ config FUSION_SAS
LSISAS1068
LSISAS1064E
LSISAS1068E
+ LSISAS1078
config FUSION_MAX_SGE
int "Maximum number of scatter gather entries (16 - 128)"
- depends on FUSION
default "128"
range 16 128
help
@@ -104,7 +109,6 @@ config FUSION_LAN
config FUSION_LOGGING
bool "Fusion MPT logging facility"
- depends on FUSION
---help---
This turns on a logging facility that can be used to debug a number
of Fusion MPT related problems.
@@ -113,7 +117,7 @@ config FUSION_LOGGING
echo [level] > /sys/class/scsi_host/host#/debug_level
- There are various debug levels that an be found in the source:
+ There are various debug levels that can be found in the source:
file:drivers/message/fusion/mptdebug.h
-endmenu
+endif # FUSION
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 6a92e3d118f..1acbdd61b67 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi.h
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index eda769730e3..2bd8adae0f0 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_cnfg.h
diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h
index 51a6aeb990b..627acfbb862 100644
--- a/drivers/message/fusion/lsi/mpi_fc.h
+++ b/drivers/message/fusion/lsi/mpi_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_fc.h
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index a1f479057ea..241592ab13a 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,7 +3,7 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2007 LSI Logic Corporation.
+ Copyright (c) 2000-2007 LSI Corporation.
---------------------------------------
Header Set Release Version: 01.05.16
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index 3a02615f12d..a9e3693601a 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_init.h
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index b1893d185bc..5cbb6bd048e 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_ioc.h
diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h
index dc0b52ae83d..03253b53b78 100644
--- a/drivers/message/fusion/lsi/mpi_lan.h
+++ b/drivers/message/fusion/lsi/mpi_lan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_lan.h
diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h
index dc98d46f907..e4dafcefeec 100644
--- a/drivers/message/fusion/lsi/mpi_log_fc.h
+++ b/drivers/message/fusion/lsi/mpi_log_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ * Copyright (c) 2000-2001 LSI Corporation. All rights reserved.
*
* NAME: fc_log.h
* SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index 635bbe04513..6be1f6b6577 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -1,6 +1,6 @@
/***************************************************************************
* *
- * Copyright 2003 LSI Logic Corporation. All rights reserved. *
+ * Copyright 2003 LSI Corporation. All rights reserved. *
* *
* Description *
* ------------ *
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
index 32819b1ec8e..2856108421d 100644
--- a/drivers/message/fusion/lsi/mpi_raid.h
+++ b/drivers/message/fusion/lsi/mpi_raid.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2007 LSI Logic Corporation.
+ * Copyright (c) 2001-2007 LSI Corporation.
*
*
* Name: mpi_raid.h
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 8e990a0fa7a..33fca83cefc 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 LSI Logic Corporation.
+ * Copyright (c) 2004-2006 LSI Corporation.
*
*
* Name: mpi_sas.h
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
index 20b66731577..ff8c37d3fdc 100644
--- a/drivers/message/fusion/lsi/mpi_targ.h
+++ b/drivers/message/fusion/lsi/mpi_targ.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_targ.h
diff --git a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h
index aa9053da1f5..8834ae6ce0f 100644
--- a/drivers/message/fusion/lsi/mpi_tool.h
+++ b/drivers/message/fusion/lsi/mpi_tool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2005 LSI Logic Corporation.
+ * Copyright (c) 2001-2005 LSI Corporation.
*
*
* Name: mpi_tool.h
diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h
index 32cc9b1151b..08dad9c1e44 100644
--- a/drivers/message/fusion/lsi/mpi_type.h
+++ b/drivers/message/fusion/lsi/mpi_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_type.h
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 414c109f4cf..52fb216dfe7 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2,10 +2,10 @@
* linux/drivers/message/fusion/mptbase.c
* This is the Fusion MPT base driver which supports multiple
* (SCSI + LAN) specialized protocol drivers.
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -102,8 +102,6 @@ static int mfcounter = 0;
/*
* Public data...
*/
-int mpt_lan_index = -1;
-int mpt_stm_index = -1;
struct proc_dir_entry *mpt_proc_root_dir;
@@ -125,11 +123,14 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
-static int mpt_base_index = -1;
-static int last_drv_idx = -1;
-
static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
+/*
+ * Driver Callback Index's
+ */
+static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 last_drv_idx;
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Forward protos...
@@ -235,6 +236,23 @@ static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
return 0;
}
+/**
+ * mpt_get_cb_idx - obtain cb_idx for registered driver
+ * @dclass: class driver enum
+ *
+ * Returns cb_idx, or zero means it wasn't found
+ **/
+static u8
+mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
+{
+ u8 cb_idx;
+
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
+ if (MptDriverClass[cb_idx] == dclass)
+ return cb_idx;
+ return 0;
+}
+
/*
* Process turbo (context) reply...
*/
@@ -243,8 +261,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
{
MPT_FRAME_HDR *mf = NULL;
MPT_FRAME_HDR *mr = NULL;
- int req_idx = 0;
- int cb_idx;
+ u16 req_idx = 0;
+ u8 cb_idx;
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
ioc->name, pa));
@@ -256,7 +274,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
break;
case MPI_CONTEXT_REPLY_TYPE_LAN:
- cb_idx = mpt_lan_index;
+ cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
/*
* Blind set of mf to NULL here was fatal
* after lan_reply says "freeme"
@@ -277,7 +295,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
break;
case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
- cb_idx = mpt_stm_index;
+ cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
break;
default:
@@ -286,8 +304,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
}
/* Check for (valid) IO callback! */
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
goto out;
@@ -304,8 +322,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
{
MPT_FRAME_HDR *mf;
MPT_FRAME_HDR *mr;
- int req_idx;
- int cb_idx;
+ u16 req_idx;
+ u8 cb_idx;
int freeme;
u32 reply_dma_low;
@@ -331,7 +349,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
- DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
/* Check/log IOC log info
*/
@@ -350,8 +368,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
/* Check for (valid) IO callback! */
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
freeme = 0;
@@ -433,8 +451,9 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
#ifdef CONFIG_FUSION_LOGGING
if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
- dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
+ dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
+ ioc->name, mf));
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
}
#endif
@@ -499,8 +518,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
u16 status;
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
- status, le32_to_cpu(pReply->IOCLogInfo)));
+ dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+ ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
pCfg->status = status;
if (status == MPI_IOCSTATUS_SUCCESS) {
@@ -563,28 +582,27 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
* in order to register separate callbacks; one for "normal" SCSI IO;
* one for MptScsiTaskMgmt requests; one for Scan/DV requests.
*
- * Returns a positive integer valued "handle" in the
- * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
- * Any non-positive return value (including zero!) should be considered
- * an error by the caller.
+ * Returns u8 valued "handle" in the range (and S.O.D. order)
+ * {N,...,7,6,5,...,1} if successful.
+ * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
+ * considered an error by the caller.
*/
-int
+u8
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
{
- int i;
-
- last_drv_idx = -1;
+ u8 cb_idx;
+ last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
/*
* Search for empty callback slot in this order: {N,...,7,6,5,...,1}
* (slot/handle 0 is reserved!)
*/
- for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
- if (MptCallbacks[i] == NULL) {
- MptCallbacks[i] = cbfunc;
- MptDriverClass[i] = dclass;
- MptEvHandlers[i] = NULL;
- last_drv_idx = i;
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptCallbacks[cb_idx] == NULL) {
+ MptCallbacks[cb_idx] = cbfunc;
+ MptDriverClass[cb_idx] = dclass;
+ MptEvHandlers[cb_idx] = NULL;
+ last_drv_idx = cb_idx;
break;
}
}
@@ -601,9 +619,9 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
* module is unloaded.
*/
void
-mpt_deregister(int cb_idx)
+mpt_deregister(u8 cb_idx)
{
- if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+ if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
MptCallbacks[cb_idx] = NULL;
MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
MptEvHandlers[cb_idx] = NULL;
@@ -625,9 +643,9 @@ mpt_deregister(int cb_idx)
* Returns 0 for success.
*/
int
-mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -1;
MptEvHandlers[cb_idx] = ev_cbfunc;
@@ -645,9 +663,9 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
* or when its module is unloaded.
*/
void
-mpt_event_deregister(int cb_idx)
+mpt_event_deregister(u8 cb_idx)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
MptEvHandlers[cb_idx] = NULL;
@@ -665,9 +683,9 @@ mpt_event_deregister(int cb_idx)
* Returns 0 for success.
*/
int
-mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
+mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -1;
MptResetHandlers[cb_idx] = reset_func;
@@ -684,9 +702,9 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
* or when its module is unloaded.
*/
void
-mpt_reset_deregister(int cb_idx)
+mpt_reset_deregister(u8 cb_idx)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
MptResetHandlers[cb_idx] = NULL;
@@ -699,12 +717,12 @@ mpt_reset_deregister(int cb_idx)
* @cb_idx: MPT protocol driver index
*/
int
-mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
+mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
{
MPT_ADAPTER *ioc;
const struct pci_device_id *id;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -EINVAL;
MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
@@ -726,12 +744,12 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
* @cb_idx: MPT protocol driver index
*/
void
-mpt_device_driver_deregister(int cb_idx)
+mpt_device_driver_deregister(u8 cb_idx)
{
struct mpt_pci_driver *dd_cbfunc;
MPT_ADAPTER *ioc;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
@@ -749,14 +767,14 @@ mpt_device_driver_deregister(int cb_idx)
/**
* mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
* allocated per MPT adapter.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
*
* Returns pointer to a MPT request frame or %NULL if none are available
* or IOC is not active.
*/
MPT_FRAME_HDR*
-mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
+mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
{
MPT_FRAME_HDR *mf;
unsigned long flags;
@@ -766,7 +784,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
#ifdef MFCNT
if (!ioc->active)
- printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+ printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
+ "returning NULL!\n", ioc->name);
#endif
/* If interrupts are not attached, do not return a request frame */
@@ -781,13 +800,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
u.frame.linkage.list);
list_del(&mf->u.frame.linkage.list);
mf->u.frame.linkage.arg1 = 0;
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
/* u16! */
req_idx = req_offset / ioc->req_sz;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
- ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
+ /* Default, will be changed if necessary in SG generation */
+ ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
#ifdef MFCNT
ioc->mfcnt++;
#endif
@@ -798,14 +818,17 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
#ifdef MFCNT
if (mf == NULL)
- printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
+ printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
+ "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
+ ioc->req_depth);
mfcounter++;
if (mfcounter == PRINT_MF_COUNT)
- printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
+ printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
+ ioc->mfcnt, ioc->req_depth);
#endif
- dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
- ioc->name, handle, ioc->id, mf));
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
+ ioc->name, cb_idx, ioc->id, mf));
return mf;
}
@@ -813,7 +836,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
/**
* mpt_put_msg_frame - Send a protocol specific MPT request frame
* to a IOC.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
* @mf: Pointer to MPT request frame
*
@@ -821,14 +844,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
* specific MPT adapter.
*/
void
-mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
{
u32 mf_dma_addr;
int req_offset;
u16 req_idx; /* Request index */
/* ensure values are reset properly! */
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
/* u16! */
req_idx = req_offset / ioc->req_sz;
@@ -838,10 +861,44 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
+ "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
+ ioc->RequestNB[req_idx]));
CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
}
+/**
+ * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
+ * to a IOC using hi priority request queue.
+ * @cb_idx: Handle of registered MPT protocol driver
+ * @ioc: Pointer to MPT adapter structure
+ * @mf: Pointer to MPT request frame
+ *
+ * This routine posts a MPT request frame to the request post FIFO of a
+ * specific MPT adapter.
+ **/
+void
+mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+ u32 mf_dma_addr;
+ int req_offset;
+ u16 req_idx; /* Request index */
+
+ /* ensure values are reset properly! */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
+ req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
+ req_idx = req_offset / ioc->req_sz;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+ DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
+
+ mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
+ ioc->name, mf_dma_addr, req_idx));
+ CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_free_msg_frame - Place MPT request frame back on FreeQ.
@@ -899,7 +956,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_send_handshake_request - Send MPT request via doorbell handshake method.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
* @reqBytes: Size of the request in bytes
* @req: Pointer to MPT request frame
@@ -914,7 +971,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
* Returns 0 for success, non-zero for failure.
*/
int
-mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
+mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
{
int r = 0;
u8 *req_as_bytes;
@@ -934,7 +991,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
}
/* Make sure there are no doorbells */
@@ -953,7 +1010,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
return -5;
- dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
ioc->name, ii));
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1395,11 +1452,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
{
MPT_ADAPTER *ioc;
u8 __iomem *mem;
+ u8 __iomem *pmem;
unsigned long mem_phys;
unsigned long port;
u32 msize;
u32 psize;
int ii;
+ u8 cb_idx;
int r = -ENODEV;
u8 revision;
u8 pcixcmd;
@@ -1408,35 +1467,39 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
struct proc_dir_entry *dent, *ent;
#endif
+ if (mpt_debug_level)
+ printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+
+ if (pci_enable_device(pdev))
+ return r;
+
ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
if (ioc == NULL) {
printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
return -ENOMEM;
}
-
ioc->debug_level = mpt_debug_level;
- if (mpt_debug_level)
- printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
-
- if (pci_enable_device(pdev))
- return r;
+ ioc->id = mpt_ids++;
+ sprintf(ioc->name, "ioc%d", ioc->id);
- dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+ printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
+ ioc->name);
+ kfree(ioc);
return r;
}
if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": Using 64 bit consistent mask\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": Using 64 bit consistent mask\n", ioc->name));
} else {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": Not using 64 bit consistent mask\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": Not using 64 bit consistent mask\n", ioc->name));
}
ioc->alloc_total = sizeof(MPT_ADAPTER);
@@ -1475,7 +1538,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);
- ioc->id = mpt_ids++;
mem_phys = msize = 0;
port = psize = 0;
@@ -1501,25 +1563,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/*mem = ioremap(mem_phys, msize);*/
mem = ioremap(mem_phys, msize);
if (mem == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+ printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
kfree(ioc);
return -EINVAL;
}
ioc->memmap = mem;
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
- &ioc->facts, &ioc->pfacts[0]));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
+ ioc->name, &ioc->facts, &ioc->pfacts[0]));
ioc->mem_phys = mem_phys;
ioc->chip = (SYSIF_REGS __iomem *)mem;
/* Save Port IO values in case we need to do downloadboot */
- {
- u8 *pmem = (u8*)port;
- ioc->pio_mem_phys = port;
- ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
- }
+ ioc->pio_mem_phys = port;
+ pmem = (u8 __iomem *)port;
+ ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
@@ -1591,8 +1651,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
- sprintf(ioc->name, "ioc%d", ioc->id);
-
spin_lock_init(&ioc->FreeQlock);
/* Disable all! */
@@ -1609,9 +1667,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){
- printk(KERN_WARNING MYNAM
- ": WARNING - %s did not initialize properly! (%d)\n",
- ioc->name, r);
+ printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
+ ioc->name, r);
list_del(&ioc->list);
if (ioc->alt_ioc)
@@ -1623,10 +1680,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* call per device driver probe entry point */
- for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
- if(MptDeviceDriverHandlers[ii] &&
- MptDeviceDriverHandlers[ii]->probe) {
- MptDeviceDriverHandlers[ii]->probe(pdev,id);
+ for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ if(MptDeviceDriverHandlers[cb_idx] &&
+ MptDeviceDriverHandlers[cb_idx]->probe) {
+ MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
}
}
@@ -1663,7 +1720,7 @@ mpt_detach(struct pci_dev *pdev)
{
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
char pname[32];
- int ii;
+ u8 cb_idx;
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL);
@@ -1673,10 +1730,10 @@ mpt_detach(struct pci_dev *pdev)
remove_proc_entry(pname, NULL);
/* call per device driver remove entry point */
- for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
- if(MptDeviceDriverHandlers[ii] &&
- MptDeviceDriverHandlers[ii]->remove) {
- MptDeviceDriverHandlers[ii]->remove(pdev);
+ for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ if(MptDeviceDriverHandlers[cb_idx] &&
+ MptDeviceDriverHandlers[cb_idx]->remove) {
+ MptDeviceDriverHandlers[cb_idx]->remove(pdev);
}
}
@@ -1788,7 +1845,7 @@ mpt_resume(struct pci_dev *pdev)
#endif
static int
-mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
+mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
{
if ((MptDriverClass[index] == MPTSPI_DRIVER &&
ioc->bus_type != SPI) ||
@@ -1830,14 +1887,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
int hard;
int rc=0;
int ii;
+ u8 cb_idx;
int handlers;
int ret = 0;
int reset_alt_ioc_active = 0;
int irq_allocated = 0;
u8 *a;
- printk(KERN_INFO MYNAM ": Initiating %s %s\n",
- ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+ printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
+ reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
/* Disable reply interrupts (also blocks FreeQ) */
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
@@ -1858,21 +1916,19 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
if (hard_reset_done == -4) {
- printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
- ioc->name);
+ printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
+ ioc->name);
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": alt-%s reply irq re-enabled\n",
- ioc->alt_ioc->name));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
}
} else {
- printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
- ioc->name);
+ printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
}
return -1;
}
@@ -1884,9 +1940,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
alt_ioc_ready = 1;
else
- printk(KERN_WARNING MYNAM
- ": alt-%s: Not ready WARNING!\n",
- ioc->alt_ioc->name);
+ printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
}
for (ii=0; ii<5; ii++) {
@@ -1897,7 +1951,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (ii == 5) {
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Retry IocFacts failed rc=%x\n", ioc->name, rc));
ret = -2;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
MptDisplayIocCapabilities(ioc);
@@ -1906,14 +1961,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (alt_ioc_ready) {
if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
/* Retry - alt IOC was initialized once
*/
rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
}
if (rc) {
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
@@ -1931,13 +1986,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (ioc->pcidev->irq) {
if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
- ioc->name);
+ ioc->name);
rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
- IRQF_SHARED, ioc->name, ioc);
+ IRQF_SHARED, ioc->name, ioc);
if (rc < 0) {
printk(MYIOC_s_ERR_FMT "Unable to allocate "
- "interrupt %d!\n", ioc->name,
- ioc->pcidev->irq);
+ "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
if (mpt_msi_enable)
pci_disable_msi(ioc->pcidev);
return -EBUSY;
@@ -1946,8 +2000,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ioc->pci_irq = ioc->pcidev->irq;
pci_set_master(ioc->pcidev); /* ?? */
pci_set_drvdata(ioc->pcidev, ioc);
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
- "%d\n", ioc->name, ioc->pcidev->irq));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
+ "%d\n", ioc->name, ioc->pcidev->irq));
}
}
@@ -1966,8 +2020,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ret = -4;
// NEW!
if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
- printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+ ioc->alt_ioc->name, rc);
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
}
@@ -1976,16 +2030,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
- printk(KERN_WARNING MYNAM
- ": alt-%s: (%d) init failure WARNING!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
+ ioc->alt_ioc->name, rc);
}
}
if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
if (ioc->upload_fw) {
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "firmware upload required!\n", ioc->name));
+ "firmware upload required!\n", ioc->name));
/* Controller is not operational, cannot do upload
*/
@@ -2001,12 +2054,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* mpt_diag_reset)
*/
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": mpt_upload: alt_%s has cached_fw=%p \n",
- ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+ "mpt_upload: alt_%s has cached_fw=%p \n",
+ ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
ioc->alt_ioc->cached_fw = NULL;
}
} else {
- printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+ printk(MYIOC_s_WARN_FMT
+ "firmware upload failure!\n", ioc->name);
ret = -5;
}
}
@@ -2021,8 +2075,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt) */
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
- ioc->alt_ioc->name));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
+ ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
}
@@ -2075,10 +2129,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
(void) GetLanConfigPages(ioc);
a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "LanAddr = %02X:%02X:%02X:"
- "%02X:%02X:%02X\n",
- ioc->name, a[5], a[4],
- a[3], a[2], a[1], a[0] ));
+ "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
}
} else {
@@ -2114,20 +2166,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
*/
if (hard_reset_done) {
rc = handlers = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if ((ret == 0) && MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if ((ret == 0) && MptResetHandlers[cb_idx]) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling IOC post_reset handler #%d\n",
- ioc->name, ii));
- rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
+ "Calling IOC post_reset handler #%d\n",
+ ioc->name, cb_idx));
+ rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
handlers++;
}
- if (alt_ioc_ready && MptResetHandlers[ii]) {
+ if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling alt-%s post_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
+ "Calling IOC post_reset handler #%d\n",
+ ioc->alt_ioc->name, cb_idx));
+ rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
}
}
@@ -2166,8 +2218,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
" searching for devfn match on %x or %x\n",
- ioc->name, pci_name(pdev), pdev->bus->number,
- pdev->devfn, func-1, func+1));
+ ioc->name, pci_name(pdev), pdev->bus->number,
+ pdev->devfn, func-1, func+1));
peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
if (!peer) {
@@ -2181,15 +2233,15 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
if (_pcidev == peer) {
/* Paranoia checks */
if (ioc->alt_ioc != NULL) {
- printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
ioc->name, ioc->alt_ioc->name);
break;
} else if (ioc_srch->alt_ioc != NULL) {
- printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
ioc_srch->name, ioc_srch->alt_ioc->name);
break;
}
- dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
ioc->name, ioc_srch->name));
ioc_srch->alt_ioc = ioc;
ioc->alt_ioc = ioc_srch;
@@ -2210,10 +2262,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
int ret;
if (ioc->cached_fw != NULL) {
- ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
+ ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
- printk(KERN_WARNING MYNAM
- ": firmware downloadboot failure (%d)!\n", ret);
+ printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
+ ioc->name, ret);
}
}
@@ -2225,8 +2278,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->alloc != NULL) {
sz = ioc->alloc_sz;
- dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
- ioc->name, ioc->alloc, ioc->alloc_sz));
+ dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
+ ioc->name, ioc->alloc, ioc->alloc_sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->alloc, ioc->alloc_dma);
ioc->reply_frames = NULL;
@@ -2286,15 +2339,14 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->HostPageBuffer != NULL) {
if((ret = mpt_host_page_access_control(ioc,
MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
- printk(KERN_ERR MYNAM
- ": %s: host page buffers free failed (%d)!\n",
- __FUNCTION__, ret);
+ printk(MYIOC_s_ERR_FMT
+ "host page buffers free failed (%d)!\n",
+ ioc->name, ret);
}
- dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
+ dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
- ioc->HostPageBuffer,
- ioc->HostPageBuffer_dma);
+ ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
ioc->HostPageBuffer = NULL;
ioc->HostPageBuffer_sz = 0;
ioc->alloc_total -= ioc->HostPageBuffer_sz;
@@ -2336,7 +2388,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
#if defined(CONFIG_MTRR) && 0
if (ioc->mtrr_reg > 0) {
mtrr_del(ioc->mtrr_reg, 0, 0);
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
}
#endif
@@ -2344,8 +2396,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
list_del(&ioc->list);
sz_last = ioc->alloc_total;
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
+ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
@@ -2424,7 +2476,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
/* Get current [raw] IOC state */
ioc_state = mpt_GetIocState(ioc, 0);
- dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+ dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
/*
* Check to see if IOC got left/stuck in doorbell handshake
@@ -2446,9 +2498,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
statefault = 2;
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
- ioc->name);
- printk(KERN_WARNING " FAULT code = %04xh\n",
- ioc_state & MPI_DOORBELL_DATA_MASK);
+ ioc->name);
+ printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
+ ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
}
/*
@@ -2464,9 +2516,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
* Else, fall through to KickStart case
*/
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
- dinitprintk(ioc, printk(KERN_INFO MYNAM
- ": whoinit 0x%x statefault %d force %d\n",
- whoinit, statefault, force));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "whoinit 0x%x statefault %d force %d\n",
+ ioc->name, whoinit, statefault, force));
if (whoinit == MPI_WHOINIT_PCI_PEER)
return -4;
else {
@@ -2549,7 +2601,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
/* Get! */
s = CHIPREG_READ32(&ioc->chip->Doorbell);
-// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
sc = s & MPI_IOC_STATE_MASK;
/* Save! */
@@ -2581,9 +2632,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
- ioc->name,
- ioc->last_state );
+ printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
+ ioc->name, ioc->last_state );
return -44;
}
@@ -2703,8 +2753,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
}
ioc->NBShiftFactor = shiftFactor;
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
- ioc->name, vv, shiftFactor, r));
+ "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
+ ioc->name, vv, shiftFactor, r));
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
/*
@@ -2757,9 +2807,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
- ioc->name,
- ioc->last_state );
+ printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
+ ioc->name, ioc->last_state );
return -4;
}
@@ -2934,7 +2983,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
state = mpt_GetIocState(ioc, 1);
count++;
}
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
ioc->aen_event_read_flag=0;
@@ -3027,10 +3076,9 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
int sz;
sz = ioc->facts.FWImageSize;
- dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
- ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
- pci_free_consistent(ioc->pcidev, sz,
- ioc->cached_fw, ioc->cached_fw_dma);
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
ioc->cached_fw = NULL;
return;
@@ -3054,7 +3102,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
static int
mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
{
- u8 request[ioc->req_sz];
u8 reply[sizeof(FWUploadReply_t)];
FWUpload_t *prequest;
FWUploadReply_t *preply;
@@ -3071,8 +3118,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
mpt_alloc_fw_memory(ioc, sz);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
- ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
if (ioc->cached_fw == NULL) {
/* Major Failure.
@@ -3080,11 +3127,16 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
return -ENOMEM;
}
- prequest = (FWUpload_t *)&request;
- preply = (FWUploadReply_t *)&reply;
+ prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
+ kzalloc(ioc->req_sz, GFP_KERNEL);
+ if (!prequest) {
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
+ "while allocating memory \n", ioc->name));
+ mpt_free_fw_memory(ioc);
+ return -ENOMEM;
+ }
- /* Destination... */
- memset(prequest, 0, ioc->req_sz);
+ preply = (FWUploadReply_t *)&reply;
reply_sz = sizeof(reply);
memset(preply, 0, reply_sz);
@@ -3096,21 +3148,22 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
ptcsge->DetailsLength = 12;
ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
ptcsge->ImageSize = cpu_to_le32(sz);
+ ptcsge++;
sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
- mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
+ mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
- prequest, sgeoffset));
- DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+ ioc->name, prequest, sgeoffset));
+ DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
cmdStatus = -EFAULT;
if (ii == 0) {
@@ -3135,6 +3188,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
ioc->name));
mpt_free_fw_memory(ioc);
}
+ kfree(prequest);
return cmdStatus;
}
@@ -3381,7 +3435,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
u32 ioc_state=0;
int cnt,cntdn;
- dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
if (ioc->bus_type == SPI) {
/* Always issue a Msg Unit Reset first. This will clear some
* SCSI bus hang conditions.
@@ -3400,7 +3454,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
return hard_reset_done;
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
- ioc->name));
+ ioc->name));
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
for (cnt=0; cnt<cntdn; cnt++) {
@@ -3417,8 +3471,8 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
}
}
- printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
- ioc->name, ioc_state);
+ dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
+ ioc->name, mpt_GetIocState(ioc, 0)));
return -1;
}
@@ -3560,20 +3614,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
* MptResetHandlers[] registered yet.
*/
{
- int ii;
+ u8 cb_idx;
int r = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling IOC pre_reset handler #%d\n",
- ioc->name, ii));
- r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
+ ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
if (ioc->alt_ioc) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling alt-%s pre_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
+ ioc->name, ioc->alt_ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
}
}
@@ -3606,8 +3660,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
if ((count = mpt_downloadboot(ioc,
(MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
- printk(KERN_WARNING MYNAM
- ": firmware downloadboot failure (%d)!\n", count);
+ printk(MYIOC_s_WARN_FMT
+ "firmware downloadboot failure (%d)!\n", ioc->name, count);
}
} else {
@@ -3750,8 +3804,8 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
if (sleepFlag != CAN_SLEEP)
count *= 10;
- printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
- ioc->name, (int)((count+5)/HZ));
+ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+ ioc->name, (int)((count+5)/HZ));
return -ETIME;
}
@@ -4144,7 +4198,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
}
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
@@ -4349,7 +4403,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
#endif
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
- DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
ioc->name, t, u16cnt/2));
@@ -4824,8 +4878,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
- ddvprintk(ioc, printk(KERN_INFO MYNAM
- " :%s noQas due to Capabilities=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "noQas due to Capabilities=%x\n",
ioc->name, pPP0->Capabilities));
}
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4888,6 +4942,38 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
/* Nvram data is left with INVALID mark
*/
rc = 1;
+ } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
+
+ /* This is an ATTO adapter, read Page2 accordingly
+ */
+ ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
+ ATTODeviceInfo_t *pdevice = NULL;
+ u16 ATTOFlags;
+
+ /* Save the Port Page 2 data
+ * (reformat into a 32bit quantity)
+ */
+ for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+ pdevice = &pPP2->DeviceSettings[ii];
+ ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
+ data = 0;
+
+ /* Translate ATTO device flags to LSI format
+ */
+ if (ATTOFlags & ATTOFLAG_DISC)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
+ if (ATTOFlags & ATTOFLAG_ID_ENB)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
+ if (ATTOFlags & ATTOFLAG_LUN_ENB)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
+ if (ATTOFlags & ATTOFLAG_TAGGED)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
+ if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
+
+ data = (data << 16) | (pdevice->Period << 8) | 10;
+ ioc->spi_data.nvram[ii] = data;
+ }
} else {
SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
MpiDeviceInfo_t *pdevice = NULL;
@@ -5701,10 +5787,10 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
CONFIGPARMS *pCfg;
unsigned long flags;
- dprintk(ioc, printk(KERN_DEBUG MYNAM
- ": IOC %s_reset routed to MPT base driver!\n",
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": IOC %s_reset routed to MPT base driver!\n",
+ ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
if (reset_phase == MPT_IOC_SETUP_RESET) {
;
@@ -5843,7 +5929,7 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo
static int
procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
{
- int ii;
+ u8 cb_idx;
int scsi, fc, sas, lan, ctl, targ, dmp;
char *drvname;
int len;
@@ -5852,10 +5938,10 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
len += sprintf(buf+len, " Fusion MPT base driver\n");
scsi = fc = sas = lan = ctl = targ = dmp = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
drvname = NULL;
- if (MptCallbacks[ii]) {
- switch (MptDriverClass[ii]) {
+ if (MptCallbacks[cb_idx]) {
+ switch (MptDriverClass[cb_idx]) {
case MPTSPI_DRIVER:
if (!scsi++) drvname = "SPI host";
break;
@@ -6099,26 +6185,25 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
* For all other protocol drivers, this is a no-op.
*/
{
- int ii;
+ u8 cb_idx;
int r = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
- ioc->name, ii));
- r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
+ ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
if (ioc->alt_ioc) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+ ioc->name, ioc->alt_ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
}
}
}
}
if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
- printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
- rc, ioc->name);
+ printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
}
ioc->reload_fw = 0;
if (ioc->alt_ioc)
@@ -6515,6 +6600,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
u32 evData0 = 0;
// u32 evCtx;
int ii;
+ u8 cb_idx;
int r = 0;
int handlers = 0;
char evStr[EVENT_DESCR_STR_SZ];
@@ -6537,12 +6623,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
evStr));
#ifdef CONFIG_FUSION_LOGGING
- devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
- ": Event data:\n"));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": Event data:\n", ioc->name));
for (ii = 0; ii < evDataLen; ii++)
devtverboseprintk(ioc, printk(" %08x",
le32_to_cpu(pEventReply->Data[ii])));
- devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+ devtverboseprintk(ioc, printk("\n"));
#endif
/*
@@ -6595,11 +6681,11 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
/*
* Call each currently registered protocol event handler.
*/
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptEvHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptEvHandlers[cb_idx]) {
devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
- ioc->name, ii));
- r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
+ ioc->name, cb_idx));
+ r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
handlers++;
}
}
@@ -7034,8 +7120,8 @@ mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
if (!desc)
return;
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
- ioc->name, ioc_status, desc, extend_desc);
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
+ ioc->name, ioc_status, desc, extend_desc));
}
/**
@@ -7261,7 +7347,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
if (!desc)
return;
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
+ ioc->name, status, desc));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7283,14 +7370,13 @@ EXPORT_SYMBOL(mpt_device_driver_register);
EXPORT_SYMBOL(mpt_device_driver_deregister);
EXPORT_SYMBOL(mpt_get_msg_frame);
EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
EXPORT_SYMBOL(mpt_free_msg_frame);
EXPORT_SYMBOL(mpt_add_sge);
EXPORT_SYMBOL(mpt_send_handshake_request);
EXPORT_SYMBOL(mpt_verify_adapter);
EXPORT_SYMBOL(mpt_GetIocState);
EXPORT_SYMBOL(mpt_print_ioc_summary);
-EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
EXPORT_SYMBOL(mpt_HardResetHandler);
EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_findImVolumes);
@@ -7308,16 +7394,16 @@ EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
static int __init
fusion_init(void)
{
- int i;
+ u8 cb_idx;
show_mptmod_ver(my_NAME, my_VERSION);
printk(KERN_INFO COPYRIGHT "\n");
- for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
- MptCallbacks[i] = NULL;
- MptDriverClass[i] = MPTUNKNOWN_DRIVER;
- MptEvHandlers[i] = NULL;
- MptResetHandlers[i] = NULL;
+ for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ MptCallbacks[cb_idx] = NULL;
+ MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+ MptEvHandlers[cb_idx] = NULL;
+ MptResetHandlers[cb_idx] = NULL;
}
/* Register ourselves (mptbase) in order to facilitate
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 15ff2264584..d7682e083f5 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -3,9 +3,9 @@
* High performance SCSI + LAN / Fibre Channel device drivers.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -68,15 +68,15 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#ifndef MODULEAUTHOR
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#endif
#ifndef COPYRIGHT
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.05"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05"
+#define MPT_LINUX_VERSION_COMMON "3.04.06"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.06"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -186,6 +186,7 @@
* MPT drivers. NOTE: Users of these macro defs must
* themselves define their own MYNAM.
*/
+#define MYIOC_s_FMT MYNAM ": %s: "
#define MYIOC_s_DEBUG_FMT KERN_DEBUG MYNAM ": %s: "
#define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: "
#define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: "
@@ -194,6 +195,35 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
+ * ATTO UL4D associated structures and defines
+ */
+#define ATTOFLAG_DISC 0x0001
+#define ATTOFLAG_TAGGED 0x0002
+#define ATTOFLAG_WIDE_ENB 0x0008
+#define ATTOFLAG_ID_ENB 0x0010
+#define ATTOFLAG_LUN_ENB 0x0060
+
+typedef struct _ATTO_DEVICE_INFO
+{
+ u8 Offset; /* 00h */
+ u8 Period; /* 01h */
+ u16 ATTOFlags; /* 02h */
+} ATTO_DEVICE_INFO, MPI_POINTER PTR_ATTO_DEVICE_INFO,
+ ATTODeviceInfo_t, MPI_POINTER pATTODeviceInfo_t;
+
+typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ u16 PortFlags; /* 04h */
+ u16 Unused1; /* 06h */
+ u32 Unused2; /* 08h */
+ ATTO_DEVICE_INFO DeviceSettings[16]; /* 0Ch */
+} fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2,
+ ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
* MPT protocol driver defs...
*/
typedef enum {
@@ -307,7 +337,8 @@ typedef struct _SYSIF_REGS
u32 Reserved2[2]; /* 38-3F reserved for future use */
u32 RequestFifo; /* 40 Request Post/Free FIFO */
u32 ReplyFifo; /* 44 Reply Post/Free FIFO */
- u32 Reserved3[2]; /* 48-4F reserved for future use */
+ u32 RequestHiPriFifo; /* 48 Hi Priority Request FIFO */
+ u32 Reserved3; /* 4C-4F reserved for future use */
u32 HostIndex; /* 50 Host Index register */
u32 Reserved4[15]; /* 54-8F */
u32 Fubar; /* 90 For Fubar usage */
@@ -649,9 +680,9 @@ typedef struct _MPT_ADAPTER
u8 reload_fw; /* Force a FW Reload on next reset */
u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
u8 pad1[4];
- int DoneCtx;
- int TaskCtx;
- int InternalCtx;
+ u8 DoneCtx;
+ u8 TaskCtx;
+ u8 InternalCtx;
spinlock_t initializing_hba_lock;
int initializing_hba_lock_flag;
struct list_head list;
@@ -668,10 +699,14 @@ typedef struct _MPT_ADAPTER
struct work_struct fc_setup_reset_work;
struct list_head fc_rports;
+ struct work_struct fc_lsc_work;
+ u8 fc_link_speed[2];
spinlock_t fc_rescan_work_lock;
struct work_struct fc_rescan_work;
char fc_rescan_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *fc_rescan_work_q;
+ struct scsi_cmnd **ScsiLookup;
+ spinlock_t scsi_lookup_lock;
} MPT_ADAPTER;
/*
@@ -785,7 +820,6 @@ typedef struct _MPT_SCSI_HOST {
MPT_ADAPTER *ioc;
int port;
u32 pad0;
- struct scsi_cmnd **ScsiLookup;
MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
struct timer_list timer;
/* Pool of memory for holding SCpnts before doing
@@ -853,20 +887,21 @@ extern void mpt_detach(struct pci_dev *pdev);
extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mpt_resume(struct pci_dev *pdev);
#endif
-extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
-extern void mpt_deregister(int cb_idx);
-extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
-extern void mpt_event_deregister(int cb_idx);
-extern int mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
-extern void mpt_reset_deregister(int cb_idx);
-extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx);
-extern void mpt_device_driver_deregister(int cb_idx);
-extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc);
+extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void mpt_deregister(u8 cb_idx);
+extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void mpt_event_deregister(u8 cb_idx);
+extern int mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func);
+extern void mpt_reset_deregister(u8 cb_idx);
+extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx);
+extern void mpt_device_driver_deregister(u8 cb_idx);
+extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc);
extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
-extern int mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
+extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
@@ -884,9 +919,6 @@ extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhys
extern struct list_head ioc_list;
extern struct proc_dir_entry *mpt_proc_root_dir;
-extern int mpt_lan_index; /* needed by mptlan.c */
-extern int mpt_stm_index; /* needed by mptstm.c */
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 89695e705bd..6029509702d 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptctl.c
* mpt Ioctl driver.
- * For use with LSI Logic PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -66,8 +66,8 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation"
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#include "mptbase.h"
#include "mptctl.h"
@@ -83,7 +83,7 @@ MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int mptctl_id = -1;
+static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
@@ -181,7 +181,6 @@ static inline int
mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
{
int rc = 0;
-// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
if (nonblock) {
if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
@@ -190,7 +189,6 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
rc = -ERESTARTSYS;
}
-// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc));
return rc;
}
@@ -342,7 +340,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
SCSITaskMgmt_t *pScsiTm;
MPT_SCSI_HOST *hd;
int ii;
- int retval;
+ int retval=0;
ioctl->reset &= ~MPTCTL_RESET_OK;
@@ -350,7 +348,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
if (ioctl->ioc->sh == NULL)
return -EPERM;
- hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
+ hd = shost_priv(ioctl->ioc->sh);
if (hd == NULL)
return -EPERM;
@@ -395,12 +393,19 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
ioctl->wait_done=0;
- if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
- goto mptctl_bus_reset_done;
+
+ if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval != 0) {
+ dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+ " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+ hd->ioc, mf));
+ goto mptctl_bus_reset_done;
+ }
}
/* Now wait for the command to complete */
@@ -444,7 +449,7 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
MPT_SCSI_HOST * hd;
unsigned long flags;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (hd == NULL)
return;
@@ -468,7 +473,7 @@ static int
mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
MPT_IOCTL *ioctl = ioc->ioctl;
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name,
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -574,7 +579,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
MPT_ADAPTER *iocp = NULL;
if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
- printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
+ printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
"Unable to copy mpt_ioctl_header data @ %p\n",
__FILE__, __LINE__, uhdr);
return -EFAULT;
@@ -587,13 +592,13 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
iocnumX = khdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnumX);
return -ENODEV;
}
if (!iocp->active) {
- printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
__FILE__, __LINE__);
return -EFAULT;
}
@@ -660,14 +665,14 @@ static int mptctl_do_reset(unsigned long arg)
MPT_ADAPTER *iocp;
if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
- printk(KERN_ERR "%s@%d::mptctl_do_reset - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
__FILE__, __LINE__, urinfo);
return -EFAULT;
}
if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
- printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
__FILE__, __LINE__, krinfo.hdr.iocnum);
return -ENODEV; /* (-6) No such device or address */
}
@@ -676,8 +681,8 @@ static int mptctl_do_reset(unsigned long arg)
iocp->name));
if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
- printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
- __FILE__, __LINE__);
+ printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n",
+ iocp->name, __FILE__, __LINE__);
return -1;
}
@@ -708,7 +713,7 @@ mptctl_fw_download(unsigned long arg)
struct mpt_fw_xfer kfwdl;
if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
- printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+ printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - "
"Unable to copy mpt_fw_xfer struct @ %p\n",
__FILE__, __LINE__, ufwdl);
return -EFAULT;
@@ -756,7 +761,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
pFWDownloadReply_t ReplyMsg = NULL;
if (mpt_verify_adapter(ioc, &iocp) < 0) {
- printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n", ioc);
+ printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
+ ioc);
return -ENODEV; /* (-6) No such device or address */
} else {
@@ -868,9 +874,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
n++;
if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
- printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
- "Unable to copy f/w buffer hunk#%d @ %p\n",
- __FILE__, __LINE__, n, ufwbuf);
+ printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
+ "Unable to copy f/w buffer hunk#%d @ %p\n",
+ iocp->name, __FILE__, __LINE__, n, ufwbuf);
goto fwdl_out;
}
fw_bytes_copied += bl->len;
@@ -906,21 +912,22 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
if (iocstat == MPI_IOCSTATUS_SUCCESS) {
- printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+ printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
return 0;
} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
- printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n",
- iocp->name);
- printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+ printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
+ iocp->name);
+ printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
+ iocp->name);
return -EBADRQC;
} else if (iocstat == MPI_IOCSTATUS_BUSY) {
- printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name);
- printk(KERN_WARNING MYNAM ": (try again later?)\n");
+ printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
+ printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
return -EBUSY;
} else {
- printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n",
- iocp->name, iocstat);
- printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+ printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
+ iocp->name, iocstat);
+ printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
return -ENOMSG;
}
return 0;
@@ -970,10 +977,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
* structures for the SG elements.
*/
i = MAX_SGL_BYTES / 8;
- buflist = kmalloc(i, GFP_USER);
- if (buflist == NULL)
+ buflist = kzalloc(i, GFP_USER);
+ if (!buflist)
return NULL;
- memset(buflist, 0, i);
buflist_ent = 0;
/* Allocate a single block of memory to store the sg elements and
@@ -1008,10 +1014,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
if (buflist[buflist_ent].kptr == NULL) {
alloc_sz = alloc_sz / 2;
if (alloc_sz == 0) {
- printk(KERN_WARNING MYNAM "-SG: No can do - "
- "not enough memory! :-(\n");
- printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
- numfrags);
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+ "not enough memory! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+ ioc->name, numfrags);
goto free_and_fail;
}
continue;
@@ -1034,18 +1040,19 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
/* Need to chain? */
if (fragcnt == sg_spill) {
- printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n");
- printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
+ printk(MYIOC_s_WARN_FMT
+ "-SG: No can do - " "Chain required! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
goto free_and_fail;
}
/* overflow check... */
if (numfrags*8 > MAX_SGL_BYTES){
/* GRRRRR... */
- printk(KERN_WARNING MYNAM "-SG: No can do - "
- "too many SG frags! :-(\n");
- printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
- numfrags);
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+ "too many SG frags! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+ ioc->name, numfrags);
goto free_and_fail;
}
}
@@ -1066,8 +1073,6 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
free_and_fail:
if (sglbuf != NULL) {
- int i;
-
for (i = 0; i < numfrags; i++) {
dma_addr_t dma_addr;
u8 *kptr;
@@ -1170,7 +1175,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
int cim_rev;
u8 revision;
struct scsi_device *sdev;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
/* Add of PCI INFO results in unaligned access for
* IA64 and Sparc. Reset long to int. Return no PCI
@@ -1189,13 +1194,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
karg = kmalloc(data_size, GFP_KERNEL);
if (karg == NULL) {
- printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
+ printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
__FILE__, __LINE__);
return -ENOMEM;
}
if (copy_from_user(karg, uarg, data_size)) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - "
"Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
kfree(karg);
@@ -1204,7 +1209,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
kfree(karg);
return -ENODEV;
@@ -1212,9 +1217,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
/* Verify the data transfer size is correct. */
if (karg->hdr.maxDataSize != data_size) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
"Structure size mismatch. Command not completed.\n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
kfree(karg);
return -EFAULT;
}
@@ -1265,8 +1270,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
karg->numDevices = 0;
if (ioc->sh) {
shost_for_each_device(sdev, ioc->sh) {
- vdev = sdev->hostdata;
- if (vdev->vtarget->tflags &
+ vdevice = sdev->hostdata;
+ if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
karg->numDevices++;
@@ -1290,9 +1295,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, karg, data_size)) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
kfree(karg);
return -EFAULT;
}
@@ -1317,7 +1322,7 @@ mptctl_gettargetinfo (unsigned long arg)
struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
struct mpt_ioctl_targetinfo karg;
MPT_ADAPTER *ioc;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
char *pmem;
int *pdata;
int iocnum;
@@ -1329,7 +1334,7 @@ mptctl_gettargetinfo (unsigned long arg)
struct scsi_device *sdev;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1337,7 +1342,7 @@ mptctl_gettargetinfo (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1353,8 +1358,8 @@ mptctl_gettargetinfo (unsigned long arg)
port = karg.hdr.port;
if (maxWordsLeft <= 0) {
- printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
- __FILE__, __LINE__);
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
@@ -1372,13 +1377,12 @@ mptctl_gettargetinfo (unsigned long arg)
* 15- 8: Bus Number
* 7- 0: Target ID
*/
- pmem = kmalloc(numBytes, GFP_KERNEL);
- if (pmem == NULL) {
- printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
- __FILE__, __LINE__);
+ pmem = kzalloc(numBytes, GFP_KERNEL);
+ if (!pmem) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
- memset(pmem, 0, numBytes);
pdata = (int *) pmem;
/* Get number of devices
@@ -1387,13 +1391,13 @@ mptctl_gettargetinfo (unsigned long arg)
shost_for_each_device(sdev, ioc->sh) {
if (!maxWordsLeft)
continue;
- vdev = sdev->hostdata;
- if (vdev->vtarget->tflags &
+ vdevice = sdev->hostdata;
+ if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
- lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun;
- *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) +
- (vdev->vtarget->id ));
+ lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
+ *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
+ (vdevice->vtarget->id ));
pdata++;
numDevices++;
--maxWordsLeft;
@@ -1405,9 +1409,9 @@ mptctl_gettargetinfo (unsigned long arg)
*/
if (copy_to_user((char __user *)arg, &karg,
sizeof(struct mpt_ioctl_targetinfo))) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
kfree(pmem);
return -EFAULT;
}
@@ -1415,9 +1419,9 @@ mptctl_gettargetinfo (unsigned long arg)
/* Copy the remaining data from kernel memory to user memory
*/
if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, pdata);
+ ioc->name, __FILE__, __LINE__, pdata);
kfree(pmem);
return -EFAULT;
}
@@ -1444,7 +1448,7 @@ mptctl_readtest (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
- printk(KERN_ERR "%s@%d::mptctl_readtest - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
"Unable to read in mpt_ioctl_test struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1452,7 +1456,7 @@ mptctl_readtest (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1476,9 +1480,9 @@ mptctl_readtest (unsigned long arg)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
- printk(KERN_ERR "%s@%d::mptctl_readtest - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
"Unable to write out mpt_ioctl_test struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -1505,7 +1509,7 @@ mptctl_eventquery (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
- printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1513,7 +1517,7 @@ mptctl_eventquery (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1526,9 +1530,9 @@ mptctl_eventquery (unsigned long arg)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
- printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
return 0;
@@ -1544,7 +1548,7 @@ mptctl_eventenable (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
- printk(KERN_ERR "%s@%d::mptctl_eventenable - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1552,7 +1556,7 @@ mptctl_eventenable (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1563,12 +1567,13 @@ mptctl_eventenable (unsigned long arg)
/* Have not yet allocated memory - do so now.
*/
int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
- ioc->events = kmalloc(sz, GFP_KERNEL);
- if (ioc->events == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+ ioc->events = kzalloc(sz, GFP_KERNEL);
+ if (!ioc->events) {
+ printk(MYIOC_s_ERR_FMT
+ ": ERROR - Insufficient memory to add adapter!\n",
+ ioc->name);
return -ENOMEM;
}
- memset(ioc->events, 0, sz);
ioc->alloc_total += sz;
ioc->eventContext = 0;
@@ -1592,7 +1597,7 @@ mptctl_eventreport (unsigned long arg)
int numBytes, maxEvents, max;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
- printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1600,7 +1605,7 @@ mptctl_eventreport (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1626,9 +1631,9 @@ mptctl_eventreport (unsigned long arg)
*/
numBytes = max * sizeof(MPT_IOCTL_EVENTS);
if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
- printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
- __FILE__, __LINE__, ioc->events);
+ ioc->name, __FILE__, __LINE__, ioc->events);
return -EFAULT;
}
@@ -1646,7 +1651,7 @@ mptctl_replace_fw (unsigned long arg)
int newFwSize;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
- printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1654,7 +1659,7 @@ mptctl_replace_fw (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1684,9 +1689,9 @@ mptctl_replace_fw (unsigned long arg)
/* Copy the data from user memory to kernel space
*/
if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
- printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
"Unable to read in mpt_ioctl_replace_fw image "
- "@ %p\n", __FILE__, __LINE__, uarg);
+ "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
mpt_free_fw_memory(ioc);
return -EFAULT;
}
@@ -1720,7 +1725,7 @@ mptctl_mpt_command (unsigned long arg)
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
- printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
"Unable to read in mpt_ioctl_command struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1728,7 +1733,7 @@ mptctl_mpt_command (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1769,21 +1774,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ulong timeout;
struct scsi_device *sdev;
+ /* bufIn and bufOut are used for user to kernel space transfers
+ */
bufIn.kptr = bufOut.kptr = NULL;
+ bufIn.len = bufOut.len = 0;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
if (!ioc->ioctl) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
"No memory available during driver init.\n",
__FILE__, __LINE__);
return -ENOMEM;
} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
"Busy with IOC Reset \n", __FILE__, __LINE__);
return -EBUSY;
}
@@ -1797,9 +1805,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
sz += sizeof(dma_addr_t) + sizeof(u32);
if (sz > ioc->req_sz) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Request frame too large (%d) maximum (%d)\n",
- __FILE__, __LINE__, sz, ioc->req_sz);
+ ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
return -EFAULT;
}
@@ -1817,9 +1825,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
* Request frame in user space
*/
if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to read MF from mpt_ioctl_command struct @ %p\n",
- __FILE__, __LINE__, mfPtr);
+ ioc->name, __FILE__, __LINE__, mfPtr);
rc = -EFAULT;
goto done_free_mem;
}
@@ -1870,17 +1878,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
if (pScsiReq->TargetID > id) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Target ID out of bounds. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -ENODEV;
goto done_free_mem;
}
if (pScsiReq->Bus >= ioc->number_of_buses) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Target Bus out of bounds. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -ENODEV;
goto done_free_mem;
}
@@ -1932,9 +1940,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ioc->ioctl->id = pScsiReq->TargetID;
} else {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -1951,9 +1959,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
case MPI_FUNCTION_SATA_PASSTHROUGH:
if (!ioc->sh) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2010,9 +2018,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ioc->ioctl->reset = MPTCTL_RESET_OK;
ioc->ioctl->id = pScsiReq->TargetID;
} else {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2021,10 +2029,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
case MPI_FUNCTION_SCSI_TASK_MGMT:
{
MPT_SCSI_HOST *hd = NULL;
- if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver not loaded or SCSI host not found. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
} else if (mptctl_set_tm_flags(hd) != 0) {
@@ -2055,9 +2063,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
(pInit->HostMfaHighAddr != high_addr) ||
(pInit->SenseBufferHighAddr != sense_high)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2088,9 +2096,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
MPI_FUNCTION_LAN_RESET
*/
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Illegal request (function 0x%x) \n",
- __FILE__, __LINE__, hdr->Function);
+ ioc->name, __FILE__, __LINE__, hdr->Function);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2103,11 +2111,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
psge = (char *) (((int *) mf) + karg.dataSgeOffset);
flagsLength = 0;
- /* bufIn and bufOut are used for user to kernel space transfers
- */
- bufIn.kptr = bufOut.kptr = NULL;
- bufIn.len = bufOut.len = 0;
-
if (karg.dataOutSize > 0)
sgSize ++;
@@ -2147,11 +2150,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (copy_from_user(bufOut.kptr,
karg.dataOutBufPtr,
bufOut.len)) {
- printk(KERN_ERR
+ printk(MYIOC_s_ERR_FMT
"%s@%d::mptctl_do_mpt_command - Unable "
"to read user data "
"struct @ %p\n",
- __FILE__, __LINE__,karg.dataOutBufPtr);
+ ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2187,15 +2190,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
- if (mpt_send_handshake_request(mptctl_id, ioc,
- sizeof(SCSITaskMgmt_t), (u32*)mf,
- CAN_SLEEP) != 0) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (ioc %p, mf %p) \n", ioc->name,
- ioc, mf));
- mptctl_free_tm_flags(ioc);
- rc = -ENODATA;
- goto done_free_mem;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
+ else {
+ rc =mpt_send_handshake_request(mptctl_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+ if (rc != 0) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "_send_handshake FAILED! (ioc %p, mf %p)\n",
+ ioc->name, ioc, mf));
+ mptctl_free_tm_flags(ioc);
+ rc = -ENODATA;
+ goto done_free_mem;
+ }
}
} else
@@ -2233,10 +2241,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (sz > 0) {
if (copy_to_user(karg.replyFrameBufPtr,
&ioc->ioctl->ReplyFrame, sz)){
- printk(KERN_ERR
+ printk(MYIOC_s_ERR_FMT
"%s@%d::mptctl_do_mpt_command - "
"Unable to write out reply frame %p\n",
- __FILE__, __LINE__, karg.replyFrameBufPtr);
+ ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
rc = -ENODATA;
goto done_free_mem;
}
@@ -2249,9 +2257,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
if (sz > 0) {
if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to write sense data to user %p\n",
- __FILE__, __LINE__,
+ ioc->name, __FILE__, __LINE__,
karg.senseDataPtr);
rc = -ENODATA;
goto done_free_mem;
@@ -2267,9 +2275,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (copy_to_user(karg.dataInBufPtr,
bufIn.kptr, karg.dataInSize)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to write data to user %p\n",
- __FILE__, __LINE__,
+ ioc->name, __FILE__, __LINE__,
karg.dataInBufPtr);
rc = -ENODATA;
}
@@ -2340,7 +2348,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
return -EFAULT;
if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
"Unable to read in hp_host_info struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -2348,7 +2356,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -2456,7 +2464,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
karg.soft_resets = 0;
karg.timeouts = 0;
if (ioc->sh != NULL) {
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
if (hd && (cim_rev == 1)) {
karg.hard_resets = hd->hard_resets;
@@ -2529,9 +2537,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
"Unable to write out hp_host_info @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -2567,7 +2575,7 @@ mptctl_hp_targetinfo(unsigned long arg)
int tmp, np, rc = 0;
if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
"Unable to read in hp_host_targetinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -2575,11 +2583,11 @@ mptctl_hp_targetinfo(unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
ioc->name));
/* There is nothing to do for FCP parts.
@@ -2673,16 +2681,16 @@ mptctl_hp_targetinfo(unsigned long arg)
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
}
}
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (hd != NULL)
karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -2732,7 +2740,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
@@ -2772,7 +2780,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
@@ -2853,31 +2861,22 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
static int
mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- int err;
- int sz;
- u8 *mem;
+ MPT_IOCTL *mem;
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
/*
* Allocate and inite a MPT_IOCTL structure
*/
- sz = sizeof (MPT_IOCTL);
- mem = kmalloc(sz, GFP_KERNEL);
- if (mem == NULL) {
- err = -ENOMEM;
- goto out_fail;
+ mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
+ if (!mem) {
+ mptctl_remove(pdev);
+ return -ENOMEM;
}
- memset(mem, 0, sz);
- ioc->ioctl = (MPT_IOCTL *) mem;
+ ioc->ioctl = mem;
ioc->ioctl->ioc = ioc;
mutex_init(&ioc->ioctl->ioctl_mutex);
return 0;
-
-out_fail:
-
- mptctl_remove(pdev);
- return err;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2924,7 +2923,8 @@ static int __init mptctl_init(void)
* Install our handler
*/
++where;
- if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+ mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
+ if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
misc_deregister(&mptctl_miscdev);
err = -EBUSY;
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index 180b3c15624..2c1890127e1 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -3,9 +3,9 @@
* Fusion MPT misc device (ioctl) driver.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 8422c25e4a3..3cdd4e96211 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptfc.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -90,9 +90,9 @@ static int max_lun = MPTFC_MAX_LUN;
module_param(max_lun, int, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-static int mptfcDoneCtx = -1;
-static int mptfcTaskCtx = -1;
-static int mptfcInternalCtx = -1; /* Used only for internal commands */
+static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
static int mptfc_target_alloc(struct scsi_target *starget);
static int mptfc_slave_alloc(struct scsi_device *sdev);
@@ -194,37 +194,36 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
unsigned long flags;
int ready;
+ MPT_ADAPTER *ioc;
- hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ hd = shost_priv(SCpnt->device->host);
+ ioc = hd->ioc;
spin_lock_irqsave(shost->host_lock, flags);
while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
spin_unlock_irqrestore(shost->host_lock, flags);
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_block_error_handler.%d: %d:%d, port status is "
"DID_IMM_RETRY, deferring %s recovery.\n",
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun,caller));
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun, caller));
msleep(1000);
spin_lock_irqsave(shost->host_lock, flags);
}
spin_unlock_irqrestore(shost->host_lock, flags);
if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, failing recovery, "
- "port state %d, vdev %p.\n", caller,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun,ready,
+ "port state %d, vdevice %p.\n", caller,
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun, ready,
SCpnt->device->hostdata));
return FAILED;
}
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, executing recovery.\n", caller,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun));
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun));
return (*func)(SCpnt);
}
@@ -470,7 +469,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
/*
* if already mapped, remap here. If not mapped,
* target_alloc will allocate vtarget and map,
- * slave_alloc will fill in vdev from vtarget.
+ * slave_alloc will fill in vdevice from vtarget.
*/
if (ri->starget) {
vtarget = ri->starget->hostdata;
@@ -602,10 +601,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
{
MPT_SCSI_HOST *hd;
VirtTarget *vtarget;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
struct fc_rport *rport;
-
+ MPT_ADAPTER *ioc;
starget = scsi_target(sdev);
rport = starget_to_rport(starget);
@@ -613,31 +612,32 @@ mptfc_slave_alloc(struct scsi_device *sdev)
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ hd = shost_priv(sdev->host);
+ ioc = hd->ioc;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
- sdev->hostdata = vdev;
+ sdev->hostdata = vdevice;
vtarget = starget->hostdata;
if (vtarget->num_luns == 0) {
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
}
- vdev->vtarget = vtarget;
- vdev->lun = sdev->lun;
+ vdevice->vtarget = vtarget;
+ vdevice->lun = sdev->lun;
vtarget->num_luns++;
- mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget);
+ mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
return 0;
}
@@ -648,9 +648,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
struct mptfc_rport_info *ri;
struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
int err;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
- if (!vdev || !vdev->vtarget) {
+ if (!vdevice || !vdevice->vtarget) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -675,6 +675,50 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
}
/*
+ * mptfc_display_port_link_speed - displaying link speed
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @portnum: IOC Port number
+ * @pp0dest: port page0 data payload
+ *
+ */
+static void
+mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)
+{
+ u8 old_speed, new_speed, state;
+ char *old, *new;
+
+ if (portnum >= 2)
+ return;
+
+ old_speed = ioc->fc_link_speed[portnum];
+ new_speed = pp0dest->CurrentSpeed;
+ state = pp0dest->PortState;
+
+ if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&
+ new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) {
+
+ old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+ old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+ old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+ "Unknown";
+ new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+ new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+ new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+ "Unknown";
+ if (old_speed == 0)
+ printk(MYIOC_s_NOTE_FMT
+ "FC Link Established, Speed = %s\n",
+ ioc->name, new);
+ else if (old_speed != new_speed)
+ printk(MYIOC_s_WARN_FMT
+ "FC Link Speed Change, Old Speed = %s, New Speed = %s\n",
+ ioc->name, old, new);
+
+ ioc->fc_link_speed[portnum] = new_speed;
+ }
+}
+
+/*
* mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
* @ioc: Pointer to MPT_ADAPTER structure
* @portnum: IOC Port number
@@ -773,6 +817,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
" complete.\n",
ioc->name);
}
+ mptfc_display_port_link_speed(ioc, portnum, pp0dest);
}
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -1023,6 +1068,18 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
}
static void
+mptfc_link_status_change(struct work_struct *work)
+{
+ MPT_ADAPTER *ioc =
+ container_of(work, MPT_ADAPTER, fc_rescan_work);
+ int ii;
+
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
+ (void) mptfc_GetFcPortPage0(ioc, ii);
+
+}
+
+static void
mptfc_setup_reset(struct work_struct *work)
{
MPT_ADAPTER *ioc =
@@ -1163,6 +1220,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ioc->fc_rescan_work_lock);
INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
+ INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
spin_lock_irqsave(&ioc->FreeQlock, flags);
@@ -1218,20 +1276,21 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
goto out_mptfc_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -1262,8 +1321,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->transportt = mptfc_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptfc_probe;
}
@@ -1325,7 +1384,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
ioc->name, event));
if (ioc->sh == NULL ||
- ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+ ((hd = shost_priv(ioc->sh)) == NULL))
return 1;
switch (event) {
@@ -1337,6 +1396,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
break;
+ case MPI_EVENT_LINK_STATUS_CHANGE:
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+ if (ioc->fc_rescan_work_q) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_lsc_work);
+ }
+ spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+ break;
default:
rc = mptscsih_event_process(ioc,pEvReply);
break;
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 3da4c37846e..7950fc678ed 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptlan.c
* IP Over Fibre Channel device driver.
- * For use with LSI Logic Fibre Channel PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI Fibre Channel PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2007 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -154,7 +154,7 @@ static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
/*
* Fusion MPT LAN private data
*/
-static int LanCtx = -1;
+static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
static u32 max_buckets_out = 127;
static u32 tx_max_out_p = 127 - 16;
@@ -165,12 +165,6 @@ DEFINE_RWLOCK(bad_naa_lock);
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Fusion MPT LAN external data
- */
-extern int mpt_lan_index;
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* lan_reply - Handle all data sent from the hardware.
* @ioc: Pointer to MPT_ADAPTER structure
@@ -1230,6 +1224,8 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
}
pRecvReq = (LANReceivePostRequest_t *) mf;
+ i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ mpt_dev->RequestNB[i] = 0;
count = buckets;
if (count > max)
count = max;
@@ -1351,10 +1347,11 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work)
static struct net_device *
mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
{
- struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
- struct mpt_lan_priv *priv = NULL;
+ struct net_device *dev;
+ struct mpt_lan_priv *priv;
u8 HWaddr[FC_ALEN], *a;
+ dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
if (!dev)
return NULL;
@@ -1366,7 +1363,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
priv->mpt_dev = mpt_dev;
priv->pnum = pnum;
- memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
INIT_DELAYED_WORK(&priv->post_buckets_task,
mpt_lan_post_receive_buckets_work);
priv->post_buckets_active = 0;
@@ -1391,8 +1387,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
spin_lock_init(&priv->txfidx_lock);
spin_lock_init(&priv->rxfidx_lock);
- memset(&priv->stats, 0, sizeof(priv->stats));
-
/* Grab pre-fetched LANPage1 stuff. :-) */
a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
@@ -1508,9 +1502,6 @@ static int __init mpt_lan_init (void)
return -EBUSY;
}
- /* Set the callback index to be used by driver core for turbo replies */
- mpt_lan_index = LanCtx;
-
dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
@@ -1531,10 +1522,9 @@ static void __exit mpt_lan_exit(void)
mpt_device_driver_deregister(MPTLAN_DRIVER);
mpt_reset_deregister(LanCtx);
- if (LanCtx >= 0) {
+ if (LanCtx) {
mpt_deregister(LanCtx);
- LanCtx = -1;
- mpt_lan_index = 0;
+ LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
}
}
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 8d08c2bed24..bafb67fc818 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptlan.h
* IP Over Fibre Channel device driver.
- * For use with LSI Logic Fibre Channel PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI Fibre Channel PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2007 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -75,7 +75,7 @@
#include <asm/io.h>
/* Override mptbase.h by pre-defining these! */
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#include "mptbase.h"
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index b9c69bff218..e4c94f93de1 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1,11 +1,10 @@
/*
* linux/drivers/message/fusion/mptsas.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
- * Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -61,6 +60,7 @@
#include "mptbase.h"
#include "mptscsih.h"
+#include "mptsas.h"
#define my_NAME "Fusion MPT SAS Host driver"
@@ -89,134 +89,35 @@ static int max_lun = MPTSAS_MAX_LUN;
module_param(max_lun, int, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-static int mptsasDoneCtx = -1;
-static int mptsasTaskCtx = -1;
-static int mptsasInternalCtx = -1; /* Used only for internal commands */
-static int mptsasMgmtCtx = -1;
+static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
+static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
static void mptsas_hotplug_work(struct work_struct *work);
-struct mptsas_target_reset_event {
- struct list_head list;
- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
- u8 target_reset_issued;
-};
-
-enum mptsas_hotplug_action {
- MPTSAS_ADD_DEVICE,
- MPTSAS_DEL_DEVICE,
- MPTSAS_ADD_RAID,
- MPTSAS_DEL_RAID,
- MPTSAS_ADD_INACTIVE_VOLUME,
- MPTSAS_IGNORE_EVENT,
-};
-
-struct mptsas_hotplug_event {
- struct work_struct work;
- MPT_ADAPTER *ioc;
- enum mptsas_hotplug_action event_type;
- u64 sas_address;
- u8 channel;
- u8 id;
- u32 device_info;
- u16 handle;
- u16 parent_handle;
- u8 phy_id;
- u8 phys_disk_num_valid; /* hrc (hidden raid component) */
- u8 phys_disk_num; /* hrc - unique index*/
- u8 hidden_raid_component; /* hrc - don't expose*/
-};
-
-struct mptsas_discovery_event {
- struct work_struct work;
- MPT_ADAPTER *ioc;
-};
-
-/*
- * SAS topology structures
- *
- * The MPT Fusion firmware interface spreads information about the
- * SAS topology over many manufacture pages, thus we need some data
- * structure to collect it and process it for the SAS transport class.
- */
-
-struct mptsas_devinfo {
- u16 handle; /* unique id to address this device */
- u16 handle_parent; /* unique id to address parent device */
- u16 handle_enclosure; /* enclosure identifier of the enclosure */
- u16 slot; /* physical slot in enclosure */
- u8 phy_id; /* phy number of parent device */
- u8 port_id; /* sas physical port this device
- is assoc'd with */
- u8 id; /* logical target id of this device */
- u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
- u8 channel; /* logical bus number of this device */
- u64 sas_address; /* WWN of this device,
- SATA is assigned by HBA,expander */
- u32 device_info; /* bitfield detailed info about this device */
-};
-
-/*
- * Specific details on ports, wide/narrow
- */
-struct mptsas_portinfo_details{
- u16 num_phys; /* number of phys belong to this port */
- u64 phy_bitmask; /* TODO, extend support for 255 phys */
- struct sas_rphy *rphy; /* transport layer rphy object */
- struct sas_port *port; /* transport layer port object */
- struct scsi_target *starget;
- struct mptsas_portinfo *port_info;
-};
-
-struct mptsas_phyinfo {
- u16 handle; /* unique id to address this */
- u8 phy_id; /* phy index */
- u8 port_id; /* firmware port identifier */
- u8 negotiated_link_rate; /* nego'd link rate for this phy */
- u8 hw_link_rate; /* hardware max/min phys link rate */
- u8 programmed_link_rate; /* programmed max/min phy link rate */
- u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
- struct mptsas_devinfo identify; /* point to phy device info */
- struct mptsas_devinfo attached; /* point to attached device info */
- struct sas_phy *phy; /* transport layer phy object */
- struct mptsas_portinfo *portinfo;
- struct mptsas_portinfo_details * port_details;
-};
-
-struct mptsas_portinfo {
- struct list_head list;
- u16 num_phys; /* number of phys */
- struct mptsas_phyinfo *phy_info;
-};
-
-struct mptsas_enclosure {
- u64 enclosure_logical_id; /* The WWN for the enclosure */
- u16 enclosure_handle; /* unique id to address this */
- u16 flags; /* details enclosure management */
- u16 num_slot; /* num slots */
- u16 start_slot; /* first slot */
- u8 start_id; /* starting logical target id */
- u8 start_channel; /* starting logical channel id */
- u8 sep_id; /* SEP device logical target id */
- u8 sep_channel; /* SEP channel logical channel id */
-};
-
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
- le16_to_cpu(phy_data->AttachedDeviceHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
- le16_to_cpu(phy_data->ControllerDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
- dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
- dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
- le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
- le32_to_cpu(phy_data->DiscoveryStatus)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- IO UNIT PAGE 0 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+ ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
+ ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
+ ioc->name, phy_data->Port));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
+ ioc->name, phy_data->PortFlags));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
+ ioc->name, phy_data->PhyFlags));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+ ioc->name, phy_data->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Controller PHY Device Info=0x%X\n", ioc->name,
+ le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
+ ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
}
static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
@@ -225,27 +126,41 @@ static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
- le16_to_cpu(pg0->AttachedDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
- (unsigned long long)le64_to_cpu(sas_address)));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
- le32_to_cpu(pg0->AttachedDeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS PHY PAGE 0 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached Device Handle=0x%X\n", ioc->name,
+ le16_to_cpu(pg0->AttachedDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+ ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached PHY Identifier=0x%X\n", ioc->name,
+ pg0->AttachedPhyIdentifier));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
+ ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+ ioc->name, pg0->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
+ ioc->name, pg0->ChangeCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
+ ioc->name, le32_to_cpu(pg0->PhyInfo)));
}
static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
- dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
- pg1->RunningDisparityErrorCount));
- dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS PHY PAGE 1 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
+ ioc->name, pg1->InvalidDwordCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Running Disparity Error Count=0x%x\n", ioc->name,
+ pg1->RunningDisparityErrorCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Loss Dword Synch Count=0x%x\n", ioc->name,
+ pg1->LossDwordSynchCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "PHY Reset Problem Count=0x%x\n\n", ioc->name,
+ pg1->PhyResetProblemCount));
}
static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
@@ -254,37 +169,53 @@ static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
- dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
- le64_to_cpu(sas_address)));
- dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
- dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
- /* The PhyNum field specifies the PHY number of the parent
- * device this device is linked to
- */
- dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
- dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
- dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
- dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->DevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->Slot)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+ ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
+ ioc->name, pg0->TargetID));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
+ ioc->name, pg0->Bus));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
+ ioc->name, pg0->PhyNum));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->AccessStatus)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
+ ioc->name, le32_to_cpu(pg0->DeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->Flags)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
+ ioc->name, pg0->PhysicalPort));
}
static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
- dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
- le16_to_cpu(pg1->OwnerDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
- le16_to_cpu(pg1->AttachedDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
+ ioc->name, pg1->PhysicalPort));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
+ ioc->name, pg1->PhyIdentifier));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+ ioc->name, pg1->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+ ioc->name, pg1->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
+ ioc->name, pg1->HwLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached Device Handle=0x%X\n\n", ioc->name,
+ le16_to_cpu(pg1->AttachedDevHandle)));
}
static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
@@ -354,8 +285,8 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
port_info = port_details->port_info;
phy_info = port_info->phy_info;
- dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
- "bitmask=0x%016llX\n", __FUNCTION__, port_details,
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
+ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
port_details->num_phys, (unsigned long long)
port_details->phy_bitmask));
@@ -382,14 +313,15 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rp
{
if (phy_info->port_details) {
phy_info->port_details->rphy = rphy;
- dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
+ ioc->name, rphy));
}
if (rphy) {
dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
- &rphy->dev, "add:"));
- dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
- rphy, rphy->dev.release));
+ &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
+ ioc->name, rphy, rphy->dev.release));
}
}
@@ -410,9 +342,9 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_po
if (port) {
dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
- &port->dev, "add:"));
- dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
- port, port->dev.release));
+ &port->dev, MYIOC_s_FMT "add:", ioc->name));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
+ ioc->name, port, port->dev.release));
}
}
@@ -463,9 +395,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
* Removing a phy from a port, letting the last
* phy be removed by firmware events.
*/
- dsaswideprintk(ioc, printk(KERN_DEBUG
- "%s: [%p]: deleting phy = %d\n",
- __FUNCTION__, port_details, i));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: [%p]: deleting phy = %d\n",
+ ioc->name, __FUNCTION__, port_details, i));
port_details->num_phys--;
port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -479,8 +411,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
phy_info = port_info->phy_info;
for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
sas_address = phy_info->attached.sas_address;
- dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
- i, (unsigned long long)sas_address));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
+ ioc->name, i, (unsigned long long)sas_address));
if (!sas_address)
continue;
port_details = phy_info->port_details;
@@ -498,9 +430,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details->phy_bitmask |=
(1 << phy_info->phy_id);
phy_info->sas_port_add_phy=1;
- dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
"phy_id=%d sas_address=0x%018llX\n",
- i, (unsigned long long)sas_address));
+ ioc->name, i, (unsigned long long)sas_address));
phy_info->port_details = port_details;
}
@@ -515,9 +447,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
continue;
if (phy_info_cmp->port_details == port_details )
continue;
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"\t\tphy_id=%d sas_address=0x%018llX\n",
- j, (unsigned long long)
+ ioc->name, j, (unsigned long long)
phy_info_cmp->attached.sas_address));
if (phy_info_cmp->port_details) {
port_details->rphy =
@@ -549,15 +481,15 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details = port_info->phy_info[i].port_details;
if (!port_details)
continue;
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s: [%p]: phy_id=%02d num_phys=%02d "
- "bitmask=0x%016llX\n", __FUNCTION__,
+ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
port_details, i, port_details->num_phys,
(unsigned long long)port_details->phy_bitmask));
- dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
- port_details->port, port_details->rphy));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+ ioc->name, port_details->port, port_details->rphy));
}
- dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
+ dsaswideprintk(ioc, printk("\n"));
mutex_unlock(&ioc->sas_topology_mutex);
}
@@ -573,15 +505,15 @@ static VirtTarget *
mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
struct scsi_device *sdev;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
VirtTarget *vtarget = NULL;
shost_for_each_device(sdev, ioc->sh) {
- if ((vdev = sdev->hostdata) == NULL)
+ if ((vdevice = sdev->hostdata) == NULL)
continue;
- if (vdev->vtarget->id == id &&
- vdev->vtarget->channel == channel)
- vtarget = vdev->vtarget;
+ if (vdevice->vtarget->id == id &&
+ vdevice->vtarget->channel == channel)
+ vtarget = vdevice->vtarget;
}
return vtarget;
}
@@ -623,13 +555,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
- if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
- sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
- mpt_free_msg_frame(ioc, mf);
- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
- ioc->name,__FUNCTION__, __LINE__));
- return 0;
- }
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
return 1;
}
@@ -649,7 +575,7 @@ static void
mptsas_target_reset_queue(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
VirtTarget *vtarget = NULL;
struct mptsas_target_reset_event *target_reset_list;
u8 id, channel;
@@ -696,7 +622,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
static void
mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
struct list_head *head = &hd->target_reset_list;
struct mptsas_target_reset_event *target_reset_list;
struct mptsas_hotplug_event *ev;
@@ -813,7 +739,7 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
if (!ioc->sh || !ioc->sh->hostdata)
goto out;
- hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (!hd->ioc)
goto out;
@@ -913,19 +839,20 @@ static int
mptsas_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(&starget->dev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
VirtTarget *vtarget;
u8 id, channel;
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
if (!vtarget)
return -ENOMEM;
vtarget->starget = starget;
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
id = starget->id;
channel = 0;
@@ -934,15 +861,15 @@ mptsas_target_alloc(struct scsi_target *starget)
* RAID volumes placed beyond the last expected port.
*/
if (starget->channel == MPTSAS_RAID_CHANNEL) {
- for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
- if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
- channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+ if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+ channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
goto out;
}
rphy = dev_to_rphy(starget->dev.parent);
- mutex_lock(&hd->ioc->sas_topology_mutex);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
@@ -954,18 +881,18 @@ mptsas_target_alloc(struct scsi_target *starget)
/*
* Exposing hidden raid components
*/
- if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
- id = mptscsih_raid_id_to_num(hd->ioc,
+ if (mptscsih_is_phys_disk(ioc, channel, id)) {
+ id = mptscsih_raid_id_to_num(ioc,
channel, id);
vtarget->tflags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
p->phy_info[i].attached.phys_disk_num = id;
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
goto out;
}
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
kfree(vtarget);
return -ENXIO;
@@ -981,10 +908,11 @@ static void
mptsas_target_destroy(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(&starget->dev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
if (!starget->hostdata)
return;
@@ -993,7 +921,7 @@ mptsas_target_destroy(struct scsi_target *starget)
goto out;
rphy = dev_to_rphy(starget->dev.parent);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
@@ -1013,61 +941,62 @@ static int
mptsas_slave_alloc(struct scsi_device *sdev)
{
struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
starget = scsi_target(sdev);
- vdev->vtarget = starget->hostdata;
+ vdevice->vtarget = starget->hostdata;
if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out;
rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
- mutex_lock(&hd->ioc->sas_topology_mutex);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
continue;
- vdev->lun = sdev->lun;
+ vdevice->lun = sdev->lun;
/*
* Exposing hidden raid components
*/
- if (mptscsih_is_phys_disk(hd->ioc,
+ if (mptscsih_is_phys_disk(ioc,
p->phy_info[i].attached.channel,
p->phy_info[i].attached.id))
sdev->no_uld_attach = 1;
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
goto out;
}
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
- kfree(vdev);
+ kfree(vdevice);
return -ENXIO;
out:
- vdev->vtarget->num_luns++;
- sdev->hostdata = vdev;
+ vdevice->vtarget->num_luns++;
+ sdev->hostdata = vdevice;
return 0;
}
static int
mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
- if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
+ if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -1239,10 +1168,8 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
/* process the completed Reply Message Frame */
reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
- printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
- __FUNCTION__,
- reply->IOCStatus,
- reply->IOCLogInfo);
+ printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
error = -ENXIO;
goto out_unlock;
}
@@ -1328,16 +1255,16 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u64 sas_address = 0;
if (!rsp) {
- printk(KERN_ERR "%s: the smp response space is missing\n",
- __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
+ ioc->name, __FUNCTION__);
return -EINVAL;
}
/* do we need to support multiple segments? */
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
- printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
- __FUNCTION__, req->bio->bi_vcnt, req->data_len,
- rsp->bio->bi_vcnt, rsp->data_len);
+ printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
+ ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
return -EINVAL;
}
@@ -1402,7 +1329,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
if (!timeleft) {
- printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
/* On timeout reset the board */
mpt_HardResetHandler(ioc, CAN_SLEEP);
ret = -ETIMEDOUT;
@@ -1417,8 +1344,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
memcpy(req->sense, smprep, sizeof(*smprep));
req->sense_len = sizeof(*smprep);
} else {
- printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
- __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+ ioc->name, __FUNCTION__);
ret = -ENXIO;
}
unmap:
@@ -2062,12 +1989,12 @@ static int mptsas_probe_one_phy(struct device *dev,
goto out;
}
mptsas_set_port(ioc, phy_info, port);
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"sas_port_alloc: port=%p dev=%p port_id=%d\n",
- port, dev, port->port_identifier));
+ ioc->name, port, dev, port->port_identifier));
}
- dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
- phy_info->phy_id));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
+ ioc->name, phy_info->phy_id));
sas_port_add_phy(port, phy_info->phy);
phy_info->sas_port_add_phy = 0;
}
@@ -2369,8 +2296,9 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
expander_sas_address)
continue;
dsaswideprintk(ioc,
- dev_printk(KERN_DEBUG, &port->dev,
- "delete port (%d)\n", port->port_identifier));
+ dev_printk(KERN_DEBUG, &port->dev,
+ MYIOC_s_FMT "delete port (%d)\n", ioc->name,
+ port->port_identifier));
sas_port_delete(port);
mptsas_port_delete(ioc, phy_info->port_details);
}
@@ -2613,7 +2541,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
goto out;
}
@@ -2754,8 +2682,8 @@ mptsas_hotplug_work(struct work_struct *work)
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
- dev_printk(KERN_DEBUG, &port->dev,
- "delete port (%d)\n", port->port_identifier);
+ dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+ "delete port (%d)\n", ioc->name, port->port_identifier);
sas_port_delete(port);
mptsas_port_delete(ioc, phy_info->port_details);
break;
@@ -2796,8 +2724,8 @@ mptsas_hotplug_work(struct work_struct *work)
if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
}
/*
@@ -2930,7 +2858,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
break;
}
@@ -2989,7 +2917,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
return;
}
@@ -3288,20 +3216,22 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->sg_tablesize = numSGE;
}
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
goto out_mptsas_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -3340,8 +3270,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
error = scsi_add_host(sh, &ioc->pcidev->dev);
if (error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptsas_probe;
}
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
new file mode 100644
index 00000000000..7c150f50629
--- /dev/null
+++ b/drivers/message/fusion/mptsas.h
@@ -0,0 +1,158 @@
+/*
+ * linux/drivers/message/fusion/mptsas.h
+ * High performance SCSI + LAN / Fibre Channel device drivers.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI MPT (Message Passing Technology) firmware.
+ *
+ * Copyright (c) 1999-2007 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.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; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ 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 MPTSAS_H_INCLUDED
+#define MPTSAS_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+struct mptsas_target_reset_event {
+ struct list_head list;
+ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
+ u8 target_reset_issued;
+};
+
+enum mptsas_hotplug_action {
+ MPTSAS_ADD_DEVICE,
+ MPTSAS_DEL_DEVICE,
+ MPTSAS_ADD_RAID,
+ MPTSAS_DEL_RAID,
+ MPTSAS_ADD_INACTIVE_VOLUME,
+ MPTSAS_IGNORE_EVENT,
+};
+
+struct mptsas_hotplug_event {
+ struct work_struct work;
+ MPT_ADAPTER *ioc;
+ enum mptsas_hotplug_action event_type;
+ u64 sas_address;
+ u8 channel;
+ u8 id;
+ u32 device_info;
+ u16 handle;
+ u16 parent_handle;
+ u8 phy_id;
+ u8 phys_disk_num_valid; /* hrc (hidden raid component) */
+ u8 phys_disk_num; /* hrc - unique index*/
+ u8 hidden_raid_component; /* hrc - don't expose*/
+};
+
+struct mptsas_discovery_event {
+ struct work_struct work;
+ MPT_ADAPTER *ioc;
+};
+
+/*
+ * SAS topology structures
+ *
+ * The MPT Fusion firmware interface spreads information about the
+ * SAS topology over many manufacture pages, thus we need some data
+ * structure to collect it and process it for the SAS transport class.
+ */
+
+struct mptsas_devinfo {
+ u16 handle; /* unique id to address this device */
+ u16 handle_parent; /* unique id to address parent device */
+ u16 handle_enclosure; /* enclosure identifier of the enclosure */
+ u16 slot; /* physical slot in enclosure */
+ u8 phy_id; /* phy number of parent device */
+ u8 port_id; /* sas physical port this device
+ is assoc'd with */
+ u8 id; /* logical target id of this device */
+ u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
+ u8 channel; /* logical bus number of this device */
+ u64 sas_address; /* WWN of this device,
+ SATA is assigned by HBA,expander */
+ u32 device_info; /* bitfield detailed info about this device */
+};
+
+/*
+ * Specific details on ports, wide/narrow
+ */
+struct mptsas_portinfo_details{
+ u16 num_phys; /* number of phys belong to this port */
+ u64 phy_bitmask; /* TODO, extend support for 255 phys */
+ struct sas_rphy *rphy; /* transport layer rphy object */
+ struct sas_port *port; /* transport layer port object */
+ struct scsi_target *starget;
+ struct mptsas_portinfo *port_info;
+};
+
+struct mptsas_phyinfo {
+ u16 handle; /* unique id to address this */
+ u8 phy_id; /* phy index */
+ u8 port_id; /* firmware port identifier */
+ u8 negotiated_link_rate; /* nego'd link rate for this phy */
+ u8 hw_link_rate; /* hardware max/min phys link rate */
+ u8 programmed_link_rate; /* programmed max/min phy link rate */
+ u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
+ struct mptsas_devinfo identify; /* point to phy device info */
+ struct mptsas_devinfo attached; /* point to attached device info */
+ struct sas_phy *phy; /* transport layer phy object */
+ struct mptsas_portinfo *portinfo;
+ struct mptsas_portinfo_details * port_details;
+};
+
+struct mptsas_portinfo {
+ struct list_head list;
+ u16 num_phys; /* number of phys */
+ struct mptsas_phyinfo *phy_info;
+};
+
+struct mptsas_enclosure {
+ u64 enclosure_logical_id; /* The WWN for the enclosure */
+ u16 enclosure_handle; /* unique id to address this */
+ u16 flags; /* details enclosure management */
+ u16 num_slot; /* num slots */
+ u16 start_slot; /* first slot */
+ u8 start_id; /* starting logical target id */
+ u8 start_channel; /* starting logical channel id */
+ u8 sep_id; /* SEP device logical target id */
+ u8 sep_channel; /* SEP channel logical channel id */
+};
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5431529741a..bdff950a54a 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptscsih.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -80,6 +80,10 @@ MODULE_VERSION(my_VERSION);
/*
* Other private/forward protos...
*/
+static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
+static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
@@ -90,7 +94,6 @@ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
@@ -192,7 +195,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
int chain_idx;
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
- ioc->name));
+ ioc->name));
spin_lock_irqsave(&ioc->FreeQlock, flags);
if (!list_empty(&ioc->FreeChainQ)) {
int offset;
@@ -203,13 +206,14 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
} else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
- dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
- ioc->name));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
+ ioc->name));
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -419,8 +423,8 @@ nextSGEset:
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
- dsgprintk(ioc, printk(KERN_DEBUG " Current buff @ %p (index 0x%x)",
- psge, req_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
+ ioc->name, psge, req_idx));
/* Start the SGE for the next buffer
*/
@@ -428,8 +432,8 @@ nextSGEset:
sgeOffset = 0;
sg_done = 0;
- dsgprintk(ioc, printk(KERN_DEBUG " Chain buff @ %p (index 0x%x)\n",
- psge, chain_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
+ ioc->name, psge, chain_idx));
/* Start the SGE for the next buffer
*/
@@ -588,18 +592,17 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
}
scsi_print_command(sc);
- printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
- pScsiReply->Bus, pScsiReply->TargetID);
- printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
- scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
- printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
- le16_to_cpu(pScsiReply->TaskTag),
+ printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
+ ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+ printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
+ "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
+ scsi_get_resid(sc));
+ printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
+ "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
le32_to_cpu(pScsiReply->TransferCount), sc->result);
-
- printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
+ printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
"scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
- desc, ioc_status,
- desc1, pScsiReply->SCSIStatus,
+ ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
pScsiReply->SCSIState);
if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -607,9 +610,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
asc = sc->sense_buffer[12];
ascq = sc->sense_buffer[13];
- printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
- "[0x%02x,0x%02x,0x%02x]\n",
- skey, asc, ascq);
+ printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
+ "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
}
/*
@@ -617,8 +619,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
*/
if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
pScsiReply->ResponseInfo)
- printk(KERN_DEBUG "response_info = %08xh\n",
- le32_to_cpu(pScsiReply->ResponseInfo));
+ printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
+ ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
}
#endif
@@ -645,11 +647,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
u16 req_idx, req_idx_MR;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
VirtTarget *vtarget;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-
+ hd = shost_priv(ioc->sh);
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
req_idx_MR = (mr != NULL) ?
le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
@@ -660,12 +661,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
printk (MYIOC_s_ERR_FMT
"req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
ioc->name, req_idx, req_idx_MR, mf, mr,
- hd->ScsiLookup[req_idx_MR]);
+ mptscsih_get_scsi_lookup(ioc, req_idx_MR));
return 0;
}
- sc = hd->ScsiLookup[req_idx];
- hd->ScsiLookup[req_idx] = NULL;
+ sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
@@ -738,8 +738,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
*/
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
pScsiReply->ResponseInfo) {
- printk(KERN_NOTICE "[%d:%d:%d:%d] "
- "FCP_ResponseInfo=%08xh\n",
+ printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
+ "FCP_ResponseInfo=%08xh\n", ioc->name,
sc->device->host->host_no, sc->device->channel,
sc->device->id, sc->device->lun,
le32_to_cpu(pScsiReply->ResponseInfo));
@@ -771,10 +771,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
- vdev = sc->device->hostdata;
- if (!vdev)
+ vdevice = sc->device->hostdata;
+ if (!vdevice)
break;
- vtarget = vdev->vtarget;
+ vtarget = vdevice->vtarget;
if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
mptscsih_issue_sep_command(ioc, vtarget,
MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
@@ -824,9 +824,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk(ioc, printk(KERN_DEBUG
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
- sc->result, sc->device->channel, sc->device->id));
+ ioc->name, sc->result, sc->device->channel, sc->device->id));
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
@@ -858,9 +858,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
- dreplyprintk(ioc, printk(KERN_DEBUG " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
- sc->underflow));
- dreplyprintk(ioc, printk(KERN_DEBUG " ActBytesXferd=%02xh\n", xfer_cnt));
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+ ioc->name, sc->underflow));
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
/* Report Queue Full
*/
@@ -969,48 +971,32 @@ static void
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
{
MPT_ADAPTER *ioc = hd->ioc;
- struct scsi_cmnd *SCpnt;
- MPT_FRAME_HDR *mf;
+ struct scsi_cmnd *sc;
+ SCSIIORequest_t *mf = NULL;
int ii;
- int max = ioc->req_depth;
-
- dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
- for (ii= 0; ii < max; ii++) {
- if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
-
- /* Command found.
- */
-
- /* Null ScsiLookup index
- */
- hd->ScsiLookup[ii] = NULL;
-
- mf = MPT_INDEX_2_MFPTR(ioc, ii);
- dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
- mf, SCpnt));
-
- /* Free Chain buffers */
- mptscsih_freeChainBuffers(ioc, ii);
-
- /* Free Message frames */
- mpt_free_msg_frame(ioc, mf);
-
- if ((unsigned char *)mf != SCpnt->host_scribble)
- continue;
-
- /* Set status, free OS resources (SG DMA buffers)
- * Do OS callback
- */
- scsi_dma_unmap(SCpnt);
-
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
+ int channel, id;
- SCpnt->scsi_done(SCpnt); /* Issue the command callback */
- }
+ for (ii= 0; ii < ioc->req_depth; ii++) {
+ sc = mptscsih_getclear_scsi_lookup(ioc, ii);
+ if (!sc)
+ continue;
+ mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
+ if (!mf)
+ continue;
+ channel = mf->Bus;
+ id = mf->TargetID;
+ mptscsih_freeChainBuffers(ioc, ii);
+ mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
+ if ((unsigned char *)mf != sc->host_scribble)
+ continue;
+ scsi_dma_unmap(sc);
+ sc->result = DID_RESET << 16;
+ sc->host_scribble = NULL;
+ sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+ "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
+ " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+ sc->scsi_done(sc);
}
-
- return;
}
/*
@@ -1032,17 +1018,16 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
{
SCSIIORequest_t *mf = NULL;
int ii;
- int max = hd->ioc->req_depth;
struct scsi_cmnd *sc;
struct scsi_lun lun;
+ MPT_ADAPTER *ioc = hd->ioc;
+ unsigned long flags;
- dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
- vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
-
- for (ii=0; ii < max; ii++) {
- if ((sc = hd->ScsiLookup[ii]) != NULL) {
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ for (ii = 0; ii < ioc->req_depth; ii++) {
+ if ((sc = ioc->ScsiLookup[ii]) != NULL) {
- mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
+ mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
if (mf == NULL)
continue;
/* If the device is a hidden raid component, then its
@@ -1059,22 +1044,23 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
memcmp(lun.scsi_lun, mf->LUN, 8))
continue;
- /* Cleanup
- */
- hd->ScsiLookup[ii] = NULL;
- mptscsih_freeChainBuffers(hd->ioc, ii);
- mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
if ((unsigned char *)mf != sc->host_scribble)
continue;
+ ioc->ScsiLookup[ii] = NULL;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ mptscsih_freeChainBuffers(ioc, ii);
+ mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
scsi_dma_unmap(sc);
sc->host_scribble = NULL;
sc->result = DID_NO_CONNECT << 16;
- sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
- "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
+ sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
+ "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
vdevice->vtarget->id, sc, mf, ii);
sc->scsi_done(sc);
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
}
}
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
return;
}
@@ -1097,17 +1083,18 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI
{
long time = jiffies;
MPT_SCSI_HOST *hd;
+ MPT_ADAPTER *ioc;
if (sc->device == NULL)
return;
if (sc->device->host == NULL)
return;
- if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
+ if ((hd = shost_priv(sc->device->host)) == NULL)
return;
-
+ ioc = hd->ioc;
if (time - hd->last_queue_full > 10 * HZ) {
- dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
- hd->ioc->name, 0, sc->device->id, sc->device->lun));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+ ioc->name, 0, sc->device->id, sc->device->lun));
hd->last_queue_full = time;
}
}
@@ -1134,28 +1121,28 @@ mptscsih_remove(struct pci_dev *pdev)
scsi_remove_host(host);
- if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
+ if((hd = shost_priv(host)) == NULL)
return;
mptscsih_shutdown(pdev);
sz1=0;
- if (hd->ScsiLookup != NULL) {
- sz1 = hd->ioc->req_depth * sizeof(void *);
- kfree(hd->ScsiLookup);
- hd->ScsiLookup = NULL;
+ if (ioc->ScsiLookup != NULL) {
+ sz1 = ioc->req_depth * sizeof(void *);
+ kfree(ioc->ScsiLookup);
+ ioc->ScsiLookup = NULL;
}
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Free'd ScsiLookup (%d) memory\n",
- hd->ioc->name, sz1));
+ ioc->name, sz1));
kfree(hd->info_kbuf);
/* NULL the Scsi_Host pointer
*/
- hd->ioc->sh = NULL;
+ ioc->sh = NULL;
scsi_host_put(host);
@@ -1171,15 +1158,6 @@ mptscsih_remove(struct pci_dev *pdev)
void
mptscsih_shutdown(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct Scsi_Host *host = ioc->sh;
- MPT_SCSI_HOST *hd;
-
- if(!host)
- return;
-
- hd = (MPT_SCSI_HOST *)host->hostdata;
-
}
#ifdef CONFIG_PM
@@ -1225,7 +1203,7 @@ mptscsih_info(struct Scsi_Host *SChost)
MPT_SCSI_HOST *h;
int size = 0;
- h = (MPT_SCSI_HOST *)SChost->hostdata;
+ h = shost_priv(SChost);
if (h) {
if (h->info_kbuf == NULL)
@@ -1319,7 +1297,7 @@ int
mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int func)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
int size = 0;
@@ -1358,7 +1336,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
MPT_SCSI_HOST *hd;
MPT_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
int lun;
u32 datalen;
u32 scsictl;
@@ -1368,7 +1346,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
int ii;
MPT_ADAPTER *ioc;
- hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ hd = shost_priv(SCpnt->device->host);
ioc = hd->ioc;
lun = SCpnt->device->lun;
SCpnt->scsi_done = done;
@@ -1385,7 +1363,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/*
* Put together a MPT SCSI request...
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
+ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
ioc->name));
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1415,8 +1393,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* Default to untagged. Once a target structure has been allocated,
* use the Inquiry data to determine if device supports tagged.
*/
- if (vdev
- && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+ if (vdevice
+ && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
} else {
@@ -1425,10 +1403,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* Use the above information to set up the message frame
*/
- pScsiReq->TargetID = (u8) vdev->vtarget->id;
- pScsiReq->Bus = vdev->vtarget->channel;
+ pScsiReq->TargetID = (u8) vdevice->vtarget->id;
+ pScsiReq->Bus = vdevice->vtarget->channel;
pScsiReq->ChainOffset = 0;
- if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
else
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
@@ -1453,7 +1431,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
pScsiReq->DataLength = cpu_to_le32(datalen);
/* SenseBuffer low address */
- pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
/* Now add the SG list
@@ -1465,23 +1443,22 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
(dma_addr_t) -1);
} else {
/* Add a 32 or 64 bit SGE */
- if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
+ if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
goto fail;
}
SCpnt->host_scribble = (unsigned char *)mf;
- hd->ScsiLookup[my_idx] = SCpnt;
+ mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
- mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
ioc->name, SCpnt, mf, my_idx));
- DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
+ DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
return 0;
fail:
- hd->ScsiLookup[my_idx] = NULL;
- mptscsih_freeChainBuffers(hd->ioc, my_idx);
- mpt_free_msg_frame(hd->ioc, mf);
+ mptscsih_freeChainBuffers(ioc, my_idx);
+ mpt_free_msg_frame(ioc, mf);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1590,38 +1567,38 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
*/
if (mptscsih_tm_pending_wait(hd) == FAILED) {
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
"Timed out waiting for last TM (%d) to complete! \n",
ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
"reset: Timed out waiting for last TM (%d) "
"to complete! \n", ioc->name,
hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
"Timed out waiting for last TM (%d) to complete! \n",
ioc->name, hd->tmPending));
return FAILED;
}
} else {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
hd->tmPending |= (1 << type);
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
}
- ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
printk(MYIOC_s_WARN_FMT
"TM Handler for type=%x: IOC Not operational (0x%x)!\n",
ioc->name, type, ioc_raw_state);
- printk(KERN_WARNING " Issuing HardReset!!\n");
+ printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
- printk((KERN_WARNING "TMHandler: HardReset "
- "FAILED!!\n"));
+ printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
+ "FAILED!!\n", ioc->name);
return FAILED;
}
@@ -1680,16 +1657,17 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
SCSITaskMgmt_t *pScsiTm;
int ii;
int retval;
+ MPT_ADAPTER *ioc = hd->ioc;
/* Return Fail to calling function if no message frames available.
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+ ioc->name));
return FAILED;
}
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
- hd->ioc->name, mf));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+ ioc->name, mf));
/* Format the Request
*/
@@ -1712,28 +1690,34 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
pScsiTm->TaskMsgContext = ctx2abort;
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
- "type=%d\n", hd->ioc->name, ctx2abort, type));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+ "type=%d\n", ioc->name, ctx2abort, type));
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
- if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
- hd->ioc, mf, retval));
- goto fail_out;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
+ " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
+ ioc, mf, retval));
+ goto fail_out;
+ }
}
if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
- hd->ioc->name));
- retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
- hd->ioc->name, retval));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+ " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
+ ioc, mf));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+ ioc->name));
+ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
+ ioc->name, retval));
goto fail_out;
}
@@ -1754,7 +1738,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
/*
* Free task managment mf, and corresponding tm flags
*/
- mpt_free_msg_frame(hd->ioc, mf);
+ mpt_free_msg_frame(ioc, mf);
hd->tmPending = 0;
hd->tmState = TM_STATE_NONE;
return FAILED;
@@ -1797,11 +1781,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
- printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
- "host! (sc=%p)\n", SCpnt);
+ printk(KERN_ERR MYNAM ": task abort: "
+ "can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1812,8 +1796,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice = SCpnt->device->hostdata;
if (!vdevice || !vdevice->vtarget) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
- "deleted (sc=%p)\n", ioc->name, SCpnt));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: device has been deleted (sc=%p)\n",
+ ioc->name, SCpnt));
SCpnt->result = DID_NO_CONNECT << 16;
SCpnt->scsi_done(SCpnt);
retval = 0;
@@ -1823,8 +1808,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* Task aborts are not supported for hidden raid components.
*/
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
- "component (sc=%p)\n", ioc->name, SCpnt));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: hidden raid component (sc=%p)\n",
+ ioc->name, SCpnt));
SCpnt->result = DID_RESET << 16;
retval = FAILED;
goto out;
@@ -1832,12 +1818,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* Find this command
*/
- if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
/* Cmd not found in ScsiLookup.
* Do OS callback.
*/
SCpnt->result = DID_RESET << 16;
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
"Command not in the active list! (sc=%p)\n", ioc->name,
SCpnt));
retval = 0;
@@ -1859,7 +1845,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
* swap it here either. It is an opaque cookie to
* the controller, so it does not matter. -DaveM
*/
- mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+ mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
hd->abortSCpnt = SCpnt;
@@ -1868,7 +1854,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
ctx2abort, mptscsih_get_tm_timeout(ioc));
- if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
+ if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
SCpnt->serial_number == sn)
retval = FAILED;
@@ -1901,9 +1887,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt);
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": target reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1959,14 +1945,14 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
{
MPT_SCSI_HOST *hd;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt );
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": bus reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1978,9 +1964,9 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
if (hd->timeouts < -1)
hd->timeouts++;
- vdev = SCpnt->device->hostdata;
+ vdevice = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
- vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+ vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2008,9 +1994,9 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
MPT_ADAPTER *ioc;
/* If we can't locate the host to reset, then we failed. */
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt);
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": host reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -2021,7 +2007,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
/* If our attempts to reset the host failed, then return a failed
* status. The host will be taken off line by the SCSI mid-layer.
*/
- if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
retval = FAILED;
} else {
/* Make sure TM pending is cleared and TM state is set to
@@ -2051,17 +2037,18 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
unsigned long flags;
int loop_count = 4 * 10; /* Wait 10 seconds */
int status = FAILED;
+ MPT_ADAPTER *ioc = hd->ioc;
do {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
if (hd->tmState == TM_STATE_NONE) {
hd->tmState = TM_STATE_IN_PROGRESS;
hd->tmPending = 1;
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
status = SUCCESS;
break;
}
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
msleep(250);
} while (--loop_count);
@@ -2082,15 +2069,16 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
unsigned long flags;
int loop_count = 4 * timeout;
int status = FAILED;
+ MPT_ADAPTER *ioc = hd->ioc;
do {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
if(hd->tmPending == 0) {
status = SUCCESS;
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
break;
}
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
msleep(250);
} while (--loop_count);
@@ -2172,7 +2160,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
return 1;
}
- hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
pScsiTmReq = (SCSITaskMgmt_t*)mf;
tmType = pScsiTmReq->TaskType;
@@ -2223,7 +2211,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
hd->cmdPtr)
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
- printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+ printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
break;
case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
@@ -2366,7 +2354,7 @@ void
mptscsih_slave_destroy(struct scsi_device *sdev)
{
struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
@@ -2393,16 +2381,17 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
int
mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
struct scsi_target *starget;
int max_depth;
int tagged;
+ MPT_ADAPTER *ioc = hd->ioc;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
- if (hd->ioc->bus_type == SPI) {
+ if (ioc->bus_type == SPI) {
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
max_depth = 1;
else if (sdev->type == TYPE_DISK &&
@@ -2437,19 +2426,20 @@ mptscsih_slave_configure(struct scsi_device *sdev)
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sh);
+ MPT_ADAPTER *ioc = hd->ioc;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
vdevice = sdev->hostdata;
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"device @ %p, channel=%d, id=%d, lun=%d\n",
- hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
- if (hd->ioc->bus_type == SPI)
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
+ if (ioc->bus_type == SPI)
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"sdtr %d wdtr %d ppr %d inq length=%d\n",
- hd->ioc->name, sdev->sdtr, sdev->wdtr,
+ ioc->name, sdev->sdtr, sdev->wdtr,
sdev->ppr, sdev->inquiry_len));
if (sdev->id > sh->max_id) {
@@ -2461,21 +2451,21 @@ mptscsih_slave_configure(struct scsi_device *sdev)
vdevice->configured_lun = 1;
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Queue depth=%d, tflags=%x\n",
- hd->ioc->name, sdev->queue_depth, vtarget->tflags));
+ ioc->name, sdev->queue_depth, vtarget->tflags));
- if (hd->ioc->bus_type == SPI)
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ if (ioc->bus_type == SPI)
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
- hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
+ ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
slave_configure_exit:
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"tagged %d, simple %d, ordered %d\n",
- hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
+ ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
return 0;
@@ -2494,14 +2484,15 @@ slave_configure_exit:
static void
mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
{
- VirtDevice *vdev;
+ VirtDevice *vdevice;
SCSIIORequest_t *pReq;
u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
+ MPT_ADAPTER *ioc = hd->ioc;
/* Get target structure
*/
pReq = (SCSIIORequest_t *) mf;
- vdev = sc->device->hostdata;
+ vdevice = sc->device->hostdata;
if (sense_count) {
u8 *sense_data;
@@ -2509,15 +2500,14 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
/* Copy the sense received into the scsi command block. */
req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+ sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
/* Log SMART data (asc = 0x5D, non-IM case only) if required.
*/
- if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
- if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
+ if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+ if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
int idx;
- MPT_ADAPTER *ioc = hd->ioc;
idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
@@ -2530,36 +2520,116 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
ioc->eventContext++;
- if (hd->ioc->pcidev->vendor ==
+ if (ioc->pcidev->vendor ==
PCI_VENDOR_ID_IBM) {
- mptscsih_issue_sep_command(hd->ioc,
- vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
- vdev->vtarget->tflags |=
+ mptscsih_issue_sep_command(ioc,
+ vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+ vdevice->vtarget->tflags |=
MPT_TARGET_FLAGS_LED_ON;
}
}
}
} else {
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
- hd->ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
+ ioc->name));
}
}
-static int
-SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
+/**
+ * mptscsih_get_scsi_lookup
+ *
+ * retrieves scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
{
- MPT_SCSI_HOST *hd;
- int i;
+ unsigned long flags;
+ struct scsi_cmnd *scmd;
- hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ scmd = ioc->ScsiLookup[i];
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ return scmd;
+}
+
+/**
+ * mptscsih_getclear_scsi_lookup
+ *
+ * retrieves and clears scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
+{
+ unsigned long flags;
+ struct scsi_cmnd *scmd;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ scmd = ioc->ScsiLookup[i];
+ ioc->ScsiLookup[i] = NULL;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ return scmd;
+}
- for (i = 0; i < hd->ioc->req_depth; i++) {
- if (hd->ScsiLookup[i] == sc) {
- return i;
+/**
+ * mptscsih_set_scsi_lookup
+ *
+ * writes a scmd entry into the ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
+static void
+mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->ScsiLookup[i] = scmd;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+}
+
+/**
+ * SCPNT_TO_LOOKUP_IDX
+ *
+ * search's for a given scmd in the ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
+static int
+SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
+{
+ unsigned long flags;
+ int i, index=-1;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ for (i = 0; i < ioc->req_depth; i++) {
+ if (ioc->ScsiLookup[i] == sc) {
+ index = i;
+ goto out;
}
}
- return -1;
+ out:
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return index;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2568,21 +2638,20 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
MPT_SCSI_HOST *hd;
unsigned long flags;
- int ii;
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM
- ": IOC %s_reset routed to SCSI host driver!\n",
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": IOC %s_reset routed to SCSI host driver!\n",
+ ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
/* If a FW reload request arrives after base installed but
* before all scsi hosts have been attached, then an alt_ioc
* may have a NULL sh pointer.
*/
- if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+ if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
return 0;
else
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (reset_phase == MPT_IOC_SETUP_RESET) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
@@ -2624,11 +2693,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
* Init all control structures.
*/
- /* ScsiLookup initialization
- */
- for (ii=0; ii < hd->ioc->req_depth; ii++)
- hd->ScsiLookup[ii] = NULL;
-
/* 2. Chain Buffer initialization
*/
@@ -2675,7 +2739,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
ioc->name, event));
if (ioc->sh == NULL ||
- ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+ ((hd = shost_priv(ioc->sh)) == NULL))
return 1;
switch (event) {
@@ -2713,7 +2777,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_STATE_CHANGE: /* 02 */
case MPI_EVENT_EVENT_CHANGE: /* 0A */
default:
- dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
+ ioc->name, event));
break;
}
@@ -2753,7 +2818,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
int completionCode;
u16 req_idx;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if ((mf == NULL) ||
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
@@ -2765,17 +2830,17 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
del_timer(&hd->timer);
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- hd->ScsiLookup[req_idx] = NULL;
+ mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
pReq = (SCSIIORequest_t *) mf;
if (mf != hd->cmdPtr) {
printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
- hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+ ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
}
hd->cmdPtr = NULL;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
- hd->ioc->name, mf, mr, req_idx));
+ ioc->name, mf, mr, req_idx));
hd->pLocal = &hd->localReply;
hd->pLocal->scsiStatus = 0;
@@ -2839,15 +2904,15 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
*/
completionCode = MPT_SCANDV_SENSE;
hd->pLocal->scsiStatus = scsi_status;
- sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+ sense_data = ((u8 *)ioc->sense_buf_pool +
(req_idx * MPT_SENSE_BUFFER_ALLOC));
sz = min_t(int, pReq->SenseBufferLength,
SCSI_STD_SENSE_BYTES);
memcpy(hd->pLocal->sense, sense_data, sz);
- ddvprintk(ioc, printk(KERN_DEBUG " Check Condition, sense ptr %p\n",
- sense_data));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
+ ioc->name, sense_data));
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
if (pReq->CDB[0] == INQUIRY)
completionCode = MPT_SCANDV_ISSUE_SENSE;
@@ -2906,8 +2971,9 @@ void
mptscsih_timer_expired(unsigned long data)
{
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+ MPT_ADAPTER *ioc = hd->ioc;
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
if (hd->cmdPtr) {
MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
@@ -2921,13 +2987,13 @@ mptscsih_timer_expired(unsigned long data)
*/
} else {
/* Perform a FW reload */
- if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+ if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+ printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
}
}
} else {
/* This should NEVER happen */
- printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+ printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
}
/* No more processing.
@@ -2935,7 +3001,7 @@ mptscsih_timer_expired(unsigned long data)
* The FW will reply to all outstanding commands, callback will finish cleanup.
* Hard reset clean-up will free all resources.
*/
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
return;
}
@@ -2973,11 +3039,12 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
char cmdLen;
char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char cmd = io->cmd;
+ MPT_ADAPTER *ioc = hd->ioc;
in_isr = in_interrupt();
if (in_isr) {
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
- hd->ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+ ioc->name));
return -EPERM;
}
@@ -3078,9 +3145,9 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
/* Get and Populate a free Frame
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
+ ioc->name));
return -EBUSY;
}
@@ -3119,19 +3186,19 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
if (cmd == REQUEST_SENSE) {
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
- hd->ioc->name, cmd));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
+ ioc->name, cmd));
}
for (ii=0; ii < 16; ii++)
pScsiReq->CDB[ii] = CDB[ii];
pScsiReq->DataLength = cpu_to_le32(io->size);
- pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
- hd->ioc->name, cmd, io->channel, io->id, io->lun));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+ ioc->name, cmd, io->channel, io->id, io->lun));
if (dir == MPI_SCSIIO_CONTROL_READ) {
mpt_add_sge((char *) &pScsiReq->SGL,
@@ -3166,7 +3233,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
hd->cmdPtr = mf;
add_timer(&hd->timer);
- mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
wait_event(hd->scandv_waitq, hd->scandv_wait_done);
if (hd->pLocal) {
@@ -3182,8 +3249,8 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
} else {
rc = -EFAULT;
/* This should never happen. */
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
- hd->ioc->name));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
+ ioc->name));
}
return rc;
@@ -3235,7 +3302,7 @@ static ssize_t
mptscsih_version_fw_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
@@ -3250,7 +3317,7 @@ static ssize_t
mptscsih_version_bios_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
@@ -3265,7 +3332,7 @@ static ssize_t
mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
@@ -3276,7 +3343,7 @@ static ssize_t
mptscsih_version_product_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
@@ -3288,7 +3355,7 @@ static ssize_t
mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",
@@ -3301,7 +3368,7 @@ static ssize_t
mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
@@ -3313,7 +3380,7 @@ static ssize_t
mptscsih_board_name_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
@@ -3324,7 +3391,7 @@ static ssize_t
mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
@@ -3336,7 +3403,7 @@ static ssize_t
mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
@@ -3348,7 +3415,7 @@ static ssize_t
mptscsih_io_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
@@ -3360,7 +3427,7 @@ static ssize_t
mptscsih_device_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
@@ -3372,7 +3439,7 @@ static ssize_t
mptscsih_debug_level_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
@@ -3382,7 +3449,7 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
int val = 0;
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 67b088db2f1..d289e97cfe8 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -3,9 +3,9 @@
* High performance SCSI / Fibre Channel SCSI Host device driver.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 8c98420640a..25bcfcf36f2 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptspi.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -90,9 +90,9 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *,
static struct scsi_transport_template *mptspi_transport_template = NULL;
-static int mptspiDoneCtx = -1;
-static int mptspiTaskCtx = -1;
-static int mptspiInternalCtx = -1; /* Used only for internal commands */
+static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
/**
* mptspi_setTargetNegoParms - Update the target negotiation parameters
@@ -107,7 +107,8 @@ static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
struct scsi_device *sdev)
{
- SpiCfgData *pspi_data = &hd->ioc->spi_data;
+ MPT_ADAPTER *ioc = hd->ioc;
+ SpiCfgData *pspi_data = &ioc->spi_data;
int id = (int) target->id;
int nvram;
u8 width = MPT_NARROW;
@@ -138,9 +139,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
else {
factor = MPT_ULTRA320;
if (scsi_device_qas(sdev)) {
- ddvprintk(hd->ioc,
- printk(KERN_DEBUG "Enabling QAS due to "
- "byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+ ddvprintk(ioc,
+ printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
+ "byte56=%02x on id=%d!\n", ioc->name,
+ scsi_device_qas(sdev), id));
noQas = 0;
}
if (sdev->type == TYPE_TAPE &&
@@ -227,8 +229,8 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
/* Disable QAS in a mixed configuration case
*/
- ddvprintk(hd->ioc, printk(KERN_DEBUG
- "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
}
}
@@ -302,7 +304,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
@@ -374,14 +376,15 @@ static int
mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
{
int i, rc = 0;
+ MPT_ADAPTER *ioc = hd->ioc;
- if (!hd->ioc->raid_data.pIocPg2)
+ if (!ioc->raid_data.pIocPg2)
goto out;
- if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
+ if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
- for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
- if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
+ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
rc = 1;
goto out;
}
@@ -394,17 +397,19 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
static int mptspi_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
VirtTarget *vtarget;
+ MPT_ADAPTER *ioc;
if (hd == NULL)
return -ENODEV;
+ ioc = hd->ioc;
vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
if (!vtarget)
return -ENOMEM;
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
vtarget->id = (u8)starget->id;
vtarget->channel = (u8)starget->channel;
@@ -412,34 +417,34 @@ static int mptspi_target_alloc(struct scsi_target *starget)
starget->hostdata = vtarget;
if (starget->channel == 1) {
- if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
+ if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
return 0;
vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
/* The real channel for this device is zero */
vtarget->channel = 0;
/* The actual physdisknum (for RAID passthrough) */
- vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
+ vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
starget->id);
}
if (starget->channel == 0 &&
mptspi_is_raid(hd, starget->id)) {
vtarget->raidVolume = 1;
- ddvprintk(hd->ioc, printk(KERN_DEBUG
- "RAID Volume @ channel=%d id=%d\n", starget->channel,
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
starget->id));
}
- if (hd->ioc->spi_data.nvram &&
- hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
- u32 nvram = hd->ioc->spi_data.nvram[starget->id];
+ if (ioc->spi_data.nvram &&
+ ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
+ u32 nvram = ioc->spi_data.nvram[starget->id];
spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
} else {
- spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor;
- spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth;
+ spi_min_period(starget) = ioc->spi_data.minSyncFactor;
+ spi_max_width(starget) = ioc->spi_data.maxBusWidth;
}
- spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset;
+ spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
spi_offset(starget) = 0;
mptspi_write_width(starget, 0);
@@ -509,10 +514,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
struct _MPT_ADAPTER *ioc = hd->ioc;
- struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0;
- dma_addr_t pg0_dma;
+ struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
+ dma_addr_t spi_dev_pg0_dma;
int size;
struct _x_config_parms cfg;
struct _CONFIG_PAGE_HEADER hdr;
@@ -530,9 +535,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
size += 2048;
*/
- pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL);
- if (pg0 == NULL) {
- starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+ spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
+ if (spi_dev_pg0 == NULL) {
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "dma_alloc_coherent for parameters failed\n", ioc->name);
return -EINVAL;
}
@@ -546,22 +552,22 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
memset(&cfg, 0, sizeof(cfg));
cfg.cfghdr.hdr = &hdr;
- cfg.physAddr = pg0_dma;
+ cfg.physAddr = spi_dev_pg0_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.pageAddr = starget->id;
if (mpt_config(ioc, &cfg)) {
- starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
- memcpy(pass_pg0, pg0, size);
+ memcpy(pass_pg0, spi_dev_pg0, size);
- mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters));
+ mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
out_free:
- dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma);
+ dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
return err;
}
@@ -588,11 +594,11 @@ static u32 mptspi_getRP(struct scsi_target *starget)
static void mptspi_read_parameters(struct scsi_target *starget)
{
int nego;
- struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0;
+ struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
- mptspi_read_spi_device_pg0(starget, &pg0);
+ mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
- nego = le32_to_cpu(pg0.NegotiatedParameters);
+ nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
@@ -612,12 +618,13 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
{
MpiRaidActionRequest_t *pReq;
MPT_FRAME_HDR *mf;
+ MPT_ADAPTER *ioc = hd->ioc;
/* Get and Populate a free Frame
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+ ioc->name));
return -EAGAIN;
}
pReq = (MpiRaidActionRequest_t *)mf;
@@ -638,8 +645,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
mpt_add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
- hd->ioc->name, pReq->Action, channel, id));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+ ioc->name, pReq->Action, channel, id));
hd->pLocal = NULL;
hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
@@ -651,7 +658,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
hd->cmdPtr = mf;
add_timer(&hd->timer);
- mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
wait_event(hd->scandv_waitq, hd->scandv_wait_done);
if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
@@ -664,6 +671,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
struct scsi_device *sdev)
{
VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
/* no DV on RAID devices */
if (sdev->channel == 0 &&
@@ -673,8 +681,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
/* If this is a piece of a RAID, then quiesce first */
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
- starget_printk(KERN_ERR, scsi_target(sdev),
- "Integrated RAID quiesce failed\n");
+ starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+ "Integrated RAID quiesce failed\n", ioc->name);
return;
}
@@ -684,8 +692,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
- starget_printk(KERN_ERR, scsi_target(sdev),
- "Integrated RAID resume failed\n");
+ starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+ "Integrated RAID resume failed\n", ioc->name);
mptspi_read_parameters(sdev->sdev_target);
spi_display_xfer_agreement(sdev->sdev_target);
@@ -694,28 +702,29 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
static int mptspi_slave_alloc(struct scsi_device *sdev)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
+ MPT_ADAPTER *ioc = hd->ioc;
if (sdev->channel == 1 &&
- mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
+ mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
return -ENXIO;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
- vdev->lun = sdev->lun;
- sdev->hostdata = vdev;
+ vdevice->lun = sdev->lun;
+ sdev->hostdata = vdevice;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
- vdev->vtarget = vtarget;
+ vdevice->vtarget = vtarget;
vtarget->num_luns++;
if (sdev->channel == 1)
@@ -726,8 +735,7 @@ static int mptspi_slave_alloc(struct scsi_device *sdev)
static int mptspi_slave_configure(struct scsi_device *sdev)
{
- struct _MPT_SCSI_HOST *hd =
- (struct _MPT_SCSI_HOST *)sdev->host->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget = scsi_target(sdev)->hostdata;
int ret;
@@ -755,24 +763,25 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
static int
mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+ VirtDevice *vdevice = SCpnt->device->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
- if (!vdev || !vdev->vtarget) {
+ if (!vdevice || !vdevice->vtarget) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
if (SCpnt->device->channel == 1 &&
- mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
+ mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
if (spi_dv_pending(scsi_target(SCpnt->device)))
- ddvprintk(hd->ioc, scsi_print_command(SCpnt));
+ ddvprintk(ioc, scsi_print_command(SCpnt));
return mptscsih_qcmd(SCpnt,done);
}
@@ -829,7 +838,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
struct _MPT_ADAPTER *ioc = hd->ioc;
struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
dma_addr_t pg1_dma;
@@ -847,7 +856,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
if (pg1 == NULL) {
- starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "dma_alloc_coherent for parameters failed\n", ioc->name);
return -EINVAL;
}
@@ -876,7 +886,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
if (mpt_config(ioc, &cfg)) {
- starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
@@ -1015,7 +1026,7 @@ static void mptspi_write_qas(struct scsi_target *starget, int qas)
{
struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
VirtTarget *vtarget = starget->hostdata;
u32 nego;
@@ -1067,15 +1078,16 @@ static void mpt_work_wrapper(struct work_struct *work)
struct work_queue_wrapper *wqw =
container_of(work, struct work_queue_wrapper, work);
struct _MPT_SCSI_HOST *hd = wqw->hd;
- struct Scsi_Host *shost = hd->ioc->sh;
+ MPT_ADAPTER *ioc = hd->ioc;
+ struct Scsi_Host *shost = ioc->sh;
struct scsi_device *sdev;
int disk = wqw->disk;
struct _CONFIG_PAGE_IOC_3 *pg3;
kfree(wqw);
- mpt_findImVolumes(hd->ioc);
- pg3 = hd->ioc->raid_data.pIocPg3;
+ mpt_findImVolumes(ioc);
+ pg3 = ioc->raid_data.pIocPg3;
if (!pg3)
return;
@@ -1092,24 +1104,25 @@ static void mpt_work_wrapper(struct work_struct *work)
if(vtarget->id != disk)
continue;
- starget_printk(KERN_INFO, vtarget->starget,
- "Integrated RAID requests DV of new device\n");
+ starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
+ "Integrated RAID requests DV of new device\n", ioc->name);
mptspi_dv_device(hd, sdev);
}
- shost_printk(KERN_INFO, shost,
- "Integrated RAID detects new device %d\n", disk);
- scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1);
+ shost_printk(KERN_INFO, shost, MYIOC_s_FMT
+ "Integrated RAID detects new device %d\n", ioc->name, disk);
+ scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
}
static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
{
struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
+ MPT_ADAPTER *ioc = hd->ioc;
if (!wqw) {
- shost_printk(KERN_ERR, hd->ioc->sh,
- "Failed to act on RAID event for physical disk %d\n",
- disk);
+ shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
+ "Failed to act on RAID event for physical disk %d\n",
+ ioc->name, disk);
return;
}
INIT_WORK(&wqw->work, mpt_work_wrapper);
@@ -1123,7 +1136,7 @@ static int
mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
int reason
@@ -1190,6 +1203,8 @@ static struct spi_function_template mptspi_transport_functions = {
static struct pci_device_id mptspi_pci_table[] = {
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
+ PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
@@ -1210,11 +1225,12 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
struct scsi_target *starget;
struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
u32 nego;
+ MPT_ADAPTER *ioc = hd->ioc;
kfree(wqw);
if (hd->spi_pending) {
- shost_for_each_device(sdev, hd->ioc->sh) {
+ shost_for_each_device(sdev, ioc->sh) {
if (hd->spi_pending & (1 << sdev->id))
continue;
starget = scsi_target(sdev);
@@ -1225,7 +1241,7 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
mptspi_write_spi_device_pg1(starget, &pg1);
}
} else {
- shost_for_each_device(sdev, hd->ioc->sh)
+ shost_for_each_device(sdev, ioc->sh)
mptspi_dv_device(hd, sdev);
}
}
@@ -1250,7 +1266,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
static int
mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
@@ -1269,7 +1285,7 @@ static int
mptspi_resume(struct pci_dev *pdev)
{
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_resume(pdev);
@@ -1416,7 +1432,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Resetting sg_tablesize to %d from %d\n",
ioc->name, numSGE, sh->sg_tablesize));
sh->sg_tablesize = numSGE;
@@ -1424,20 +1440,21 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
goto out_mptspi_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -1477,13 +1494,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Some versions of the firmware don't support page 0; without
* that we can't get the parameters */
- if (hd->ioc->spi_data.sdp0length != 0)
+ if (ioc->spi_data.sdp0length != 0)
sh->transportt = mptspi_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptspi_probe;
}
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6c0b2f0a51a..81e068fa7ac 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -517,7 +517,7 @@ static char *next_cmd(char **cmds)
****************************************************************************/
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct device *tpacpi_hwmon;
static struct input_dev *tpacpi_inputdev;
@@ -945,15 +945,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
- KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
+ KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
- KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+ KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -974,9 +974,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 082a1cbc16c..acd5835ec88 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -171,7 +171,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
/* Device model */
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver;
static struct input_dev *tpacpi_inputdev;
static int tpacpi_create_driver_attributes(struct device_driver *drv);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d195fb088f4..8f77949f93d 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
- int i = 0;
- int length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "TIFM_CARD_TYPE=%s",
- tifm_media_type_name(sock->type, 1)))
+ if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
return -ENOMEM;
return 0;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8d6f6014870..b0c22cad942 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
- int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mmc_card *card = dev_to_mmc_card(dev);
const char *type;
- int i = 0, length = 0;
+ int retval = 0;
switch (card->type) {
case MMC_TYPE_MMC:
@@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
}
if (type) {
- if (add_uevent_var(envp, num_envp, &i,
- buf, buf_size, &length,
- "MMC_TYPE=%s", type))
- return -ENOMEM;
+ retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+ if (retval)
+ return retval;
}
- if (add_uevent_var(envp, num_envp, &i,
- buf, buf_size, &length,
- "MMC_NAME=%s", mmc_card_name(card)))
- return -ENOMEM;
+ retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
- envp[i] = NULL;
-
- return 0;
+ return retval;
}
static int mmc_bus_probe(struct device *dev)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 64fbc9759a3..c65d203a846 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
- led_trigger_unregister(host->led);
+ led_trigger_unregister_simple(host->led);
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 0713a8c71e5..233d0f9b3c4 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -96,30 +96,23 @@ static int sdio_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
- int buf_size)
+sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct sdio_func *func = dev_to_sdio_func(dev);
- int i = 0, length = 0;
- if (add_uevent_var(envp, num_envp, &i,
- buf, buf_size, &length,
+ if (add_uevent_var(env,
"SDIO_CLASS=%02X", func->class))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buf, buf_size, &length,
+ if (add_uevent_var(env,
"SDIO_ID=%04X:%04X", func->vendor, func->device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buf, buf_size, &length,
+ if (add_uevent_var(env,
"MODALIAS=sdio:c%02Xv%04Xd%04X",
func->class, func->vendor, func->device))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index f30327bba6f..254b194e762 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -26,7 +26,7 @@
*/
#include <linux/hrtimer.h>
#include <linux/delay.h>
-#include <linux/blkdev.h>
+#include <linux/bio.h>
#include <linux/dma-mapping.h>
#include <linux/crc7.h>
#include <linux/crc-itu-t.h>
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index fbec8cd55e3..8848e8ac705 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -278,6 +278,14 @@ config SSFDC
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
+config MTD_OOPS
+ tristate "Log panic/oops to an MTD buffer"
+ depends on MTD
+ help
+ This enables panic and oops messages to be logged to a circular
+ buffer in a flash partition where it can be read back at some
+ later point.
+
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 6d958a4566f..7f0b04b4caa 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_NFTL) += nftl.o
obj-$(CONFIG_INFTL) += inftl.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
obj-$(CONFIG_SSFDC) += ssfdc.o
+obj-$(CONFIG_MTD_OOPS) += mtdoops.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 2f19fa78d24..3aa3dca56ae 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -526,7 +526,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
/*
- * Probing of multi-partition flash ships.
+ * Probing of multi-partition flash chips.
*
* To support multiple partitions when available, we simply arrange
* for each of them to have their own flchip structure even if they
@@ -653,7 +653,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
resettime:
timeo = jiffies + HZ;
retry:
- if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
/*
* OK. We have possibility for contension on the write/erase
* operations which are global to the real chip and not per
@@ -798,6 +798,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (mode == FL_READY && chip->oldstate == FL_READY)
return 0;
+ case FL_SHUTDOWN:
+ /* The machine is rebooting now,so no one can get chip anymore */
+ return -EIO;
default:
sleep:
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1166,28 +1169,34 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- unsigned long ofs;
+ unsigned long ofs, last_end = 0;
int chipnum;
int ret = 0;
if (!map->virt || (from + len > mtd->size))
return -EINVAL;
- *mtdbuf = (void *)map->virt + from;
- *retlen = 0;
-
/* Now lock the chip(s) to POINT state */
/* ofs: offset within the first chip that the first read should start */
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
+ *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+ *retlen = 0;
+
while (len) {
unsigned long thislen;
if (chipnum >= cfi->numchips)
break;
+ /* We cannot point across chips that are virtually disjoint */
+ if (!last_end)
+ last_end = cfi->chips[chipnum].start;
+ else if (cfi->chips[chipnum].start != last_end)
+ break;
+
if ((len + ofs -1) >> cfi->chipshift)
thislen = (1<<cfi->chipshift) - ofs;
else
@@ -1201,6 +1210,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
len -= thislen;
ofs = 0;
+ last_end += 1 << cfi->chipshift;
chipnum++;
}
return 0;
@@ -1780,7 +1790,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
return ret;
}
-int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
unsigned long ofs, len;
int ret;
@@ -1930,7 +1940,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
__FUNCTION__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1940,7 +1950,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
__FUNCTION__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
return ret;
@@ -1954,7 +1964,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
__FUNCTION__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1964,7 +1974,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
__FUNCTION__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
return ret;
@@ -2255,7 +2265,7 @@ static void cfi_intelext_save_locks(struct mtd_info *mtd)
adr = region->offset + block * len;
status = cfi_varsize_frob(mtd,
- do_getlockstatus_oneblock, adr, len, 0);
+ do_getlockstatus_oneblock, adr, len, NULL);
if (status)
set_bit(block, region->lockmap);
else
@@ -2402,10 +2412,10 @@ static int cfi_intelext_reset(struct mtd_info *mtd)
and switch to array mode so any bootloader in
flash is accessible for soft reboot. */
spin_lock(chip->mutex);
- ret = get_chip(map, chip, chip->start, FL_SYNCING);
+ ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
if (!ret) {
map_write(map, CMD(0xff), chip->start);
- chip->state = FL_READY;
+ chip->state = FL_SHUTDOWN;
}
spin_unlock(chip->mutex);
}
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 1f644584046..389acc600f5 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1609,7 +1609,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
}
-int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
unsigned long ofs, len;
int ret;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 58e561e8769..a67b23b87fc 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@@ -70,6 +69,7 @@
/* Fujitsu */
#define MBM29F040C 0x00A4
+#define MBM29F800BA 0x2258
#define MBM29LV650UE 0x22D7
#define MBM29LV320TE 0x22F6
#define MBM29LV320BE 0x22F9
@@ -129,6 +129,7 @@
#define LH28F640BF 0x00b0
/* ST - www.st.com */
+#define M29F800AB 0x0058
#define M29W800DT 0x00D7
#define M29W800DB 0x005B
#define M29W160DT 0x22C4
@@ -646,6 +647,23 @@ static const struct amd_flash_info jedec_table[] = {
}
}, {
.mfr_id = MANUFACTURER_FUJITSU,
+ .dev_id = MBM29F800BA,
+ .name = "Fujitsu MBM29F800BA",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,15),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_FUJITSU,
.dev_id = MBM29LV650UE,
.name = "Fujitsu MBM29LV650UE",
.uaddr = {
@@ -1510,6 +1528,23 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256)
}
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M29F800AB,
+ .name = "ST M29F800AB",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,15),
+ }
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
.dev_id = M29W800DT,
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index ff642f8fbee..811d56fd890 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -60,21 +60,22 @@ config MTD_DATAFLASH
Sometimes DataFlash chips are packaged inside MMC-format
cards; at this writing, the MMC stack won't handle those.
-config MTD_DATAFLASH26
- tristate "AT91RM9200 DataFlash AT26xxx"
- depends on MTD && ARCH_AT91RM9200 && AT91_SPI
- help
- This enables access to the DataFlash chip (AT26xxx) on an
- AT91RM9200-based board.
- If you have such a board and such a DataFlash, say 'Y'.
-
config MTD_M25P80
- tristate "Support for M25 SPI Flash"
+ tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI_MASTER && EXPERIMENTAL
help
- This enables access to ST M25P80 and similar SPI flash chips,
- used for program and data storage. Set up your spi devices
- with the right board-specific platform data.
+ This enables access to most modern SPI flash chips, used for
+ program and data storage. Series supported include Atmel AT26DF,
+ Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips
+ are supported as well. See the driver source for the current list,
+ or to add other chips.
+
+ Note that the original DataFlash chips (AT45 series, not AT26DF),
+ need an entirely different driver.
+
+ Set up your spi devices with the right board-specific platform data,
+ if you want to specify device partitioning or to use a device which
+ doesn't support the JEDEC ID instruction.
config MTD_SLRAM
tristate "Uncached system RAM"
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 8ab568b3f53..0f788d5c4bf 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
-obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c
deleted file mode 100644
index 64ce37f986f..00000000000
--- a/drivers/mtd/devices/at91_dataflash26.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
- * This is a largely modified version of at91_dataflash.c that
- * supports AT26xxx dataflash chips. The original driver supports
- * AT45xxx chips.
- *
- * Note: This driver was only tested with an AT26F004. It should be
- * easy to make it work with other AT26xxx dataflash devices, though.
- *
- * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
- * original Copyright (C) SAN People (Pty) Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-
-#include <asm/arch/at91_spi.h>
-
-#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */
-
-#define MANUFACTURER_ID_ATMEL 0x1F
-
-/* command codes */
-
-#define AT26_OP_READ_STATUS 0x05
-#define AT26_OP_READ_DEV_ID 0x9F
-#define AT26_OP_ERASE_PAGE_4K 0x20
-#define AT26_OP_READ_ARRAY_FAST 0x0B
-#define AT26_OP_SEQUENTIAL_WRITE 0xAF
-#define AT26_OP_WRITE_ENABLE 0x06
-#define AT26_OP_WRITE_DISABLE 0x04
-#define AT26_OP_SECTOR_PROTECT 0x36
-#define AT26_OP_SECTOR_UNPROTECT 0x39
-
-/* status register bits */
-
-#define AT26_STATUS_BUSY 0x01
-#define AT26_STATUS_WRITE_ENABLE 0x02
-
-struct dataflash_local
-{
- int spi; /* SPI chip-select number */
- unsigned int page_size; /* number of bytes per page */
-};
-
-
-/* Detected DataFlash devices */
-static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
-static int nr_devices = 0;
-
-/* Allocate a single SPI transfer descriptor. We're assuming that if multiple
- SPI transfers occur at the same time, spi_access_bus() will serialize them.
- If this is not valid, then either (i) each dataflash 'priv' structure
- needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
- another mechanism. */
-static struct spi_transfer_list* spi_transfer_desc;
-
-/*
- * Perform a SPI transfer to access the DataFlash device.
- */
-static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
- char* txnext, int txnext_len, char* rxnext, int rxnext_len)
-{
- struct spi_transfer_list* list = spi_transfer_desc;
-
- list->tx[0] = tx; list->txlen[0] = tx_len;
- list->rx[0] = rx; list->rxlen[0] = rx_len;
-
- list->tx[1] = txnext; list->txlen[1] = txnext_len;
- list->rx[1] = rxnext; list->rxlen[1] = rxnext_len;
-
- list->nr_transfers = nr;
- /* Note: spi_transfer() always returns 0, there are no error checks */
- return spi_transfer(list);
-}
-
-/*
- * Return the status of the DataFlash device.
- */
-static unsigned char at91_dataflash26_status(void)
-{
- unsigned char command[2];
-
- command[0] = AT26_OP_READ_STATUS;
- command[1] = 0;
-
- do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
-
- return command[1];
-}
-
-/*
- * Poll the DataFlash device until it is READY.
- */
-static unsigned char at91_dataflash26_waitready(void)
-{
- unsigned char status;
-
- while (1) {
- status = at91_dataflash26_status();
- if (!(status & AT26_STATUS_BUSY))
- return status;
- }
-}
-
-/*
- * Enable/disable write access
- */
- static void at91_dataflash26_write_enable(int enable)
-{
- unsigned char cmd[2];
-
- DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
-
- if (enable)
- cmd[0] = AT26_OP_WRITE_ENABLE;
- else
- cmd[0] = AT26_OP_WRITE_DISABLE;
- cmd[1] = 0;
-
- do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
-}
-
-/*
- * Protect/unprotect sector
- */
- static void at91_dataflash26_sector_protect(loff_t addr, int protect)
-{
- unsigned char cmd[4];
-
- DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
- addr, protect);
-
- if (protect)
- cmd[0] = AT26_OP_SECTOR_PROTECT;
- else
- cmd[0] = AT26_OP_SECTOR_UNPROTECT;
- cmd[1] = (addr & 0x00FF0000) >> 16;
- cmd[2] = (addr & 0x0000FF00) >> 8;
- cmd[3] = (addr & 0x000000FF);
-
- do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
-}
-
-/*
- * Erase blocks of flash.
- */
-static int at91_dataflash26_erase(struct mtd_info *mtd,
- struct erase_info *instr)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned char cmd[4];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
- instr->addr, instr->len);
-
- /* Sanity checks */
- if (priv->page_size != 4096)
- return -EINVAL; /* Can't handle other sizes at the moment */
-
- if ( ((instr->len % mtd->erasesize) != 0)
- || ((instr->len % priv->page_size) != 0)
- || ((instr->addr % priv->page_size) != 0)
- || ((instr->addr + instr->len) > mtd->size))
- return -EINVAL;
-
- spi_access_bus(priv->spi);
-
- while (instr->len > 0) {
- at91_dataflash26_write_enable(1);
- at91_dataflash26_sector_protect(instr->addr, 0);
- at91_dataflash26_write_enable(1);
- cmd[0] = AT26_OP_ERASE_PAGE_4K;
- cmd[1] = (instr->addr & 0x00FF0000) >> 16;
- cmd[2] = (instr->addr & 0x0000FF00) >> 8;
- cmd[3] = (instr->addr & 0x000000FF);
-
- DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
- "0x%02x\n",
- cmd[0], cmd[1], cmd[2], cmd[3]);
-
- do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
- at91_dataflash26_waitready();
-
- instr->addr += priv->page_size; /* next page */
- instr->len -= priv->page_size;
- }
-
- at91_dataflash26_write_enable(0);
- spi_release_bus(priv->spi);
-
- /* Inform MTD subsystem that erase is complete */
- instr->state = MTD_ERASE_DONE;
- if (instr->callback)
- instr->callback(instr);
-
- return 0;
-}
-
-/*
- * Read from the DataFlash device.
- * from : Start offset in flash device
- * len : Number of bytes to read
- * retlen : Number of bytes actually read
- * buf : Buffer that will receive data
- */
-static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned char cmd[5];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
- from, from+len);
-
- *retlen = 0;
-
- /* Sanity checks */
- if (!len)
- return 0;
- if (from + len > mtd->size)
- return -EINVAL;
-
- cmd[0] = AT26_OP_READ_ARRAY_FAST;
- cmd[1] = (from & 0x00FF0000) >> 16;
- cmd[2] = (from & 0x0000FF00) >> 8;
- cmd[3] = (from & 0x000000FF);
- /* cmd[4] is a "Don't care" byte */
-
- DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
- cmd[0], cmd[1], cmd[2], cmd[3]);
-
- spi_access_bus(priv->spi);
- do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
- spi_release_bus(priv->spi);
-
- *retlen = len;
- return 0;
-}
-
-/*
- * Write to the DataFlash device.
- * to : Start offset in flash device
- * len : Number of bytes to write
- * retlen : Number of bytes actually written
- * buf : Buffer containing the data
- */
-static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned int addr, buf_index = 0;
- int ret = -EIO, sector, last_sector;
- unsigned char status, cmd[5];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
-
- *retlen = 0;
-
- /* Sanity checks */
- if (!len)
- return 0;
- if (to + len > mtd->size)
- return -EINVAL;
-
- spi_access_bus(priv->spi);
-
- addr = to;
- last_sector = -1;
-
- while (buf_index < len) {
- sector = addr / priv->page_size;
- /* Write first byte if a new sector begins */
- if (sector != last_sector) {
- at91_dataflash26_write_enable(1);
- at91_dataflash26_sector_protect(addr, 0);
- at91_dataflash26_write_enable(1);
-
- /* Program first byte of a new sector */
- cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
- cmd[1] = (addr & 0x00FF0000) >> 16;
- cmd[2] = (addr & 0x0000FF00) >> 8;
- cmd[3] = (addr & 0x000000FF);
- cmd[4] = buf[buf_index++];
- do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
- status = at91_dataflash26_waitready();
- addr++;
- /* On write errors, the chip resets the write enable
- flag. This also happens after the last byte of a
- sector is successfully programmed. */
- if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
- && ((addr % priv->page_size) != 0) ) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "write error1: addr=0x%06x, "
- "status=0x%02x\n", addr, status);
- goto write_err;
- }
- (*retlen)++;
- last_sector = sector;
- }
-
- /* Write subsequent bytes in the same sector */
- cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
- cmd[1] = buf[buf_index++];
- do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
- status = at91_dataflash26_waitready();
- addr++;
-
- if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
- && ((addr % priv->page_size) != 0) ) {
- DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
- "status=0x%02x\n", addr, status);
- goto write_err;
- }
-
- (*retlen)++;
- }
-
- ret = 0;
- at91_dataflash26_write_enable(0);
-write_err:
- spi_release_bus(priv->spi);
- return ret;
-}
-
-/*
- * Initialize and register DataFlash device with MTD subsystem.
- */
-static int __init add_dataflash(int channel, char *name, int nr_pages,
- int pagesize)
-{
- struct mtd_info *device;
- struct dataflash_local *priv;
-
- if (nr_devices >= DATAFLASH_MAX_DEVICES) {
- printk(KERN_ERR "at91_dataflash26: Too many devices "
- "detected\n");
- return 0;
- }
-
- device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
- GFP_KERNEL);
- if (!device)
- return -ENOMEM;
-
- device->name = (char *)&device[1];
- sprintf(device->name, "%s.spi%d", name, channel);
- device->size = nr_pages * pagesize;
- device->erasesize = pagesize;
- device->owner = THIS_MODULE;
- device->type = MTD_DATAFLASH;
- device->flags = MTD_CAP_NORFLASH;
- device->erase = at91_dataflash26_erase;
- device->read = at91_dataflash26_read;
- device->write = at91_dataflash26_write;
-
- priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
- GFP_KERNEL);
- if (!priv) {
- kfree(device);
- return -ENOMEM;
- }
-
- priv->spi = channel;
- priv->page_size = pagesize;
- device->priv = priv;
-
- mtd_devices[nr_devices] = device;
- nr_devices++;
- printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
- name, channel, device->size);
-
- return add_mtd_device(device);
-}
-
-/*
- * Detect and initialize DataFlash device connected to specified SPI channel.
- *
- */
-
-struct dataflash26_types {
- unsigned char id0;
- unsigned char id1;
- char *name;
- int pagesize;
- int nr_pages;
-};
-
-struct dataflash26_types df26_types[] = {
- {
- .id0 = 0x04,
- .id1 = 0x00,
- .name = "AT26F004",
- .pagesize = 4096,
- .nr_pages = 128,
- },
- {
- .id0 = 0x45,
- .id1 = 0x01,
- .name = "AT26DF081A", /* Not tested ! */
- .pagesize = 4096,
- .nr_pages = 256,
- },
-};
-
-static int __init at91_dataflash26_detect(int channel)
-{
- unsigned char status, cmd[5];
- int i;
-
- spi_access_bus(channel);
- status = at91_dataflash26_status();
-
- if (status == 0 || status == 0xff) {
- printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
- status);
- spi_release_bus(channel);
- return -ENODEV;
- }
-
- cmd[0] = AT26_OP_READ_DEV_ID;
- do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
- spi_release_bus(channel);
-
- if (cmd[1] != MANUFACTURER_ID_ATMEL)
- return -ENODEV;
-
- for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
- if ( cmd[2] == df26_types[i].id0
- && cmd[3] == df26_types[i].id1)
- return add_dataflash(channel,
- df26_types[i].name,
- df26_types[i].nr_pages,
- df26_types[i].pagesize);
- }
-
- printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
- "(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
- return -ENODEV;
-}
-
-static int __init at91_dataflash26_init(void)
-{
- spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
- GFP_KERNEL);
- if (!spi_transfer_desc)
- return -ENOMEM;
-
- /* DataFlash (SPI chip select 0) */
- at91_dataflash26_detect(0);
-
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
- /* DataFlash card (SPI chip select 3) */
- at91_dataflash26_detect(3);
-#endif
- return 0;
-}
-
-static void __exit at91_dataflash26_exit(void)
-{
- int i;
-
- for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
- if (mtd_devices[i]) {
- del_mtd_device(mtd_devices[i]);
- kfree(mtd_devices[i]->priv);
- kfree(mtd_devices[i]);
- }
- }
- nr_devices = 0;
- kfree(spi_transfer_desc);
-}
-
-module_init(at91_dataflash26_init);
-module_exit(at91_dataflash26_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Hans J. Koch");
-MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index 54aa7590764..d8cc94ec4e5 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -81,9 +81,7 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
- 0xff000000,
-##else
+#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 78c2511ae9e..98df5bcc02f 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -1,5 +1,5 @@
/*
- * MTD SPI driver for ST M25Pxx flash chips
+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*
* Author: Mike Lavender, mike@steroidmicros.com
*
@@ -19,33 +19,32 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
-#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
-#include <asm/semaphore.h>
-
-
-/* NOTE: AT 25F and SST 25LF series are very similar,
- * but commands for sector erase and chip id differ...
- */
#define FLASH_PAGESIZE 256
/* Flash opcodes. */
-#define OPCODE_WREN 6 /* Write enable */
-#define OPCODE_RDSR 5 /* Read status register */
-#define OPCODE_READ 3 /* Read data bytes */
-#define OPCODE_PP 2 /* Page program */
-#define OPCODE_SE 0xd8 /* Sector erase */
-#define OPCODE_RES 0xab /* Read Electronic Signature */
+#define OPCODE_WREN 0x06 /* Write enable */
+#define OPCODE_RDSR 0x05 /* Read status register */
+#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */
+#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
+#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
+#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
#define SR_BP0 4 /* Block protect 0 */
#define SR_BP1 8 /* Block protect 1 */
#define SR_BP2 0x10 /* Block protect 2 */
@@ -65,9 +64,10 @@
struct m25p {
struct spi_device *spi;
- struct semaphore lock;
+ struct mutex lock;
struct mtd_info mtd;
- unsigned partitioned;
+ unsigned partitioned:1;
+ u8 erase_opcode;
u8 command[4];
};
@@ -150,8 +150,9 @@ static int wait_till_ready(struct m25p *flash)
*/
static int erase_sector(struct m25p *flash, u32 offset)
{
- DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id,
- __FUNCTION__, offset);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n",
+ flash->spi->dev.bus_id, __FUNCTION__,
+ flash->mtd.erasesize / 1024, offset);
/* Wait until finished previous write command. */
if (wait_till_ready(flash))
@@ -161,7 +162,7 @@ static int erase_sector(struct m25p *flash, u32 offset)
write_enable(flash);
/* Set up command buffer. */
- flash->command[0] = OPCODE_SE;
+ flash->command[0] = flash->erase_opcode;
flash->command[1] = offset >> 16;
flash->command[2] = offset >> 8;
flash->command[3] = offset;
@@ -201,13 +202,17 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
addr = instr->addr;
len = instr->len;
- down(&flash->lock);
+ mutex_lock(&flash->lock);
+
+ /* REVISIT in some cases we could speed up erasing large regions
+ * by using OPCODE_SE instead of OPCODE_BE_4K
+ */
/* now erase those sectors */
while (len) {
if (erase_sector(flash, addr)) {
instr->state = MTD_ERASE_FAILED;
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return -EIO;
}
@@ -215,7 +220,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
len -= mtd->erasesize;
}
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
@@ -260,16 +265,19 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
if (retlen)
*retlen = 0;
- down(&flash->lock);
+ mutex_lock(&flash->lock);
/* Wait till previous write/erase is done. */
if (wait_till_ready(flash)) {
/* REVISIT status return?? */
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 1;
}
- /* NOTE: OPCODE_FAST_READ (if available) is faster... */
+ /* FIXME switch to OPCODE_FAST_READ. It's required for higher
+ * clocks; and at this writing, every chip this driver handles
+ * supports that opcode.
+ */
/* Set up the write data buffer. */
flash->command[0] = OPCODE_READ;
@@ -281,7 +289,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
*retlen = m.actual_length - sizeof(flash->command);
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 0;
}
@@ -323,7 +331,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
t[1].tx_buf = buf;
spi_message_add_tail(&t[1], &m);
- down(&flash->lock);
+ mutex_lock(&flash->lock);
/* Wait until finished previous write command. */
if (wait_till_ready(flash))
@@ -381,10 +389,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
if (retlen)
*retlen += m.actual_length
- sizeof(flash->command);
- }
- }
+ }
+ }
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 0;
}
@@ -398,24 +406,118 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
struct flash_info {
char *name;
- u8 id;
- u16 jedec_id;
+
+ /* JEDEC id zero means "no ID" (most older chips); otherwise it has
+ * a high byte of zero plus three data bytes: the manufacturer id,
+ * then a two byte device id.
+ */
+ u32 jedec_id;
+
+ /* The size listed here is what works with OPCODE_SE, which isn't
+ * necessarily called a "sector" by the vendor.
+ */
unsigned sector_size;
- unsigned n_sectors;
+ u16 n_sectors;
+
+ u16 flags;
+#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
};
+
+/* NOTE: double check command sets and memory organization when you add
+ * more flash chips. This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
static struct flash_info __devinitdata m25p_data [] = {
- /* REVISIT: fill in JEDEC ids, for parts that have them */
- { "m25p05", 0x05, 0x2010, 32 * 1024, 2 },
- { "m25p10", 0x10, 0x2011, 32 * 1024, 4 },
- { "m25p20", 0x11, 0x2012, 64 * 1024, 4 },
- { "m25p40", 0x12, 0x2013, 64 * 1024, 8 },
- { "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
- { "m25p16", 0x14, 0x2015, 64 * 1024, 32 },
- { "m25p32", 0x15, 0x2016, 64 * 1024, 64 },
- { "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
+
+ /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+ { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, },
+ { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, },
+
+ { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
+
+ { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, },
+ { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
+ { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
+ { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, },
+
+ /* Spansion -- single (large) sector size only, at least
+ * for the chips listed here (without boot sectors).
+ */
+ { "s25sl004a", 0x010212, 64 * 1024, 8, },
+ { "s25sl008a", 0x010213, 64 * 1024, 16, },
+ { "s25sl016a", 0x010214, 64 * 1024, 32, },
+ { "s25sl032a", 0x010215, 64 * 1024, 64, },
+ { "s25sl064a", 0x010216, 64 * 1024, 128, },
+
+ /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+ { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
+ { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
+ { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
+ { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
+
+ /* ST Microelectronics -- newer production may have feature updates */
+ { "m25p05", 0x202010, 32 * 1024, 2, },
+ { "m25p10", 0x202011, 32 * 1024, 4, },
+ { "m25p20", 0x202012, 64 * 1024, 4, },
+ { "m25p40", 0x202013, 64 * 1024, 8, },
+ { "m25p80", 0, 64 * 1024, 16, },
+ { "m25p16", 0x202015, 64 * 1024, 32, },
+ { "m25p32", 0x202016, 64 * 1024, 64, },
+ { "m25p64", 0x202017, 64 * 1024, 128, },
+ { "m25p128", 0x202018, 256 * 1024, 64, },
+
+ { "m45pe80", 0x204014, 64 * 1024, 16, },
+ { "m45pe16", 0x204015, 64 * 1024, 32, },
+
+ { "m25pe80", 0x208014, 64 * 1024, 16, },
+ { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, },
+
+ /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+ { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
+ { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
+ { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
+ { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
+ { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
+ { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
+ { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
};
+static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+{
+ int tmp;
+ u8 code = OPCODE_RDID;
+ u8 id[3];
+ u32 jedec;
+ struct flash_info *info;
+
+ /* JEDEC also defines an optional "extended device information"
+ * string for after vendor-specific data, after the three bytes
+ * we use here. Supporting some chips might require using it.
+ */
+ tmp = spi_write_then_read(spi, &code, 1, id, 3);
+ if (tmp < 0) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",
+ spi->dev.bus_id, tmp);
+ return NULL;
+ }
+ jedec = id[0];
+ jedec = jedec << 8;
+ jedec |= id[1];
+ jedec = jedec << 8;
+ jedec |= id[2];
+
+ for (tmp = 0, info = m25p_data;
+ tmp < ARRAY_SIZE(m25p_data);
+ tmp++, info++) {
+ if (info->jedec_id == jedec)
+ return info;
+ }
+ dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
+ return NULL;
+}
+
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -429,37 +531,51 @@ static int __devinit m25p_probe(struct spi_device *spi)
unsigned i;
/* Platform data helps sort out which chip type we have, as
- * well as how this board partitions it.
+ * well as how this board partitions it. If we don't have
+ * a chip ID, try the JEDEC id commands; they'll work for most
+ * newer chips, even if we don't recognize the particular chip.
*/
data = spi->dev.platform_data;
- if (!data || !data->type) {
- /* FIXME some chips can identify themselves with RES
- * or JEDEC get-id commands. Try them ...
- */
- DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
- spi->dev.bus_id);
- return -ENODEV;
- }
+ if (data && data->type) {
+ for (i = 0, info = m25p_data;
+ i < ARRAY_SIZE(m25p_data);
+ i++, info++) {
+ if (strcmp(data->type, info->name) == 0)
+ break;
+ }
- for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) {
- if (strcmp(data->type, info->name) == 0)
- break;
- }
- if (i == ARRAY_SIZE(m25p_data)) {
- DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
- spi->dev.bus_id, data->type);
+ /* unrecognized chip? */
+ if (i == ARRAY_SIZE(m25p_data)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
+ spi->dev.bus_id, data->type);
+ info = NULL;
+
+ /* recognized; is that chip really what's there? */
+ } else if (info->jedec_id) {
+ struct flash_info *chip = jedec_probe(spi);
+
+ if (!chip || chip != info) {
+ dev_warn(&spi->dev, "found %s, expected %s\n",
+ chip ? chip->name : "UNKNOWN",
+ info->name);
+ info = NULL;
+ }
+ }
+ } else
+ info = jedec_probe(spi);
+
+ if (!info)
return -ENODEV;
- }
flash = kzalloc(sizeof *flash, GFP_KERNEL);
if (!flash)
return -ENOMEM;
flash->spi = spi;
- init_MUTEX(&flash->lock);
+ mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash);
- if (data->name)
+ if (data && data->name)
flash->mtd.name = data->name;
else
flash->mtd.name = spi->dev.bus_id;
@@ -468,17 +584,25 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
- flash->mtd.erasesize = info->sector_size;
flash->mtd.erase = m25p80_erase;
flash->mtd.read = m25p80_read;
flash->mtd.write = m25p80_write;
+ /* prefer "small sector" erase if possible */
+ if (info->flags & SECT_4K) {
+ flash->erase_opcode = OPCODE_BE_4K;
+ flash->mtd.erasesize = 4096;
+ } else {
+ flash->erase_opcode = OPCODE_SE;
+ flash->mtd.erasesize = info->sector_size;
+ }
+
dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
flash->mtd.size / 1024);
DEBUG(MTD_DEBUG_LEVEL2,
- "mtd .name = %s, .size = 0x%.8x (%uM) "
- ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n",
+ "mtd .name = %s, .size = 0x%.8x (%uMiB) "
+ ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
flash->mtd.name,
flash->mtd.size, flash->mtd.size / (1024*1024),
flash->mtd.erasesize, flash->mtd.erasesize / 1024,
@@ -488,7 +612,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
for (i = 0; i < flash->mtd.numeraseregions; i++)
DEBUG(MTD_DEBUG_LEVEL2,
"mtd.eraseregions[%d] = { .offset = 0x%.8x, "
- ".erasesize = 0x%.8x (%uK), "
+ ".erasesize = 0x%.8x (%uKiB), "
".numblocks = %d }\n",
i, flash->mtd.eraseregions[i].offset,
flash->mtd.eraseregions[i].erasesize,
@@ -516,14 +640,14 @@ static int __devinit m25p_probe(struct spi_device *spi)
}
if (nr_parts > 0) {
- for (i = 0; i < data->nr_parts; i++) {
+ for (i = 0; i < nr_parts; i++) {
DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
"{.name = %s, .offset = 0x%.8x, "
- ".size = 0x%.8x (%uK) }\n",
- i, data->parts[i].name,
- data->parts[i].offset,
- data->parts[i].size,
- data->parts[i].size / 1024);
+ ".size = 0x%.8x (%uKiB) }\n",
+ i, parts[i].name,
+ parts[i].offset,
+ parts[i].size,
+ parts[i].size / 1024);
}
flash->partitioned = 1;
return add_mtd_partitions(&flash->mtd, parts, nr_parts);
@@ -560,6 +684,11 @@ static struct spi_driver m25p80_driver = {
},
.probe = m25p_probe,
.remove = __devexit_p(m25p_remove),
+
+ /* REVISIT: many of these chips have deep power-down modes, which
+ * should clearly be entered on suspend() to minimize power use.
+ * And also when they're otherwise idle...
+ */
};
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index a987e917f4e..a5ed6d232c3 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
@@ -89,7 +90,7 @@ struct dataflash {
unsigned short page_offset; /* offset in flash address */
unsigned int page_size; /* of bytes per page */
- struct semaphore lock;
+ struct mutex lock;
struct spi_device *spi;
struct mtd_info mtd;
@@ -167,7 +168,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
x.len = 4;
spi_message_add_tail(&x, &msg);
- down(&priv->lock);
+ mutex_lock(&priv->lock);
while (instr->len > 0) {
unsigned int pageaddr;
int status;
@@ -210,7 +211,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->len -= priv->page_size;
}
}
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
/* Inform MTD subsystem that erase is complete */
instr->state = MTD_ERASE_DONE;
@@ -266,7 +267,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
x[1].len = len;
spi_message_add_tail(&x[1], &msg);
- down(&priv->lock);
+ mutex_lock(&priv->lock);
/* Continuous read, max clock = f(car) which may be less than
* the peak rate available. Some chips support commands with
@@ -279,7 +280,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
/* plus 4 "don't care" bytes */
status = spi_sync(priv->spi, &msg);
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
if (status >= 0) {
*retlen = msg.actual_length - 8;
@@ -336,7 +337,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
else
writelen = len;
- down(&priv->lock);
+ mutex_lock(&priv->lock);
while (remaining > 0) {
DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
pageaddr, offset, writelen);
@@ -441,7 +442,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
else
writelen = remaining;
}
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
return status;
}
@@ -463,7 +464,7 @@ add_dataflash(struct spi_device *spi, char *name,
if (!priv)
return -ENOMEM;
- init_MUTEX(&priv->lock);
+ mutex_init(&priv->lock);
priv->spi = spi;
priv->page_size = pagesize;
priv->page_offset = pageoffset;
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index e8f686f7a35..7060a0895ce 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -30,8 +30,8 @@
*
* Notes:
* Due to what I assume is more buggy SROM, the 64M PMC551 I
- * have available claims that all 4 of it's DRAM banks have 64M
- * of ram configured (making a grand total of 256M onboard).
+ * have available claims that all 4 of its DRAM banks have 64MiB
+ * of ram configured (making a grand total of 256MiB onboard).
* This is slightly annoying since the BAR0 size reflects the
* aperture size, not the dram size, and the V370PDC supplies no
* other method for memory size discovery. This problem is
@@ -70,7 +70,7 @@
* made the memory unusable, added a fix to code to touch up
* the DRAM some.
*
- * Bugs/FIXME's:
+ * Bugs/FIXMEs:
* * MUST fix the init function to not spin on a register
* waiting for it to set .. this does not safely handle busted
* devices that never reset the register correctly which will
@@ -562,10 +562,10 @@ static u32 fixup_pmc551(struct pci_dev *dev)
/*
* Some screen fun
*/
- printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
+ printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at "
"0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
size >> 10 : size >> 20,
- (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
+ (size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size,
((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
(unsigned long long)pci_resource_start(dev, 0));
@@ -649,14 +649,10 @@ MODULE_DESCRIPTION(PMC551_VERSION);
* Stuff these outside the ifdef so as to not bust compiled in driver support
*/
static int msize = 0;
-#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
-static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE;
-#else
static int asize = 0;
-#endif
module_param(msize, int, 0);
-MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]");
+MODULE_PARM_DESC(msize, "memory size in MiB [1 - 1024]");
module_param(asize, int, 0);
MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
@@ -799,8 +795,7 @@ static int __init init_pmc551(void)
mtd->owner = THIS_MODULE;
if (add_mtd_device(mtd)) {
- printk(KERN_NOTICE "pmc551: Failed to register new "
- "device\n");
+ printk(KERN_NOTICE "pmc551: Failed to register new device\n");
pci_iounmap(PCI_Device, priv->start);
kfree(mtd->priv);
kfree(mtd);
@@ -811,13 +806,13 @@ static int __init init_pmc551(void)
pci_dev_get(PCI_Device);
printk(KERN_NOTICE "Registered pmc551 memory device.\n");
- printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+ printk(KERN_NOTICE "Mapped %dMiB of memory from 0x%p to 0x%p\n",
priv->asize >> 20,
priv->start, priv->start + priv->asize);
- printk(KERN_NOTICE "Total memory is %d%c\n",
+ printk(KERN_NOTICE "Total memory is %d%sB\n",
(length < 1024) ? length :
(length < 1048576) ? length >> 10 : length >> 20,
- (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
+ (length < 1024) ? "" : (length < 1048576) ? "Ki" : "Mi");
priv->nextpmc551 = pmc551list;
pmc551list = mtd;
found++;
@@ -850,7 +845,7 @@ static void __exit cleanup_pmc551(void)
pmc551list = priv->nextpmc551;
if (priv->start) {
- printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
+ printk(KERN_DEBUG "pmc551: unmapping %dMiB starting at "
"0x%p\n", priv->asize >> 20, priv->start);
pci_iounmap(priv->dev, priv->start);
}
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index ecac0e438f4..b8917beeb65 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -580,14 +580,13 @@ int INFTL_mount(struct INFTLrecord *s)
logical_block = block = BLOCK_NIL;
/* Temporary buffer to store ANAC numbers. */
- ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
+ ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
if (!ANACtable) {
printk(KERN_WARNING "INFTL: allocation of ANACtable "
"failed (%zd bytes)\n",
s->nb_blocks * sizeof(u8));
return -ENOMEM;
}
- memset(ANACtable, 0, s->nb_blocks);
/*
* First pass is to explore each physical unit, and construct the
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 6cd132c7518..2a2a125b0c7 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -163,20 +163,12 @@ config MTD_SBC_GXX
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
-config MTD_LUBBOCK
- tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
- depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
- help
- This provides a driver for the on-board flash of the Intel
- 'Lubbock' XScale evaluation board.
-
-config MTD_MAINSTONE
- tristate "CFI Flash device mapped on Intel Mainstone XScale eval board"
- depends on MACH_MAINSTONE && MTD_CFI_INTELEXT
+config MTD_PXA2XX
+ tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards"
+ depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT
select MTD_PARTITIONS
help
- This provides a driver for the on-board flash of the Intel
- 'Mainstone PXA27x evaluation board.
+ This provides a driver for the NOR flash attached to a PXA2xx chip.
config MTD_OCTAGON
tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
@@ -354,7 +346,7 @@ config MTD_CFI_FLAGADM
config MTD_WALNUT
tristate "Flash device mapped on IBM 405GP Walnut"
- depends on MTD_JEDECPROBE && WALNUT
+ depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 405GP
Walnut board. If you have one of these boards and would like to
@@ -370,7 +362,7 @@ config MTD_EBONY
config MTD_OCOTEA
tristate "Flash devices mapped on IBM 440GX Ocotea"
- depends on MTD_CFI && OCOTEA
+ depends on MTD_CFI && OCOTEA && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 440GX
Ocotea board. If you have one of these boards and would like to
@@ -384,22 +376,6 @@ config MTD_REDWOOD
Redwood board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
-config MTD_TQM834x
- tristate "Flash device mapped on TQ Components TQM834x Boards"
- depends on MTD_CFI && TQM834x
- help
- This enables access routines for the flash chips on the
- TQ Components TQM834x boards. If you have one of these boards
- and would like to use the flash chips on it, say 'Y'.
-
-config MTD_OCELOT
- tristate "Momenco Ocelot boot flash device"
- depends on MOMENCO_OCELOT
- help
- This enables access routines for the boot flash device and for the
- NVRAM on the Momenco Ocelot board. If you have one of these boards
- and would like access to either of these, say 'Y'.
-
config MTD_SOLUTIONENGINE
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS
@@ -605,6 +581,13 @@ config MTD_SHARP_SL
help
This enables access to the flash chip on the Sharp SL Series of PDAs.
+config MTD_INTEL_VR_NOR
+ tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
+ depends on PCI
+ help
+ Map driver for a NOR flash bank located on the Expansion Bus of the
+ Intel Vermilion Range chipset.
+
config MTD_PLATRAM
tristate "Map driver for platform device RAM (mtd-ram)"
select MTD_RAM
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 970b189271a..316382a1401 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -20,8 +20,7 @@ obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
-obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
-obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o
+obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
@@ -43,7 +42,6 @@ obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
obj-$(CONFIG_MTD_VMAX) += vmax301.o
obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
-obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
@@ -70,4 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o
-obj-$(CONFIG_MTD_TQM834x) += tqm834x.o
+obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index 84fbe0e8c47..82811bcb043 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -75,13 +75,6 @@
#define BOARD_FLASH_WIDTH 2 /* 16-bits */
#endif
-#ifdef CONFIG_MIPS_HYDROGEN3
-#define BOARD_MAP_NAME "Hydrogen3 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#define USE_LOCAL_ACCESSORS /* why? */
-#endif
-
#ifdef CONFIG_MIPS_BOSPORUS
#define BOARD_MAP_NAME "Bosporus Flash"
#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
@@ -130,13 +123,6 @@ int __init alchemy_mtd_init(void)
window_addr = 0x20000000 - BOARD_FLASH_SIZE;
window_size = BOARD_FLASH_SIZE;
-#ifdef CONFIG_MIPS_MIRAGE_WHY
- /* Boot ROM flash bank only; no user bank */
- window_addr = 0x1C000000;
- window_size = 0x04000000;
- /* USERFS from 0x1C00 0000 to 0x1FC00000 */
- alchemy_partitions[0].size = 0x03C00000;
-#endif
/*
* Static partition definition selection
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c
new file mode 100644
index 00000000000..1e7814ae212
--- /dev/null
+++ b/drivers/mtd/maps/intel_vr_nor.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/mtd/maps/intel_vr_nor.c
+ *
+ * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel
+ * Vermilion Range chipset.
+ *
+ * The Vermilion Range Expansion Bus supports four chip selects, each of which
+ * has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device
+ * is a 256MiB memory region containing the address spaces for all four of the
+ * chip selects, with start addresses hardcoded on 64MiB boundaries.
+ *
+ * This map driver only supports NOR flash on chip select 0. The buswidth
+ * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing
+ * and Control Register for Chip Select 0 (EXP_TIMING_CS0). This driver does
+ * not modify the value in the EXP_TIMING_CS0 register except to enable writing
+ * and disable boot acceleration. The timing parameters in the register are
+ * assumed to have been properly initialized by the BIOS. The reset default
+ * timing parameters are maximally conservative (slow), so access to the flash
+ * will be slower than it should be if the BIOS has not initialized the timing
+ * parameters.
+ *
+ * Author: Andy Lowe <alowe@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+
+#define DRV_NAME "vr_nor"
+
+struct vr_nor_mtd {
+ void __iomem *csr_base;
+ struct map_info map;
+ struct mtd_info *info;
+ int nr_parts;
+ struct pci_dev *dev;
+};
+
+/* Expansion Bus Configuration and Status Registers are in BAR 0 */
+#define EXP_CSR_MBAR 0
+/* Expansion Bus Memory Window is BAR 1 */
+#define EXP_WIN_MBAR 1
+/* Maximum address space for Chip Select 0 is 64MiB */
+#define CS0_SIZE 0x04000000
+/* Chip Select 0 is at offset 0 in the Memory Window */
+#define CS0_START 0x0
+/* Chip Select 0 Timing Register is at offset 0 in CSR */
+#define EXP_TIMING_CS0 0x00
+#define TIMING_CS_EN (1 << 31) /* Chip Select Enable */
+#define TIMING_BOOT_ACCEL_DIS (1 << 8) /* Boot Acceleration Disable */
+#define TIMING_WR_EN (1 << 1) /* Write Enable */
+#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */
+#define TIMING_MASK 0x3FFF0000
+
+static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
+{
+ if (p->nr_parts > 0) {
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ del_mtd_partitions(p->info);
+#endif
+ } else
+ del_mtd_device(p->info);
+}
+
+static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
+{
+ int err = 0;
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ struct mtd_partition *parts;
+ static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+ /* register the flash bank */
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ /* partition the flash bank */
+ p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0);
+ if (p->nr_parts > 0)
+ err = add_mtd_partitions(p->info, parts, p->nr_parts);
+#endif
+ if (p->nr_parts <= 0)
+ err = add_mtd_device(p->info);
+
+ return err;
+}
+
+static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
+{
+ map_destroy(p->info);
+}
+
+static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
+{
+ static const char *probe_types[] =
+ { "cfi_probe", "jedec_probe", NULL };
+ const char **type;
+
+ for (type = probe_types; !p->info && *type; type++)
+ p->info = do_map_probe(*type, &p->map);
+ if (!p->info)
+ return -ENODEV;
+
+ p->info->owner = THIS_MODULE;
+
+ return 0;
+}
+
+static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
+{
+ unsigned int exp_timing_cs0;
+
+ /* write-protect the flash bank */
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ exp_timing_cs0 &= ~TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ /* unmap the flash window */
+ iounmap(p->map.virt);
+
+ /* unmap the csr window */
+ iounmap(p->csr_base);
+}
+
+/*
+ * Initialize the map_info structure and map the flash.
+ * Returns 0 on success, nonzero otherwise.
+ */
+static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
+{
+ unsigned long csr_phys, csr_len;
+ unsigned long win_phys, win_len;
+ unsigned int exp_timing_cs0;
+ int err;
+
+ csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR);
+ csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR);
+ win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR);
+ win_len = pci_resource_len(p->dev, EXP_WIN_MBAR);
+
+ if (!csr_phys || !csr_len || !win_phys || !win_len)
+ return -ENODEV;
+
+ if (win_len < (CS0_START + CS0_SIZE))
+ return -ENXIO;
+
+ p->csr_base = ioremap_nocache(csr_phys, csr_len);
+ if (!p->csr_base)
+ return -ENOMEM;
+
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ if (!(exp_timing_cs0 & TIMING_CS_EN)) {
+ dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+ "is disabled.\n");
+ err = -ENODEV;
+ goto release;
+ }
+ if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) {
+ dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+ "is configured for maximally slow access times.\n");
+ }
+ p->map.name = DRV_NAME;
+ p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2;
+ p->map.phys = win_phys + CS0_START;
+ p->map.size = CS0_SIZE;
+ p->map.virt = ioremap_nocache(p->map.phys, p->map.size);
+ if (!p->map.virt) {
+ err = -ENOMEM;
+ goto release;
+ }
+ simple_map_init(&p->map);
+
+ /* Enable writes to flash bank */
+ exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ return 0;
+
+ release:
+ iounmap(p->csr_base);
+ return err;
+}
+
+static struct pci_device_id vr_nor_pci_ids[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)},
+ {0,}
+};
+
+static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
+{
+ struct vr_nor_mtd *p = pci_get_drvdata(dev);
+
+ pci_set_drvdata(dev, NULL);
+ vr_nor_destroy_partitions(p);
+ vr_nor_destroy_mtd_setup(p);
+ vr_nor_destroy_maps(p);
+ kfree(p);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+}
+
+static int __devinit
+vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct vr_nor_mtd *p = NULL;
+ unsigned int exp_timing_cs0;
+ int err;
+
+ err = pci_enable_device(dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(dev, DRV_NAME);
+ if (err)
+ goto disable_dev;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!p)
+ goto release;
+
+ p->dev = dev;
+
+ err = vr_nor_init_maps(p);
+ if (err)
+ goto release;
+
+ err = vr_nor_mtd_setup(p);
+ if (err)
+ goto destroy_maps;
+
+ err = vr_nor_init_partitions(p);
+ if (err)
+ goto destroy_mtd_setup;
+
+ pci_set_drvdata(dev, p);
+
+ return 0;
+
+ destroy_mtd_setup:
+ map_destroy(p->info);
+
+ destroy_maps:
+ /* write-protect the flash bank */
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ exp_timing_cs0 &= ~TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ /* unmap the flash window */
+ iounmap(p->map.virt);
+
+ /* unmap the csr window */
+ iounmap(p->csr_base);
+
+ release:
+ kfree(p);
+ pci_release_regions(dev);
+
+ disable_dev:
+ pci_disable_device(dev);
+
+ out:
+ return err;
+}
+
+static struct pci_driver vr_nor_pci_driver = {
+ .name = DRV_NAME,
+ .probe = vr_nor_pci_probe,
+ .remove = __devexit_p(vr_nor_pci_remove),
+ .id_table = vr_nor_pci_ids,
+};
+
+static int __init vr_nor_mtd_init(void)
+{
+ return pci_register_driver(&vr_nor_pci_driver);
+}
+
+static void __exit vr_nor_mtd_exit(void)
+{
+ pci_unregister_driver(&vr_nor_pci_driver);
+}
+
+module_init(vr_nor_mtd_init);
+module_exit(vr_nor_mtd_exit);
+
+MODULE_AUTHOR("Andy Lowe");
+MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids);
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
deleted file mode 100644
index e8560683b97..00000000000
--- a/drivers/mtd/maps/lubbock-flash.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
- *
- * Map driver for the Lubbock developer platform.
- *
- * Author: Nicolas Pitre
- * Copyright: (C) 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/lubbock.h>
-#include <asm/cacheflush.h>
-
-#define ROM_ADDR 0x00000000
-#define FLASH_ADDR 0x04000000
-
-#define WINDOW_SIZE 64*1024*1024
-
-static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
-{
- flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info lubbock_maps[2] = { {
- .size = WINDOW_SIZE,
- .phys = 0x00000000,
- .inval_cache = lubbock_map_inval_cache,
-}, {
- .size = WINDOW_SIZE,
- .phys = 0x04000000,
- .inval_cache = lubbock_map_inval_cache,
-} };
-
-static struct mtd_partition lubbock_partitions[] = {
- {
- .name = "Bootloader",
- .size = 0x00040000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
- .name = "Kernel",
- .size = 0x00100000,
- .offset = 0x00040000,
- },{
- .name = "Filesystem",
- .size = MTDPART_SIZ_FULL,
- .offset = 0x00140000
- }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_lubbock(void)
-{
- int flashboot = (LUB_CONF_SWITCHES & 1);
- int ret = 0, i;
-
- lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
- (BOOT_DEF & 1) ? 2 : 4;
-
- /* Compensate for the nROMBT switch which swaps the flash banks */
- printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
- flashboot?"Flash":"ROM", flashboot);
-
- lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
- lubbock_maps[flashboot].name = "Lubbock Boot ROM";
-
- for (i = 0; i < 2; i++) {
- lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
- if (!lubbock_maps[i].virt) {
- printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
- if (!ret)
- ret = -ENOMEM;
- continue;
- }
- lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE);
- if (!lubbock_maps[i].cached)
- printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
- simple_map_init(&lubbock_maps[i]);
-
- printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
- lubbock_maps[i].name, lubbock_maps[i].phys,
- lubbock_maps[i].bankwidth * 8);
-
- mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-
- if (!mymtds[i]) {
- iounmap((void *)lubbock_maps[i].virt);
- if (lubbock_maps[i].cached)
- iounmap(lubbock_maps[i].cached);
- if (!ret)
- ret = -EIO;
- continue;
- }
- mymtds[i]->owner = THIS_MODULE;
-
- ret = parse_mtd_partitions(mymtds[i], probes,
- &parsed_parts[i], 0);
-
- if (ret > 0)
- nr_parsed_parts[i] = ret;
- }
-
- if (!mymtds[0] && !mymtds[1])
- return ret;
-
- for (i = 0; i < 2; i++) {
- if (!mymtds[i]) {
- printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
- } else if (nr_parsed_parts[i]) {
- add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
- } else if (!i) {
- printk("Using static partitions on %s\n", lubbock_maps[i].name);
- add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions));
- } else {
- printk("Registering %s as whole device\n", lubbock_maps[i].name);
- add_mtd_device(mymtds[i]);
- }
- }
- return 0;
-}
-
-static void __exit cleanup_lubbock(void)
-{
- int i;
- for (i = 0; i < 2; i++) {
- if (!mymtds[i])
- continue;
-
- if (nr_parsed_parts[i] || !i)
- del_mtd_partitions(mymtds[i]);
- else
- del_mtd_device(mymtds[i]);
-
- map_destroy(mymtds[i]);
- iounmap((void *)lubbock_maps[i].virt);
- if (lubbock_maps[i].cached)
- iounmap(lubbock_maps[i].cached);
-
- kfree(parsed_parts[i]);
- }
-}
-
-module_init(init_lubbock);
-module_exit(cleanup_lubbock);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
deleted file mode 100644
index d76487d82dc..00000000000
--- a/drivers/mtd/maps/mainstone-flash.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * $Id: $
- *
- * Map driver for the Mainstone developer platform.
- *
- * Author: Nicolas Pitre
- * Copyright: (C) 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/mainstone.h>
-#include <asm/cacheflush.h>
-
-
-#define ROM_ADDR 0x00000000
-#define FLASH_ADDR 0x04000000
-
-#define WINDOW_SIZE 0x04000000
-
-static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
- ssize_t len)
-{
- flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info mainstone_maps[2] = { {
- .size = WINDOW_SIZE,
- .phys = PXA_CS0_PHYS,
- .inval_cache = mainstone_map_inval_cache,
-}, {
- .size = WINDOW_SIZE,
- .phys = PXA_CS1_PHYS,
- .inval_cache = mainstone_map_inval_cache,
-} };
-
-static struct mtd_partition mainstone_partitions[] = {
- {
- .name = "Bootloader",
- .size = 0x00040000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
- .name = "Kernel",
- .size = 0x00400000,
- .offset = 0x00040000,
- },{
- .name = "Filesystem",
- .size = MTDPART_SIZ_FULL,
- .offset = 0x00440000
- }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_mainstone(void)
-{
- int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
- int ret = 0, i;
-
- mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4;
- mainstone_maps[1].bankwidth = 4;
-
- /* Compensate for SW7 which swaps the flash banks */
- mainstone_maps[SW7].name = "processor flash";
- mainstone_maps[SW7 ^ 1].name = "main board flash";
-
- printk(KERN_NOTICE "Mainstone configured to boot from %s\n",
- mainstone_maps[0].name);
-
- for (i = 0; i < 2; i++) {
- mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
- WINDOW_SIZE);
- if (!mainstone_maps[i].virt) {
- printk(KERN_WARNING "Failed to ioremap %s\n",
- mainstone_maps[i].name);
- if (!ret)
- ret = -ENOMEM;
- continue;
- }
- mainstone_maps[i].cached =
- ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
- if (!mainstone_maps[i].cached)
- printk(KERN_WARNING "Failed to ioremap cached %s\n",
- mainstone_maps[i].name);
- simple_map_init(&mainstone_maps[i]);
-
- printk(KERN_NOTICE
- "Probing %s at physical address 0x%08lx"
- " (%d-bit bankwidth)\n",
- mainstone_maps[i].name, mainstone_maps[i].phys,
- mainstone_maps[i].bankwidth * 8);
-
- mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
-
- if (!mymtds[i]) {
- iounmap((void *)mainstone_maps[i].virt);
- if (mainstone_maps[i].cached)
- iounmap(mainstone_maps[i].cached);
- if (!ret)
- ret = -EIO;
- continue;
- }
- mymtds[i]->owner = THIS_MODULE;
-
- ret = parse_mtd_partitions(mymtds[i], probes,
- &parsed_parts[i], 0);
-
- if (ret > 0)
- nr_parsed_parts[i] = ret;
- }
-
- if (!mymtds[0] && !mymtds[1])
- return ret;
-
- for (i = 0; i < 2; i++) {
- if (!mymtds[i]) {
- printk(KERN_WARNING "%s is absent. Skipping\n",
- mainstone_maps[i].name);
- } else if (nr_parsed_parts[i]) {
- add_mtd_partitions(mymtds[i], parsed_parts[i],
- nr_parsed_parts[i]);
- } else if (!i) {
- printk("Using static partitions on %s\n",
- mainstone_maps[i].name);
- add_mtd_partitions(mymtds[i], mainstone_partitions,
- ARRAY_SIZE(mainstone_partitions));
- } else {
- printk("Registering %s as whole device\n",
- mainstone_maps[i].name);
- add_mtd_device(mymtds[i]);
- }
- }
- return 0;
-}
-
-static void __exit cleanup_mainstone(void)
-{
- int i;
- for (i = 0; i < 2; i++) {
- if (!mymtds[i])
- continue;
-
- if (nr_parsed_parts[i] || !i)
- del_mtd_partitions(mymtds[i]);
- else
- del_mtd_device(mymtds[i]);
-
- map_destroy(mymtds[i]);
- iounmap((void *)mainstone_maps[i].virt);
- if (mainstone_maps[i].cached)
- iounmap(mainstone_maps[i].cached);
- kfree(parsed_parts[i]);
- }
-}
-
-module_init(init_mainstone);
-module_exit(cleanup_mainstone);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Mainstone");
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 7b96cd02f82..0c9b305a72e 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -158,68 +158,11 @@ static struct notifier_block nettel_notifier_block = {
nettel_reboot_notifier, NULL, 0
};
-/*
- * Erase the configuration file system.
- * Used to support the software reset button.
- */
-static void nettel_erasecallback(struct erase_info *done)
-{
- wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
- wake_up(wait_q);
-}
-
-static struct erase_info nettel_erase;
-
-int nettel_eraseconfig(void)
-{
- struct mtd_info *mtd;
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t wait_q;
- int ret;
-
- init_waitqueue_head(&wait_q);
- mtd = get_mtd_device(NULL, 2);
- if (!IS_ERR(mtd)) {
- nettel_erase.mtd = mtd;
- nettel_erase.callback = nettel_erasecallback;
- nettel_erase.callback = NULL;
- nettel_erase.addr = 0;
- nettel_erase.len = mtd->size;
- nettel_erase.priv = (u_long) &wait_q;
- nettel_erase.priv = 0;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&wait_q, &wait);
-
- ret = mtd->erase(mtd, &nettel_erase);
- if (ret) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&wait_q, &wait);
- put_mtd_device(mtd);
- return(ret);
- }
-
- schedule(); /* Wait for erase to finish. */
- remove_wait_queue(&wait_q, &wait);
-
- put_mtd_device(mtd);
- }
-
- return(0);
-}
-
-#else
-
-int nettel_eraseconfig(void)
-{
- return(0);
-}
-
#endif
/****************************************************************************/
-int __init nettel_init(void)
+static int __init nettel_init(void)
{
volatile unsigned long *amdpar;
unsigned long amdaddr, maxsize;
@@ -421,10 +364,6 @@ int __init nettel_init(void)
intel_mtd->owner = THIS_MODULE;
-#ifndef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
-#endif
-
num_intel_partitions = sizeof(nettel_intel_partitions) /
sizeof(nettel_intel_partitions[0]);
@@ -477,7 +416,7 @@ out_unmap2:
/****************************************************************************/
-void __exit nettel_cleanup(void)
+static void __exit nettel_cleanup(void)
{
#ifdef CONFIG_MTD_CFI_INTELEXT
unregister_reboot_notifier(&nettel_notifier_block);
diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c
deleted file mode 100644
index 6977963d789..00000000000
--- a/drivers/mtd/maps/ocelot.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $
- *
- * Flash on Momenco Ocelot
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define OCELOT_PLD 0x2c000000
-#define FLASH_WINDOW_ADDR 0x2fc00000
-#define FLASH_WINDOW_SIZE 0x00080000
-#define FLASH_BUSWIDTH 1
-#define NVRAM_WINDOW_ADDR 0x2c800000
-#define NVRAM_WINDOW_SIZE 0x00007FF0
-#define NVRAM_BUSWIDTH 1
-
-static unsigned int cacheflush = 0;
-
-static struct mtd_info *flash_mtd;
-static struct mtd_info *nvram_mtd;
-
-static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
- struct map_info *map = mtd->priv;
- size_t done = 0;
-
- /* If we use memcpy, it does word-wide writes. Even though we told the
- GT64120A that it's an 8-bit wide region, word-wide writes don't work.
- We end up just writing the first byte of the four to all four bytes.
- So we have this loop instead */
- *retlen = len;
- while(len) {
- __raw_writeb(*(unsigned char *) from, map->virt + to);
- from++;
- to++;
- len--;
- }
-}
-
-static struct mtd_partition *parsed_parts;
-
-struct map_info ocelot_flash_map = {
- .name = "Ocelot boot flash",
- .size = FLASH_WINDOW_SIZE,
- .bankwidth = FLASH_BUSWIDTH,
- .phys = FLASH_WINDOW_ADDR,
-};
-
-struct map_info ocelot_nvram_map = {
- .name = "Ocelot NVRAM",
- .size = NVRAM_WINDOW_SIZE,
- .bankwidth = NVRAM_BUSWIDTH,
- .phys = NVRAM_WINDOW_ADDR,
-};
-
-static const char *probes[] = { "RedBoot", NULL };
-
-static int __init init_ocelot_maps(void)
-{
- void *pld;
- int nr_parts;
- unsigned char brd_status;
-
- printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n",
- FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
-
- /* First check whether the flash jumper is present */
- pld = ioremap(OCELOT_PLD, 0x10);
- if (!pld) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
- return -EIO;
- }
- brd_status = readb(pld+4);
- iounmap(pld);
-
- /* Now ioremap the NVRAM space */
- ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
- if (!ocelot_nvram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
- return -EIO;
- }
-
- simple_map_init(&ocelot_nvram_map);
-
- /* And do the RAM probe on it to get an MTD device */
- nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
- if (!nvram_mtd) {
- printk("NVRAM probe failed\n");
- goto fail_1;
- }
- nvram_mtd->owner = THIS_MODULE;
- nvram_mtd->erasesize = 16;
- /* Override the write() method */
- nvram_mtd->write = ocelot_ram_write;
-
- /* Now map the flash space */
- ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
- if (!ocelot_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
- goto fail_2;
- }
- /* Now the cached version */
- ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-
- simple_map_init(&ocelot_flash_map);
-
- /* Only probe for flash if the write jumper is present */
- if (brd_status & 0x40) {
- flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
- } else {
- printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
- }
- /* If that failed or the jumper's absent, pretend it's ROM */
- if (!flash_mtd) {
- flash_mtd = do_map_probe("map_rom", &ocelot_flash_map);
- /* If we're treating it as ROM, set the erase size */
- if (flash_mtd)
- flash_mtd->erasesize = 0x10000;
- }
- if (!flash_mtd)
- goto fail3;
-
- add_mtd_device(nvram_mtd);
-
- flash_mtd->owner = THIS_MODULE;
- nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-
- if (nr_parts > 0)
- add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
- else
- add_mtd_device(flash_mtd);
-
- return 0;
-
- fail3:
- iounmap((void *)ocelot_flash_map.virt);
- if (ocelot_flash_map.cached)
- iounmap((void *)ocelot_flash_map.cached);
- fail_2:
- map_destroy(nvram_mtd);
- fail_1:
- iounmap((void *)ocelot_nvram_map.virt);
-
- return -ENXIO;
-}
-
-static void __exit cleanup_ocelot_maps(void)
-{
- del_mtd_device(nvram_mtd);
- map_destroy(nvram_mtd);
- iounmap((void *)ocelot_nvram_map.virt);
-
- if (parsed_parts)
- del_mtd_partitions(flash_mtd);
- else
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
- iounmap((void *)ocelot_flash_map.virt);
- if (ocelot_flash_map.cached)
- iounmap((void *)ocelot_flash_map.cached);
-}
-
-module_init(init_ocelot_maps);
-module_exit(cleanup_ocelot_maps);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
-MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board");
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index cf75a566442..aeed9ea7971 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -232,7 +232,6 @@ static int __devinit of_flash_probe(struct of_device *dev,
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
goto err_out;
- memset(info, 0, sizeof(*info));
dev_set_drvdata(&dev->dev, info);
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index 7e0377ec1c4..02bde8c982e 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -73,13 +73,16 @@ int __init init_msp_flash(void)
return -ENXIO;
printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
- msp_flash = (struct mtd_info **)kmalloc(
- fcnt * sizeof(struct map_info *), GFP_KERNEL);
- msp_parts = (struct mtd_partition **)kmalloc(
- fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
- msp_maps = (struct map_info *)kmalloc(
- fcnt * sizeof(struct mtd_info), GFP_KERNEL);
- memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
+
+ msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+ msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+ msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+ if (!msp_flash || !msp_parts || !msp_maps) {
+ kfree(msp_maps);
+ kfree(msp_parts);
+ kfree(msp_flash);
+ return -ENOMEM;
+ }
/* loop over the flash devices, initializing each */
for (i = 0; i < fcnt; i++) {
@@ -95,9 +98,8 @@ int __init init_msp_flash(void)
continue;
}
- msp_parts[i] = (struct mtd_partition *)kmalloc(
- pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
- memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
+ msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition),
+ GFP_KERNEL);
/* now initialize the devices proper */
flash_name[5] = '0' + i;
diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c
index 18049bceba8..30de5c0c09a 100644
--- a/drivers/mtd/maps/pmcmsp-ramroot.c
+++ b/drivers/mtd/maps/pmcmsp-ramroot.c
@@ -79,7 +79,6 @@ static int __init init_rrmap(void)
rr_mtd->owner = THIS_MODULE;
add_mtd_device(rr_mtd);
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
return 0;
}
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c
deleted file mode 100644
index fb78d87cc13..00000000000
--- a/drivers/mtd/maps/pq2fads.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * drivers/mtd/maps/pq2fads.c
- *
- * Mapping for the flash SIMM on 8272ADS and PQ2FADS board
- *
- * Author: Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-
-/*
- NOTE: bank width and interleave relative to the installed flash
- should have been chosen within MTD_CFI_GEOMETRY options.
- */
-#define PQ2FADS_BANK_WIDTH 4
-
-static struct mtd_partition pq2fads_partitions[] = {
- {
-#ifdef CONFIG_ADS8272
- .name = "HRCW",
- .size = 0x40000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "User FS",
- .size = 0x5c0000,
- .offset = 0x40000,
-#else
- .name = "User FS",
- .size = 0x600000,
- .offset = 0,
-#endif
- }, {
- .name = "uImage",
- .size = 0x100000,
- .offset = 0x600000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "bootloader",
- .size = 0x40000,
- .offset = 0x700000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "bootloader env",
- .size = 0x40000,
- .offset = 0x740000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }
-};
-
-
-/* pointer to MPC885ADS board info data */
-extern unsigned char __res[];
-
-static int __init init_pq2fads_mtd(void)
-{
- bd_t *bd = (bd_t *)__res;
- physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL);
-
- physmap_set_partitions(pq2fads_partitions,
- sizeof (pq2fads_partitions) /
- sizeof (pq2fads_partitions[0]));
- return 0;
-}
-
-static void __exit cleanup_pq2fads_mtd(void)
-{
-}
-
-module_init(init_pq2fads_mtd);
-module_exit(cleanup_pq2fads_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards");
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
new file mode 100644
index 00000000000..82113295c26
--- /dev/null
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -0,0 +1,200 @@
+/*
+ * Map driver for Intel XScale PXA2xx platforms.
+ *
+ * Author: Nicolas Pitre
+ * Copyright: (C) 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/cacheflush.h>
+
+#include <asm/mach/flash.h>
+
+static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
+ ssize_t len)
+{
+ flush_ioremap_region(map->phys, map->cached, from, len);
+}
+
+struct pxa2xx_flash_info {
+ struct mtd_partition *parts;
+ int nr_parts;
+ struct mtd_info *mtd;
+ struct map_info map;
+};
+
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+
+static int __init pxa2xx_flash_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct flash_platform_data *flash = pdev->dev.platform_data;
+ struct pxa2xx_flash_info *info;
+ struct mtd_partition *parts;
+ struct resource *res;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ info = kmalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct pxa2xx_flash_info));
+ info->map.name = (char *) flash->name;
+ info->map.bankwidth = flash->width;
+ info->map.phys = res->start;
+ info->map.size = res->end - res->start + 1;
+ info->parts = flash->parts;
+ info->nr_parts = flash->nr_parts;
+
+ info->map.virt = ioremap(info->map.phys, info->map.size);
+ if (!info->map.virt) {
+ printk(KERN_WARNING "Failed to ioremap %s\n",
+ info->map.name);
+ return -ENOMEM;
+ }
+ info->map.cached =
+ ioremap_cached(info->map.phys, info->map.size);
+ if (!info->map.cached)
+ printk(KERN_WARNING "Failed to ioremap cached %s\n",
+ info->map.name);
+ info->map.inval_cache = pxa2xx_map_inval_cache;
+ simple_map_init(&info->map);
+
+ printk(KERN_NOTICE
+ "Probing %s at physical address 0x%08lx"
+ " (%d-bit bankwidth)\n",
+ info->map.name, (unsigned long)info->map.phys,
+ info->map.bankwidth * 8);
+
+ info->mtd = do_map_probe(flash->map_name, &info->map);
+
+ if (!info->mtd) {
+ iounmap((void *)info->map.virt);
+ if (info->map.cached)
+ iounmap(info->map.cached);
+ return -EIO;
+ }
+ info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ ret = parse_mtd_partitions(info->mtd, probes, &parts, 0);
+
+ if (ret > 0) {
+ info->nr_parts = ret;
+ info->parts = parts;
+ }
+#endif
+
+ if (info->nr_parts) {
+ add_mtd_partitions(info->mtd, info->parts,
+ info->nr_parts);
+ } else {
+ printk("Registering %s as whole device\n",
+ info->map.name);
+ add_mtd_device(info->mtd);
+ }
+
+ dev_set_drvdata(dev, info);
+ return 0;
+}
+
+static int __exit pxa2xx_flash_remove(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->nr_parts)
+ del_mtd_partitions(info->mtd);
+ else
+#endif
+ del_mtd_device(info->mtd);
+
+ map_destroy(info->mtd);
+ iounmap(info->map.virt);
+ if (info->map.cached)
+ iounmap(info->map.cached);
+ kfree(info->parts);
+ kfree(info);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (info->mtd && info->mtd->suspend)
+ ret = info->mtd->suspend(info->mtd);
+ return ret;
+}
+
+static int pxa2xx_flash_resume(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ if (info->mtd && info->mtd->resume)
+ info->mtd->resume(info->mtd);
+ return 0;
+}
+static void pxa2xx_flash_shutdown(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ if (info && info->mtd->suspend(info->mtd) == 0)
+ info->mtd->resume(info->mtd);
+}
+#else
+#define pxa2xx_flash_suspend NULL
+#define pxa2xx_flash_resume NULL
+#define pxa2xx_flash_shutdown NULL
+#endif
+
+static struct device_driver pxa2xx_flash_driver = {
+ .name = "pxa2xx-flash",
+ .bus = &platform_bus_type,
+ .probe = pxa2xx_flash_probe,
+ .remove = __exit_p(pxa2xx_flash_remove),
+ .suspend = pxa2xx_flash_suspend,
+ .resume = pxa2xx_flash_resume,
+ .shutdown = pxa2xx_flash_shutdown,
+};
+
+static int __init init_pxa2xx_flash(void)
+{
+ return driver_register(&pxa2xx_flash_driver);
+}
+
+static void __exit cleanup_pxa2xx_flash(void)
+{
+ driver_unregister(&pxa2xx_flash_driver);
+}
+
+module_init(init_pxa2xx_flash);
+module_exit(cleanup_pxa2xx_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx");
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
deleted file mode 100644
index 9adc970e55e..00000000000
--- a/drivers/mtd/maps/tqm834x.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * drivers/mtd/maps/tqm834x.c
- *
- * MTD mapping driver for TQM834x boards
- *
- * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define FLASH_BANK_MAX 2
-
-extern unsigned char __res[];
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
- int nums;
- unsigned char *type;
- struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
-static struct map_info* map_banks[FLASH_BANK_MAX];
-static struct mtd_part_def part_banks[FLASH_BANK_MAX];
-
-static unsigned long num_banks;
-static unsigned long start_scan_addr;
-
-#ifdef CONFIG_MTD_PARTITIONS
-/*
- * The following defines the partition layout of TQM834x boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * Assume minimal initial size of 4 MiB per bank, will be updated
- * later in init_tqm834x_mtd() routine.
- */
-
-/* Partition definition for the first flash bank which is always present. */
-static struct mtd_partition tqm834x_partitions_bank1[] = {
- {
- .name = "u-boot", /* u-boot firmware */
- .offset = 0x00000000,
- .size = 0x00040000, /* 256 KiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "env", /* u-boot environment */
- .offset = 0x00040000,
- .size = 0x00020000, /* 128 KiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "kernel", /* linux kernel image */
- .offset = 0x00060000,
- .size = 0x00100000, /* 1 MiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "initrd", /* ramdisk image */
- .offset = 0x00160000,
- .size = 0x00200000, /* 2 MiB */
- },
- {
- .name = "user", /* user data */
- .offset = 0x00360000,
- .size = 0x000a0000, /* remaining space */
- /* NOTE: this parttion size is re-calcated in */
- /* init_tqm834x_mtd() to cover actual remaining space. */
- },
-};
-
-/* Partition definition for the second flash bank which may be present on some
- * TQM834x boards.
- */
-static struct mtd_partition tqm834x_partitions_bank2[] = {
- {
- .name = "jffs2", /* jffs2 filesystem */
- .offset = 0x00000000,
- .size = 0x00400000, /* whole device */
- /* NOTE: this parttion size is re-calcated in */
- /* init_tqm834x_mtd() to cover actual device size. */
- },
-};
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-static int __init init_tqm834x_mtd(void)
-{
- int idx = 0, ret = 0;
- unsigned long flash_addr, flash_size, mtd_size = 0;
-
- /* pointer to TQM834x board info data */
- bd_t *bd = (bd_t *)__res;
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- int n;
- char mtdid[4];
- const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
-
- flash_addr = bd->bi_flashstart;
- flash_size = bd->bi_flashsize;
-
- /* request maximum flash size address space */
- start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
- if (!start_scan_addr) {
- printk("%s: Failed to ioremap address: 0x%lx\n",
- __FUNCTION__, flash_addr);
- return -EIO;
- }
-
- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if (mtd_size >= flash_size)
- break;
-
- pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
-
- map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
- if (map_banks[idx] == NULL) {
- ret = -ENOMEM;
- goto error_mem;
- }
- map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
- if (map_banks[idx]->name == NULL) {
- ret = -ENOMEM;
- goto error_mem;
- }
-
- sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
- map_banks[idx]->size = flash_size;
- map_banks[idx]->bankwidth = 4;
-
- simple_map_init(map_banks[idx]);
-
- map_banks[idx]->virt = (void __iomem *)
- (start_scan_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
- map_banks[idx]->phys =
- flash_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
-
- /* start to probe flash chips */
- mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
- if (mtd_banks[idx]) {
- mtd_banks[idx]->owner = THIS_MODULE;
- mtd_size += mtd_banks[idx]->size;
- num_banks++;
- pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
- __FUNCTION__, num_banks,
- mtd_banks[idx]->name, mtd_banks[idx]->size);
- }
- }
-
- /* no supported flash chips found */
- if (!num_banks) {
- printk("TQM834x: No supported flash chips found!\n");
- ret = -ENXIO;
- goto error_mem;
- }
-
-#ifdef CONFIG_MTD_PARTITIONS
- /*
- * Select static partition definitions
- */
- n = ARRAY_SIZE(tqm834x_partitions_bank1);
- part_banks[0].mtd_part = tqm834x_partitions_bank1;
- part_banks[0].type = "static image bank1";
- part_banks[0].nums = n;
-
- /* update last partition size to cover actual remaining space */
- tqm834x_partitions_bank1[n - 1].size =
- mtd_banks[0]->size -
- tqm834x_partitions_bank1[n - 1].offset;
-
- /* check if we have second bank? */
- if (num_banks == 2) {
- n = ARRAY_SIZE(tqm834x_partitions_bank2);
- part_banks[1].mtd_part = tqm834x_partitions_bank2;
- part_banks[1].type = "static image bank2";
- part_banks[1].nums = n;
-
- /* update last partition size to cover actual remaining space */
- tqm834x_partitions_bank2[n - 1].size =
- mtd_banks[1]->size -
- tqm834x_partitions_bank2[n - 1].offset;
- }
-
- for(idx = 0; idx < num_banks ; idx++) {
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- sprintf(mtdid, "%d", idx);
- n = parse_mtd_partitions(mtd_banks[idx],
- part_probes,
- &part_banks[idx].mtd_part,
- 0);
- pr_debug("%s: %d command line partitions on bank %s\n",
- __FUNCTION__, n, mtdid);
- if (n > 0) {
- part_banks[idx].type = "command line";
- part_banks[idx].nums = n;
- }
-#endif /* CONFIG_MTD_CMDLINE_PARTS */
- if (part_banks[idx].nums == 0) {
- printk(KERN_NOTICE
- "TQM834x flash bank %d: no partition info "
- "available, registering whole device\n", idx);
- add_mtd_device(mtd_banks[idx]);
- } else {
- printk(KERN_NOTICE
- "TQM834x flash bank %d: Using %s partition "
- "definition\n", idx, part_banks[idx].type);
- add_mtd_partitions(mtd_banks[idx],
- part_banks[idx].mtd_part,
- part_banks[idx].nums);
- }
- }
-#else /* ! CONFIG_MTD_PARTITIONS */
- printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
- "at once\n", num_banks);
-
- for(idx = 0 ; idx < num_banks ; idx++)
- add_mtd_device(mtd_banks[idx]);
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
- return 0;
-error_mem:
- for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if (map_banks[idx] != NULL) {
- if (map_banks[idx]->name != NULL) {
- kfree(map_banks[idx]->name);
- map_banks[idx]->name = NULL;
- }
- kfree(map_banks[idx]);
- map_banks[idx] = NULL;
- }
- }
-
- iounmap((void *)start_scan_addr);
-
- return ret;
-}
-
-static void __exit cleanup_tqm834x_mtd(void)
-{
- unsigned int idx = 0;
- for(idx = 0 ; idx < num_banks ; idx++) {
- /* destroy mtd_info previously allocated */
- if (mtd_banks[idx]) {
- del_mtd_partitions(mtd_banks[idx]);
- map_destroy(mtd_banks[idx]);
- }
-
- /* release map_info not used anymore */
- kfree(map_banks[idx]->name);
- kfree(map_banks[idx]);
- }
-
- if (start_scan_addr) {
- iounmap((void *)start_scan_addr);
- start_scan_addr = 0;
- }
-}
-
-module_init(init_tqm834x_mtd);
-module_exit(cleanup_tqm834x_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
-MODULE_DESCRIPTION("MTD map driver for TQM834x boards");
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index ef89780eb9d..74d9d30edab 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -24,10 +24,9 @@
#include <linux/kthread.h>
#include <asm/uaccess.h>
-static LIST_HEAD(blktrans_majors);
+#include "mtdcore.h"
-extern struct mutex mtd_table_mutex;
-extern struct mtd_info *mtd_table[];
+static LIST_HEAD(blktrans_majors);
struct mtd_blkcore_priv {
struct task_struct *thread;
@@ -202,7 +201,7 @@ static int blktrans_ioctl(struct inode *inode, struct file *file,
}
}
-struct block_device_operations mtd_blktrans_ops = {
+static struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index d091b2430b4..22ed96c4b7b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -136,7 +136,8 @@ static int mtd_close(struct inode *inode, struct file *file)
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- if (mtd->sync)
+ /* Only sync if opened RW */
+ if ((file->f_mode & 2) && mtd->sync)
mtd->sync(mtd);
put_mtd_device(mtd);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 41844ea0246..d563dcd4b26 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -178,7 +178,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
/* Check alignment */
if (mtd->writesize > 1) {
- loff_t __to = to;
+ uint64_t __to = to;
if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))
return -EINVAL;
}
@@ -726,6 +726,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
+ concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail;
if (subdev[0]->writev)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c153b64a830..6c2645e2837 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -22,6 +22,8 @@
#include <linux/mtd/mtd.h>
+#include "mtdcore.h"
+
/* These are exported solely for the purpose of mtd_blkdevs.c. You
should not use them for _anything_ else */
DEFINE_MUTEX(mtd_table_mutex);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
new file mode 100644
index 00000000000..a33251f4b87
--- /dev/null
+++ b/drivers/mtd/mtdcore.h
@@ -0,0 +1,11 @@
+/* linux/drivers/mtd/mtdcore.h
+ *
+ * Header file for driver private mtdcore exports
+ *
+ */
+
+/* These are exported solely for the purpose of mtd_blkdevs.c. You
+ should not use them for _anything_ else */
+
+extern struct mutex mtd_table_mutex;
+extern struct mtd_info *mtd_table[MAX_MTD_DEVICES];
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
new file mode 100644
index 00000000000..f8af627f0b9
--- /dev/null
+++ b/drivers/mtd/mtdoops.c
@@ -0,0 +1,376 @@
+/*
+ * MTD Oops/Panic logger
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+
+#define OOPS_PAGE_SIZE 4096
+
+static struct mtdoops_context {
+ int mtd_index;
+ struct work_struct work;
+ struct mtd_info *mtd;
+ int oops_pages;
+ int nextpage;
+ int nextcount;
+
+ void *oops_buf;
+ int ready;
+ int writecount;
+} oops_cxt;
+
+static void mtdoops_erase_callback(struct erase_info *done)
+{
+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+ wake_up(wait_q);
+}
+
+static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
+{
+ struct erase_info erase;
+ DECLARE_WAITQUEUE(wait, current);
+ wait_queue_head_t wait_q;
+ int ret;
+
+ init_waitqueue_head(&wait_q);
+ erase.mtd = mtd;
+ erase.callback = mtdoops_erase_callback;
+ erase.addr = offset;
+ if (mtd->erasesize < OOPS_PAGE_SIZE)
+ erase.len = OOPS_PAGE_SIZE;
+ else
+ erase.len = mtd->erasesize;
+ erase.priv = (u_long)&wait_q;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&wait_q, &wait);
+
+ ret = mtd->erase(mtd, &erase);
+ if (ret) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wait_q, &wait);
+ printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] "
+ "on \"%s\" failed\n",
+ erase.addr, erase.len, mtd->name);
+ return ret;
+ }
+
+ schedule(); /* Wait for erase to finish. */
+ remove_wait_queue(&wait_q, &wait);
+
+ return 0;
+}
+
+static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ size_t retlen;
+ u32 count;
+ int ret;
+
+ cxt->nextpage++;
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ cxt->nextcount++;
+ if (cxt->nextcount == 0xffffffff)
+ cxt->nextcount = 0;
+
+ ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
+ &retlen, (u_char *) &count);
+ if ((retlen != 4) || (ret < 0)) {
+ printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+ ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
+ retlen, ret);
+ return 1;
+ }
+
+ /* See if we need to erase the next block */
+ if (count != 0xffffffff)
+ return 1;
+
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
+ cxt->nextpage, cxt->nextcount);
+ cxt->ready = 1;
+ return 0;
+}
+
+static void mtdoops_prepare(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ int i = 0, j, ret, mod;
+
+ /* We were unregistered */
+ if (!mtd)
+ return;
+
+ mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
+ if (mod != 0) {
+ cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ }
+
+ while (mtd->block_isbad &&
+ mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+badblock:
+ printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
+ cxt->nextpage * OOPS_PAGE_SIZE);
+ i++;
+ cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) {
+ printk(KERN_ERR "mtdoops: All blocks bad!\n");
+ return;
+ }
+ }
+
+ for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
+ ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+
+ if (ret < 0) {
+ if (mtd->block_markbad)
+ mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+ goto badblock;
+ }
+
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+
+ cxt->ready = 1;
+}
+
+static void mtdoops_workfunc(struct work_struct *work)
+{
+ struct mtdoops_context *cxt =
+ container_of(work, struct mtdoops_context, work);
+
+ mtdoops_prepare(cxt);
+}
+
+static int find_next_position(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ int page, maxpos = 0;
+ u32 count, maxcount = 0xffffffff;
+ size_t retlen;
+
+ for (page = 0; page < cxt->oops_pages; page++) {
+ mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+ if (count == 0xffffffff)
+ continue;
+ if (maxcount == 0xffffffff) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count > maxcount) && (count < 0xc0000000)) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count > maxcount) && (count > 0xc0000000)
+ && (maxcount > 0x80000000)) {
+ maxcount = count;
+ maxpos = page;
+ }
+ }
+ if (maxcount == 0xffffffff) {
+ cxt->nextpage = 0;
+ cxt->nextcount = 1;
+ cxt->ready = 1;
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
+ cxt->nextpage, cxt->nextcount);
+ return 0;
+ }
+
+ cxt->nextpage = maxpos;
+ cxt->nextcount = maxcount;
+
+ return mtdoops_inc_counter(cxt);
+}
+
+
+static void mtdoops_notify_add(struct mtd_info *mtd)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+ int ret;
+
+ if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+ return;
+
+ if (mtd->size < (mtd->erasesize * 2)) {
+ printk(KERN_ERR "MTD partition %d not big enough for mtdoops\n",
+ mtd->index);
+ return;
+ }
+
+ cxt->mtd = mtd;
+ cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
+
+ ret = find_next_position(cxt);
+ if (ret == 1)
+ mtdoops_prepare(cxt);
+
+ printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+}
+
+static void mtdoops_notify_remove(struct mtd_info *mtd)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+ return;
+
+ cxt->mtd = NULL;
+ flush_scheduled_work();
+}
+
+static void mtdoops_console_sync(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+ struct mtd_info *mtd = cxt->mtd;
+ size_t retlen;
+ int ret;
+
+ if (!cxt->ready || !mtd)
+ return;
+
+ if (cxt->writecount == 0)
+ return;
+
+ if (cxt->writecount < OOPS_PAGE_SIZE)
+ memset(cxt->oops_buf + cxt->writecount, 0xff,
+ OOPS_PAGE_SIZE - cxt->writecount);
+
+ ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+ OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+ cxt->ready = 0;
+ cxt->writecount = 0;
+
+ if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+ printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+ cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+
+ ret = mtdoops_inc_counter(cxt);
+ if (ret == 1)
+ schedule_work(&cxt->work);
+}
+
+static void
+mtdoops_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct mtdoops_context *cxt = co->data;
+ struct mtd_info *mtd = cxt->mtd;
+ int i;
+
+ if (!oops_in_progress) {
+ mtdoops_console_sync();
+ return;
+ }
+
+ if (!cxt->ready || !mtd)
+ return;
+
+ if (cxt->writecount == 0) {
+ u32 *stamp = cxt->oops_buf;
+ *stamp = cxt->nextcount;
+ cxt->writecount = 4;
+ }
+
+ if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
+ count = OOPS_PAGE_SIZE - cxt->writecount;
+
+ for (i = 0; i < count; i++, s++)
+ *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s;
+
+ cxt->writecount = cxt->writecount + count;
+}
+
+static int __init mtdoops_console_setup(struct console *co, char *options)
+{
+ struct mtdoops_context *cxt = co->data;
+
+ if (cxt->mtd_index != -1)
+ return -EBUSY;
+ if (co->index == -1)
+ return -EINVAL;
+
+ cxt->mtd_index = co->index;
+ return 0;
+}
+
+static struct mtd_notifier mtdoops_notifier = {
+ .add = mtdoops_notify_add,
+ .remove = mtdoops_notify_remove,
+};
+
+static struct console mtdoops_console = {
+ .name = "ttyMTD",
+ .write = mtdoops_console_write,
+ .setup = mtdoops_console_setup,
+ .unblank = mtdoops_console_sync,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &oops_cxt,
+};
+
+static int __init mtdoops_console_init(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ cxt->mtd_index = -1;
+ cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
+
+ if (!cxt->oops_buf) {
+ printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&cxt->work, mtdoops_workfunc);
+
+ register_console(&mtdoops_console);
+ register_mtd_user(&mtdoops_notifier);
+ return 0;
+}
+
+static void __exit mtdoops_console_exit(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ unregister_mtd_user(&mtdoops_notifier);
+ unregister_console(&mtdoops_console);
+ vfree(cxt->oops_buf);
+}
+
+
+subsys_initcall(mtdoops_console_init);
+module_exit(mtdoops_console_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1d60b6f048..8f9c3baeb38 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -91,6 +91,25 @@ config MTD_NAND_AU1550
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
+config MTD_NAND_BF5XX
+ tristate "Blackfin on-chip NAND Flash Controller driver"
+ depends on BF54x && MTD_NAND
+ help
+ This enables the Blackfin on-chip NAND flash controller
+
+ No board specific support is done by this driver, each board
+ must advertise a platform_device for the driver to attach.
+
+ This driver can also be built as a module. If so, the module
+ will be called bf5xx-nand.
+
+config MTD_NAND_BF5XX_HWECC
+ bool "BF5XX NAND Hardware ECC"
+ depends on MTD_NAND_BF5XX
+ help
+ Enable the use of the BF5XX's internal ECC generator when
+ using NAND.
+
config MTD_NAND_RTC_FROM4
tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
depends on SH_SOLUTION_ENGINE
@@ -134,10 +153,10 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
- depends on 44x
+ depends on 4xx && !PPC_MERGE
select MTD_NAND_ECC_SMC
help
- NDFC Nand Flash Controllers are integrated in EP44x SoCs
+ NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "S3C2410 NAND IDLE clock stop"
@@ -237,7 +256,7 @@ config MTD_NAND_CAFE
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
- Use NAND flash attached to the CAFÉ chip designed for the $100
+ Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
@@ -280,5 +299,11 @@ config MTD_NAND_PLATFORM
devices. You will need to provide platform-specific functions
via platform_data.
+config MTD_ALAUDA
+ tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1"
+ depends on MTD_NAND && USB
+ help
+ These two (and possibly other) Alauda-based cardreaders for
+ SmartMedia and xD allow raw flash access.
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index edba1db14bf..3ad6c0165da 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
+obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
@@ -27,5 +28,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
+obj-$(CONFIG_MTD_ALAUDA) += alauda.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
new file mode 100644
index 00000000000..257937cd99b
--- /dev/null
+++ b/drivers/mtd/nand/alauda.c
@@ -0,0 +1,742 @@
+/*
+ * MTD driver for Alauda chips
+ *
+ * Copyright (C) 2007 Joern Engel <joern@logfs.org>
+ *
+ * Based on drivers/usb/usb-skeleton.c which is:
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * and on drivers/usb/storage/alauda.c, which is:
+ * (c) 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * Idea and initial work by Arnd Bergmann <arnd@arndb.de>
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand_ecc.h>
+
+/* Control commands */
+#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
+#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
+#define ALAUDA_GET_XD_MEDIA_SIG 0x86
+
+/* Common prefix */
+#define ALAUDA_BULK_CMD 0x40
+
+/* The two ports */
+#define ALAUDA_PORT_XD 0x00
+#define ALAUDA_PORT_SM 0x01
+
+/* Bulk commands */
+#define ALAUDA_BULK_READ_PAGE 0x84
+#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */
+#define ALAUDA_BULK_READ_BLOCK 0x94
+#define ALAUDA_BULK_ERASE_BLOCK 0xa3
+#define ALAUDA_BULK_WRITE_PAGE 0xa4
+#define ALAUDA_BULK_WRITE_BLOCK 0xb4
+#define ALAUDA_BULK_RESET_MEDIA 0xe0
+
+/* Address shifting */
+#define PBA_LO(pba) ((pba & 0xF) << 5)
+#define PBA_HI(pba) (pba >> 3)
+#define PBA_ZONE(pba) (pba >> 11)
+
+#define TIMEOUT HZ
+
+static struct usb_device_id alauda_table [] = {
+ { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */
+ { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, alauda_table);
+
+struct alauda_card {
+ u8 id; /* id byte */
+ u8 chipshift; /* 1<<chipshift total size */
+ u8 pageshift; /* 1<<pageshift page size */
+ u8 blockshift; /* 1<<blockshift block size */
+};
+
+struct alauda {
+ struct usb_device *dev;
+ struct usb_interface *interface;
+ struct mtd_info *mtd;
+ struct alauda_card *card;
+ struct mutex card_mutex;
+ u32 pagemask;
+ u32 bytemask;
+ u32 blockmask;
+ unsigned int write_out;
+ unsigned int bulk_in;
+ unsigned int bulk_out;
+ u8 port;
+ struct kref kref;
+};
+
+static struct alauda_card alauda_card_ids[] = {
+ /* NAND flash */
+ { 0x6e, 20, 8, 12}, /* 1 MB */
+ { 0xe8, 20, 8, 12}, /* 1 MB */
+ { 0xec, 20, 8, 12}, /* 1 MB */
+ { 0x64, 21, 8, 12}, /* 2 MB */
+ { 0xea, 21, 8, 12}, /* 2 MB */
+ { 0x6b, 22, 9, 13}, /* 4 MB */
+ { 0xe3, 22, 9, 13}, /* 4 MB */
+ { 0xe5, 22, 9, 13}, /* 4 MB */
+ { 0xe6, 23, 9, 13}, /* 8 MB */
+ { 0x73, 24, 9, 14}, /* 16 MB */
+ { 0x75, 25, 9, 14}, /* 32 MB */
+ { 0x76, 26, 9, 14}, /* 64 MB */
+ { 0x79, 27, 9, 14}, /* 128 MB */
+ { 0x71, 28, 9, 14}, /* 256 MB */
+
+ /* MASK ROM */
+ { 0x5d, 21, 9, 13}, /* 2 MB */
+ { 0xd5, 22, 9, 13}, /* 4 MB */
+ { 0xd6, 23, 9, 13}, /* 8 MB */
+ { 0x57, 24, 9, 13}, /* 16 MB */
+ { 0x58, 25, 9, 13}, /* 32 MB */
+ { }
+};
+
+static struct alauda_card *get_card(u8 id)
+{
+ struct alauda_card *card;
+
+ for (card = alauda_card_ids; card->id; card++)
+ if (card->id == id)
+ return card;
+ return NULL;
+}
+
+static void alauda_delete(struct kref *kref)
+{
+ struct alauda *al = container_of(kref, struct alauda, kref);
+
+ if (al->mtd) {
+ del_mtd_device(al->mtd);
+ kfree(al->mtd);
+ }
+ usb_put_dev(al->dev);
+ kfree(al);
+}
+
+static int alauda_get_media_status(struct alauda *al, void *buf)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+ ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static int alauda_ack_media(struct alauda *al)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
+ ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static int alauda_get_media_signatures(struct alauda *al, void *buf)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+ ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static void alauda_reset(struct alauda *al)
+{
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
+ 0, 0, 0, 0, al->port
+ };
+ mutex_lock(&al->card_mutex);
+ usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
+ mutex_unlock(&al->card_mutex);
+}
+
+static void correct_data(void *buf, void *read_ecc,
+ int *corrected, int *uncorrected)
+{
+ u8 calc_ecc[3];
+ int err;
+
+ nand_calculate_ecc(NULL, buf, calc_ecc);
+ err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
+ if (err) {
+ if (err > 0)
+ (*corrected)++;
+ else
+ (*uncorrected)++;
+ }
+}
+
+struct alauda_sg_request {
+ struct urb *urb[3];
+ struct completion comp;
+};
+
+static void alauda_complete(struct urb *urb)
+{
+ struct completion *comp = urb->context;
+
+ if (comp)
+ complete(comp);
+}
+
+static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
+ void *oob)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = from >> al->card->blockshift;
+ u32 page = (from >> al->card->pageshift) & al->pagemask;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
+ };
+ int i, err;
+
+ for (i=0; i<3; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<3; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<3; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<3; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ usb_free_urb(sg.urb[2]);
+ return err;
+}
+
+static int alauda_read_page(struct mtd_info *mtd, loff_t from,
+ void *buf, u8 *oob, int *corrected, int *uncorrected)
+{
+ int err;
+
+ err = __alauda_read_page(mtd, from, buf, oob);
+ if (err)
+ return err;
+ correct_data(buf, oob+13, corrected, uncorrected);
+ correct_data(buf+256, oob+8, corrected, uncorrected);
+ return 0;
+}
+
+static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
+ void *oob)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = to >> al->card->blockshift;
+ u32 page = (to >> al->card->pageshift) & al->pagemask;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
+ };
+ int i, err;
+
+ for (i=0; i<3; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<3; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<3; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<3; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ usb_free_urb(sg.urb[2]);
+ return err;
+}
+
+static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = ofs >> al->card->blockshift;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
+ };
+ u8 buf[2];
+ int i, err;
+
+ for (i=0; i<2; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<2; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<2; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<2; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ return err;
+}
+
+static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
+{
+ static u8 ignore_buf[512]; /* write only */
+
+ return __alauda_read_page(mtd, from, ignore_buf, oob);
+}
+
+static int popcount8(u8 c)
+{
+ int ret = 0;
+
+ for ( ; c; c>>=1)
+ ret += c & 1;
+ return ret;
+}
+
+static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+ u8 oob[16];
+ int err;
+
+ err = alauda_read_oob(mtd, ofs, oob);
+ if (err)
+ return err;
+
+ /* A block is marked bad if two or more bits are zero */
+ return popcount8(oob[5]) >= 7 ? 0 : 1;
+}
+
+static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ void *bounce_buf;
+ int err, corrected=0, uncorrected=0;
+
+ bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!bounce_buf)
+ return -ENOMEM;
+
+ *retlen = len;
+ while (len) {
+ u8 oob[16];
+ size_t byte = from & al->bytemask;
+ size_t cplen = min(len, mtd->writesize - byte);
+
+ err = alauda_read_page(mtd, from, bounce_buf, oob,
+ &corrected, &uncorrected);
+ if (err)
+ goto out;
+
+ memcpy(buf, bounce_buf + byte, cplen);
+ buf += cplen;
+ from += cplen;
+ len -= cplen;
+ }
+ err = 0;
+ if (corrected)
+ err = -EUCLEAN;
+ if (uncorrected)
+ err = -EBADMSG;
+out:
+ kfree(bounce_buf);
+ return err;
+}
+
+static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ int err, corrected=0, uncorrected=0;
+
+ if ((from & al->bytemask) || (len & al->bytemask))
+ return alauda_bounce_read(mtd, from, len, retlen, buf);
+
+ *retlen = len;
+ while (len) {
+ u8 oob[16];
+
+ err = alauda_read_page(mtd, from, buf, oob,
+ &corrected, &uncorrected);
+ if (err)
+ return err;
+
+ buf += mtd->writesize;
+ from += mtd->writesize;
+ len -= mtd->writesize;
+ }
+ err = 0;
+ if (corrected)
+ err = -EUCLEAN;
+ if (uncorrected)
+ err = -EBADMSG;
+ return err;
+}
+
+static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ int err;
+
+ if ((to & al->bytemask) || (len & al->bytemask))
+ return -EINVAL;
+
+ *retlen = len;
+ while (len) {
+ u32 page = (to >> al->card->pageshift) & al->pagemask;
+ u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ /* don't write to bad blocks */
+ if (page == 0) {
+ err = alauda_isbad(mtd, to);
+ if (err) {
+ return -EIO;
+ }
+ }
+ nand_calculate_ecc(mtd, buf, &oob[13]);
+ nand_calculate_ecc(mtd, buf+256, &oob[8]);
+
+ err = alauda_write_page(mtd, to, (void*)buf, oob);
+ if (err)
+ return err;
+
+ buf += mtd->writesize;
+ to += mtd->writesize;
+ len -= mtd->writesize;
+ }
+ return 0;
+}
+
+static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct alauda *al = mtd->priv;
+ u32 ofs = instr->addr;
+ u32 len = instr->len;
+ int err;
+
+ if ((ofs & al->blockmask) || (len & al->blockmask))
+ return -EINVAL;
+
+ while (len) {
+ /* don't erase bad blocks */
+ err = alauda_isbad(mtd, ofs);
+ if (err > 0)
+ err = -EIO;
+ if (err < 0)
+ return err;
+
+ err = alauda_erase_block(mtd, ofs);
+ if (err < 0)
+ return err;
+
+ ofs += mtd->erasesize;
+ len -= mtd->erasesize;
+ }
+ return 0;
+}
+
+static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ int err;
+
+ err = __alauda_erase(mtd, instr);
+ instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+ return err;
+}
+
+static int alauda_init_media(struct alauda *al)
+{
+ u8 buf[4], *b0=buf, *b1=buf+1;
+ struct alauda_card *card;
+ struct mtd_info *mtd;
+ int err;
+
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
+ if (!mtd)
+ return -ENOMEM;
+
+ for (;;) {
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ goto error;
+ if (*b0 & 0x10)
+ break;
+ msleep(20);
+ }
+
+ err = alauda_ack_media(al);
+ if (err)
+ goto error;
+
+ msleep(10);
+
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ goto error;
+
+ if (*b0 != 0x14) {
+ /* media not ready */
+ err = -EIO;
+ goto error;
+ }
+ err = alauda_get_media_signatures(al, buf);
+ if (err < 0)
+ goto error;
+
+ card = get_card(*b1);
+ if (!card) {
+ printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
+ err = -EIO;
+ goto error;
+ }
+ printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
+ 1<<card->pageshift, 1<<card->blockshift,
+ 1<<(card->chipshift-20));
+ al->card = card;
+ al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
+ al->bytemask = (1 << card->pageshift) - 1;
+ al->blockmask = (1 << card->blockshift) - 1;
+
+ mtd->name = "alauda";
+ mtd->size = 1<<card->chipshift;
+ mtd->erasesize = 1<<card->blockshift;
+ mtd->writesize = 1<<card->pageshift;
+ mtd->type = MTD_NANDFLASH;
+ mtd->flags = MTD_CAP_NANDFLASH;
+ mtd->read = alauda_read;
+ mtd->write = alauda_write;
+ mtd->erase = alauda_erase;
+ mtd->block_isbad = alauda_isbad;
+ mtd->priv = al;
+ mtd->owner = THIS_MODULE;
+
+ err = add_mtd_device(mtd);
+ if (err) {
+ err = -ENFILE;
+ goto error;
+ }
+
+ al->mtd = mtd;
+ alauda_reset(al); /* no clue whether this is necessary */
+ return 0;
+error:
+ kfree(mtd);
+ return err;
+}
+
+static int alauda_check_media(struct alauda *al)
+{
+ u8 buf[2], *b0 = buf, *b1 = buf+1;
+ int err;
+
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ return err;
+
+ if ((*b1 & 0x01) == 0) {
+ /* door open */
+ return -EIO;
+ }
+ if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
+ /* no media ? */
+ return -EIO;
+ }
+ if (*b0 & 0x08) {
+ /* media change ? */
+ return alauda_init_media(al);
+ }
+ return 0;
+}
+
+static int alauda_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct alauda *al;
+ struct usb_host_interface *iface;
+ struct usb_endpoint_descriptor *ep,
+ *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
+ int i, err = -ENOMEM;
+
+ al = kzalloc(2*sizeof(*al), GFP_KERNEL);
+ if (!al)
+ goto error;
+
+ kref_init(&al->kref);
+ usb_set_intfdata(interface, al);
+
+ al->dev = usb_get_dev(interface_to_usbdev(interface));
+ al->interface = interface;
+
+ iface = interface->cur_altsetting;
+ for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+ ep = &iface->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep)) {
+ ep_in = ep;
+ } else if (usb_endpoint_is_bulk_out(ep)) {
+ if (i==0)
+ ep_wr = ep;
+ else
+ ep_out = ep;
+ }
+ }
+ err = -EIO;
+ if (!ep_wr || !ep_in || !ep_out)
+ goto error;
+
+ al->write_out = usb_sndbulkpipe(al->dev,
+ ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ al->bulk_in = usb_rcvbulkpipe(al->dev,
+ ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ al->bulk_out = usb_sndbulkpipe(al->dev,
+ ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+ /* second device is identical up to now */
+ memcpy(al+1, al, sizeof(*al));
+
+ mutex_init(&al[0].card_mutex);
+ mutex_init(&al[1].card_mutex);
+
+ al[0].port = ALAUDA_PORT_XD;
+ al[1].port = ALAUDA_PORT_SM;
+
+ info("alauda probed");
+ alauda_check_media(al);
+ alauda_check_media(al+1);
+
+ return 0;
+
+error:
+ if (al)
+ kref_put(&al->kref, alauda_delete);
+ return err;
+}
+
+static void alauda_disconnect(struct usb_interface *interface)
+{
+ struct alauda *al;
+
+ al = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /* FIXME: prevent more I/O from starting */
+
+ /* decrement our usage count */
+ if (al)
+ kref_put(&al->kref, alauda_delete);
+
+ info("alauda gone");
+}
+
+static struct usb_driver alauda_driver = {
+ .name = "alauda",
+ .probe = alauda_probe,
+ .disconnect = alauda_disconnect,
+ .id_table = alauda_table,
+};
+
+static int __init alauda_init(void)
+{
+ return usb_register(&alauda_driver);
+}
+
+static void __exit alauda_exit(void)
+{
+ usb_deregister(&alauda_driver);
+}
+
+module_init(alauda_init);
+module_exit(alauda_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
new file mode 100644
index 00000000000..1657ecd7488
--- /dev/null
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -0,0 +1,788 @@
+/* linux/drivers/mtd/nand/bf5xx_nand.c
+ *
+ * Copyright 2006-2007 Analog Devices Inc.
+ * http://blackfin.uclinux.org/
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Blackfin BF5xx on-chip NAND flash controler driver
+ *
+ * Derived from drivers/mtd/nand/s3c2410.c
+ * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
+ *
+ * Derived from drivers/mtd/nand/cafe.c
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Changelog:
+ * 12-Jun-2007 Bryan Wu: Initial version
+ * 18-Jul-2007 Bryan Wu:
+ * - ECC_HW and ECC_SW supported
+ * - DMA supported in ECC_HW
+ * - YAFFS tested as rootfs in both ECC_HW and ECC_SW
+ *
+ * TODO:
+ * Enable JFFS2 over NAND as rootfs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME "bf5xx-nand"
+#define DRV_VERSION "1.2"
+#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>"
+#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver"
+
+#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
+static int hardware_ecc = 1;
+#else
+static int hardware_ecc;
+#endif
+
+static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+
+/*
+ * Data structures for bf5xx nand flash controller driver
+ */
+
+/* bf5xx nand info */
+struct bf5xx_nand_info {
+ /* mtd info */
+ struct nand_hw_control controller;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+
+ /* platform info */
+ struct bf5xx_nand_platform *platform;
+
+ /* device info */
+ struct device *device;
+
+ /* DMA stuff */
+ struct completion dma_completion;
+};
+
+/*
+ * Conversion functions
+ */
+static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+{
+ return container_of(mtd, struct bf5xx_nand_info, mtd);
+}
+
+static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
+{
+ return platform_get_drvdata(pdev);
+}
+
+static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
+{
+ return pdev->dev.platform_data;
+}
+
+/*
+ * struct nand_chip interface function pointers
+ */
+
+/*
+ * bf5xx_nand_hwcontrol
+ *
+ * Issue command and address cycles to the chip
+ */
+static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ if (ctrl & NAND_CLE)
+ bfin_write_NFC_CMD(cmd);
+ else
+ bfin_write_NFC_ADDR(cmd);
+ SSYNC();
+}
+
+/*
+ * bf5xx_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+ */
+static int bf5xx_nand_devready(struct mtd_info *mtd)
+{
+ unsigned short val = bfin_read_NFC_IRQSTAT();
+
+ if ((val & NBUSYIRQ) == NBUSYIRQ)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * ECC functions
+ * These allow the bf5xx to use the controller's ECC
+ * generator block to ECC the data as it passes through
+ */
+
+/*
+ * ECC error correction function
+ */
+static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ u32 syndrome[5];
+ u32 calced, stored;
+ int i;
+ unsigned short failing_bit, failing_byte;
+ u_char data;
+
+ calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
+ stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
+
+ syndrome[0] = (calced ^ stored);
+
+ /*
+ * syndrome 0: all zero
+ * No error in data
+ * No action
+ */
+ if (!syndrome[0] || !calced || !stored)
+ return 0;
+
+ /*
+ * sysdrome 0: only one bit is one
+ * ECC data was incorrect
+ * No action
+ */
+ if (hweight32(syndrome[0]) == 1) {
+ dev_err(info->device, "ECC data was incorrect!\n");
+ return 1;
+ }
+
+ syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
+ syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
+ syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
+ syndrome[4] = syndrome[2] ^ syndrome[3];
+
+ for (i = 0; i < 5; i++)
+ dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
+
+ dev_info(info->device,
+ "calced[0x%08x], stored[0x%08x]\n",
+ calced, stored);
+
+ /*
+ * sysdrome 0: exactly 11 bits are one, each parity
+ * and parity' pair is 1 & 0 or 0 & 1.
+ * 1-bit correctable error
+ * Correct the error
+ */
+ if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
+ dev_info(info->device,
+ "1-bit correctable error, correct it.\n");
+ dev_info(info->device,
+ "syndrome[1] 0x%08x\n", syndrome[1]);
+
+ failing_bit = syndrome[1] & 0x7;
+ failing_byte = syndrome[1] >> 0x3;
+ data = *(dat + failing_byte);
+ data = data ^ (0x1 << failing_bit);
+ *(dat + failing_byte) = data;
+
+ return 0;
+ }
+
+ /*
+ * sysdrome 0: random data
+ * More than 1-bit error, non-correctable error
+ * Discard data, mark bad block
+ */
+ dev_err(info->device,
+ "More than 1-bit error, non-correctable error.\n");
+ dev_err(info->device,
+ "Please discard data, mark bad block\n");
+
+ return 1;
+}
+
+static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+ int ret;
+
+ ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+
+ /* If page size is 512, correct second 256 bytes */
+ if (page_size == 512) {
+ dat += 256;
+ read_ecc += 8;
+ calc_ecc += 8;
+ ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+ }
+
+ return ret;
+}
+
+static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ return;
+}
+
+static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
+ const u_char *dat, u_char *ecc_code)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ u16 page_size = (plat->page_size ? 512 : 256);
+ u16 ecc0, ecc1;
+ u32 code[2];
+ u8 *p;
+ int bytes = 3, i;
+
+ /* first 4 bytes ECC code for 256 page size */
+ ecc0 = bfin_read_NFC_ECC0();
+ ecc1 = bfin_read_NFC_ECC1();
+
+ code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+
+ dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
+
+ /* second 4 bytes ECC code for 512 page size */
+ if (page_size == 512) {
+ ecc0 = bfin_read_NFC_ECC2();
+ ecc1 = bfin_read_NFC_ECC3();
+ code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+ bytes = 6;
+ dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
+ }
+
+ p = (u8 *)code;
+ for (i = 0; i < bytes; i++)
+ ecc_code[i] = p[i];
+
+ return 0;
+}
+
+/*
+ * PIO mode for buffer writing and reading
+ */
+static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ unsigned short val;
+
+ /*
+ * Data reads are requested by first writing to NFC_DATA_RD
+ * and then reading back from NFC_READ.
+ */
+ for (i = 0; i < len; i++) {
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ /* Contents do not matter */
+ bfin_write_NFC_DATA_RD(0x0000);
+ SSYNC();
+
+ while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
+ cpu_relax();
+
+ buf[i] = bfin_read_NFC_READ();
+
+ val = bfin_read_NFC_IRQSTAT();
+ val |= RD_RDY;
+ bfin_write_NFC_IRQSTAT(val);
+ SSYNC();
+ }
+}
+
+static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
+{
+ uint8_t val;
+
+ bf5xx_nand_read_buf(mtd, &val, 1);
+
+ return val;
+}
+
+static void bf5xx_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ bfin_write_NFC_DATA_WR(buf[i]);
+ SSYNC();
+ }
+}
+
+static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ u16 *p = (u16 *) buf;
+ len >>= 1;
+
+ /*
+ * Data reads are requested by first writing to NFC_DATA_RD
+ * and then reading back from NFC_READ.
+ */
+ bfin_write_NFC_DATA_RD(0x5555);
+
+ SSYNC();
+
+ for (i = 0; i < len; i++)
+ p[i] = bfin_read_NFC_READ();
+}
+
+static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ int i;
+ u16 *p = (u16 *) buf;
+ len >>= 1;
+
+ for (i = 0; i < len; i++)
+ bfin_write_NFC_DATA_WR(p[i]);
+
+ SSYNC();
+}
+
+/*
+ * DMA functions for buffer writing and reading
+ */
+static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
+{
+ struct bf5xx_nand_info *info = dev_id;
+
+ clear_dma_irqstat(CH_NFC);
+ disable_dma(CH_NFC);
+ complete(&info->dma_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int bf5xx_nand_dma_rw(struct mtd_info *mtd,
+ uint8_t *buf, int is_read)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+ unsigned short val;
+
+ dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
+ mtd, buf, is_read);
+
+ /*
+ * Before starting a dma transfer, be sure to invalidate/flush
+ * the cache over the address range of your DMA buffer to
+ * prevent cache coherency problems. Otherwise very subtle bugs
+ * can be introduced to your driver.
+ */
+ if (is_read)
+ invalidate_dcache_range((unsigned int)buf,
+ (unsigned int)(buf + page_size));
+ else
+ flush_dcache_range((unsigned int)buf,
+ (unsigned int)(buf + page_size));
+
+ /*
+ * This register must be written before each page is
+ * transferred to generate the correct ECC register
+ * values.
+ */
+ bfin_write_NFC_RST(0x1);
+ SSYNC();
+
+ disable_dma(CH_NFC);
+ clear_dma_irqstat(CH_NFC);
+
+ /* setup DMA register with Blackfin DMA API */
+ set_dma_config(CH_NFC, 0x0);
+ set_dma_start_addr(CH_NFC, (unsigned long) buf);
+ set_dma_x_count(CH_NFC, (page_size >> 2));
+ set_dma_x_modify(CH_NFC, 4);
+
+ /* setup write or read operation */
+ val = DI_EN | WDSIZE_32;
+ if (is_read)
+ val |= WNR;
+ set_dma_config(CH_NFC, val);
+ enable_dma(CH_NFC);
+
+ /* Start PAGE read/write operation */
+ if (is_read)
+ bfin_write_NFC_PGCTL(0x1);
+ else
+ bfin_write_NFC_PGCTL(0x2);
+ wait_for_completion(&info->dma_completion);
+
+ return 0;
+}
+
+static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
+ uint8_t *buf, int len)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+
+ dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
+
+ if (len == page_size)
+ bf5xx_nand_dma_rw(mtd, buf, 1);
+ else
+ bf5xx_nand_read_buf(mtd, buf, len);
+}
+
+static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+
+ dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
+
+ if (len == page_size)
+ bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
+ else
+ bf5xx_nand_write_buf(mtd, buf, len);
+}
+
+/*
+ * System initialization functions
+ */
+
+static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
+{
+ int ret;
+ unsigned short val;
+
+ /* Do not use dma */
+ if (!hardware_ecc)
+ return 0;
+
+ init_completion(&info->dma_completion);
+
+ /* Setup DMAC1 channel mux for NFC which shared with SDH */
+ val = bfin_read_DMAC1_PERIMUX();
+ val &= 0xFFFE;
+ bfin_write_DMAC1_PERIMUX(val);
+ SSYNC();
+
+ /* Request NFC DMA channel */
+ ret = request_dma(CH_NFC, "BF5XX NFC driver");
+ if (ret < 0) {
+ dev_err(info->device, " unable to get DMA channel\n");
+ return ret;
+ }
+
+ set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info);
+
+ /* Turn off the DMA channel first */
+ disable_dma(CH_NFC);
+ return 0;
+}
+
+/*
+ * BF5XX NFC hardware initialization
+ * - pin mux setup
+ * - clear interrupt status
+ */
+static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
+{
+ int err = 0;
+ unsigned short val;
+ struct bf5xx_nand_platform *plat = info->platform;
+
+ /* setup NFC_CTL register */
+ dev_info(info->device,
+ "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n",
+ (plat->page_size ? 512 : 256),
+ (plat->data_width ? 16 : 8),
+ plat->wr_dly, plat->rd_dly);
+
+ val = (plat->page_size << NFC_PG_SIZE_OFFSET) |
+ (plat->data_width << NFC_NWIDTH_OFFSET) |
+ (plat->rd_dly << NFC_RDDLY_OFFSET) |
+ (plat->rd_dly << NFC_WRDLY_OFFSET);
+ dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
+
+ bfin_write_NFC_CTL(val);
+ SSYNC();
+
+ /* clear interrupt status */
+ bfin_write_NFC_IRQMASK(0x0);
+ SSYNC();
+ val = bfin_read_NFC_IRQSTAT();
+ bfin_write_NFC_IRQSTAT(val);
+ SSYNC();
+
+ if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ return -EFAULT;
+ }
+
+ /* DMA initialization */
+ if (bf5xx_nand_dma_init(info))
+ err = -ENXIO;
+
+ return err;
+}
+
+/*
+ * Device management interface
+ */
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+{
+ struct mtd_info *mtd = &info->mtd;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts = info->platform->partitions;
+ int nr = info->platform->nr_partitions;
+
+ return add_mtd_partitions(mtd, parts, nr);
+#else
+ return add_mtd_device(mtd);
+#endif
+}
+
+static int bf5xx_nand_remove(struct platform_device *pdev)
+{
+ struct bf5xx_nand_info *info = to_nand_info(pdev);
+ struct mtd_info *mtd = NULL;
+
+ platform_set_drvdata(pdev, NULL);
+
+ /* first thing we need to do is release all our mtds
+ * and their partitions, then go through freeing the
+ * resources used
+ */
+ mtd = &info->mtd;
+ if (mtd) {
+ nand_release(mtd);
+ kfree(mtd);
+ }
+
+ peripheral_free_list(bfin_nfc_pin_req);
+
+ /* free the common resources */
+ kfree(info);
+
+ return 0;
+}
+
+/*
+ * bf5xx_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+ */
+static int bf5xx_nand_probe(struct platform_device *pdev)
+{
+ struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
+ struct bf5xx_nand_info *info = NULL;
+ struct nand_chip *chip = NULL;
+ struct mtd_info *mtd = NULL;
+ int err = 0;
+
+ dev_dbg(&pdev->dev, "(%p)\n", pdev);
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform specific information\n");
+ goto exit_error;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&pdev->dev, "no memory for flash info\n");
+ err = -ENOMEM;
+ goto exit_error;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ spin_lock_init(&info->controller.lock);
+ init_waitqueue_head(&info->controller.wq);
+
+ info->device = &pdev->dev;
+ info->platform = plat;
+
+ /* initialise chip data struct */
+ chip = &info->chip;
+
+ if (plat->data_width)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
+
+ chip->read_buf = (plat->data_width) ?
+ bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
+ chip->write_buf = (plat->data_width) ?
+ bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
+
+ chip->read_byte = bf5xx_nand_read_byte;
+
+ chip->cmd_ctrl = bf5xx_nand_hwcontrol;
+ chip->dev_ready = bf5xx_nand_devready;
+
+ chip->priv = &info->mtd;
+ chip->controller = &info->controller;
+
+ chip->IO_ADDR_R = (void __iomem *) NFC_READ;
+ chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR;
+
+ chip->chip_delay = 0;
+
+ /* initialise mtd info data struct */
+ mtd = &info->mtd;
+ mtd->priv = chip;
+ mtd->owner = THIS_MODULE;
+
+ /* initialise the hardware */
+ err = bf5xx_nand_hw_init(info);
+ if (err != 0)
+ goto exit_error;
+
+ /* setup hardware ECC data struct */
+ if (hardware_ecc) {
+ if (plat->page_size == NFC_PG_SIZE_256) {
+ chip->ecc.bytes = 3;
+ chip->ecc.size = 256;
+ } else if (plat->page_size == NFC_PG_SIZE_512) {
+ chip->ecc.bytes = 6;
+ chip->ecc.size = 512;
+ }
+
+ chip->read_buf = bf5xx_nand_dma_read_buf;
+ chip->write_buf = bf5xx_nand_dma_write_buf;
+ chip->ecc.calculate = bf5xx_nand_calculate_ecc;
+ chip->ecc.correct = bf5xx_nand_correct_data;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.hwctl = bf5xx_nand_enable_hwecc;
+ } else {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ }
+
+ /* scan hardware nand chip and setup mtd info data struct */
+ if (nand_scan(mtd, 1)) {
+ err = -ENXIO;
+ goto exit_error;
+ }
+
+ /* add NAND partition */
+ bf5xx_nand_add_partition(info);
+
+ dev_dbg(&pdev->dev, "initialised ok\n");
+ return 0;
+
+exit_error:
+ bf5xx_nand_remove(pdev);
+
+ if (err == 0)
+ err = -EINVAL;
+ return err;
+}
+
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+ struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+ return 0;
+}
+
+static int bf5xx_nand_resume(struct platform_device *dev)
+{
+ struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+ if (info)
+ bf5xx_nand_hw_init(info);
+
+ return 0;
+}
+
+#else
+#define bf5xx_nand_suspend NULL
+#define bf5xx_nand_resume NULL
+#endif
+
+/* driver device registration */
+static struct platform_driver bf5xx_nand_driver = {
+ .probe = bf5xx_nand_probe,
+ .remove = bf5xx_nand_remove,
+ .suspend = bf5xx_nand_suspend,
+ .resume = bf5xx_nand_resume,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bf5xx_nand_init(void)
+{
+ printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
+ DRV_DESC, DRV_VERSION);
+
+ return platform_driver_register(&bf5xx_nand_driver);
+}
+
+static void __exit bf5xx_nand_exit(void)
+{
+ platform_driver_unregister(&bf5xx_nand_driver);
+}
+
+module_init(bf5xx_nand_init);
+module_exit(bf5xx_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 6f32a35eb10..1e811715211 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -80,7 +80,7 @@ module_param(regdebug, int, 0644);
static int checkecc = 1;
module_param(checkecc, int, 0644);
-static int numtimings;
+static unsigned int numtimings;
static int timing[3];
module_param_array(timing, int, &numtimings, 0644);
@@ -623,6 +623,11 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
uint32_t ctrl;
int err = 0;
+ /* Very old versions shared the same PCI ident for all three
+ functions on the chip. Verify the class too... */
+ if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
+ return -ENODEV;
+
err = pci_enable_device(pdev);
if (err)
return err;
@@ -816,21 +821,57 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
}
static struct pci_device_id cafe_nand_tbl[] = {
- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
- { 0, }
+ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+ { }
};
MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+static int cafe_nand_resume(struct pci_dev *pdev)
+{
+ uint32_t ctrl;
+ struct mtd_info *mtd = pci_get_drvdata(pdev);
+ struct cafe_priv *cafe = mtd->priv;
+
+ /* Start off by resetting the NAND controller completely */
+ cafe_writel(cafe, 1, NAND_RESET);
+ cafe_writel(cafe, 0, NAND_RESET);
+ cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+
+ /* Restore timing configuration */
+ cafe_writel(cafe, timing[0], NAND_TIMING1);
+ cafe_writel(cafe, timing[1], NAND_TIMING2);
+ cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+ /* Disable master reset, enable NAND clock */
+ ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+ ctrl &= 0xffffeff0;
+ ctrl |= 0x00007000;
+ cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+ cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+ cafe_writel(cafe, 0, NAND_DMA_CTRL);
+ cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+ cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+ /* Set up DMA address */
+ cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+ if (sizeof(cafe->dmaaddr) > 4)
+ /* Shift in two parts to shut the compiler up */
+ cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+ else
+ cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+ /* Enable NAND IRQ in global IRQ mask register */
+ cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+ return 0;
+}
+
static struct pci_driver cafe_nand_pci_driver = {
.name = "CAFÉ NAND",
.id_table = cafe_nand_tbl,
.probe = cafe_nand_probe,
.remove = __devexit_p(cafe_nand_remove),
-#ifdef CONFIG_PMx
- .suspend = cafe_nand_suspend,
.resume = cafe_nand_resume,
-#endif
};
static int cafe_nand_init(void)
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index e96259f22cc..ab9f5c5db38 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -56,8 +56,6 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
- 0xff000000,
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
index 7e9afc4c775..bed87290dec 100644
--- a/drivers/mtd/nand/excite_nandflash.c
+++ b/drivers/mtd/nand/excite_nandflash.c
@@ -27,7 +27,6 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 24ac6778b1a..b4e0e772389 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -7,7 +7,7 @@
* Basic support for AG-AND chips is provided.
*
* Additional technical information is available on
- * http://www.linux-mtd.infradead.org/tech/nand.html
+ * http://www.linux-mtd.infradead.org/doc/nand.html
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
@@ -2069,13 +2069,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
/*
* If BBT requires refresh and erase was successful, rewrite any
* selected bad block tables
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2fc674a190c..a3e3ab0185d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -141,6 +141,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
+ {NAND_MFR_AMD, "AMD"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 205df0f771f..a7574807dc4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -1272,7 +1272,13 @@ static int prog_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
- mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+ /*
+ * We allocate memory with GFP_NOFS because a flash FS may
+ * utilize this. If it is holding an FS lock, then gets here,
+ * then kmalloc runs writeback which goes to the FS again
+ * and deadlocks. This was seen in practice.
+ */
+ mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
if (mypage->byte == NULL) {
NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
return -1;
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index fd7a8d5ba29..1c0e89f00e8 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -24,7 +24,11 @@
#include <linux/platform_device.h>
#include <asm/io.h>
+#ifdef CONFIG_40x
+#include <asm/ibm405.h>
+#else
#include <asm/ibm44x.h>
+#endif
struct ndfc_nand_mtd {
struct mtd_info mtd;
@@ -230,7 +234,11 @@ static int ndfc_nand_probe(struct platform_device *pdev)
struct ndfc_controller *ndfc = &ndfc_ctrl;
unsigned long long phys = settings->ndfc_erpn | res->start;
+#ifndef CONFIG_PHYS_64BIT
+ ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+#else
ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+#endif
if (!ndfc->ndfcbase) {
printk(KERN_ERR "NDFC: ioremap failed\n");
return -EIO;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 5fac4c421a2..b79a9cf2d16 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -60,8 +60,8 @@
#include <asm/io.h>
-#include <asm/arch/regs-nand.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/regs-nand.h>
+#include <asm/plat-s3c/nand.h>
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int hardware_ecc = 1;
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index c257d397d08..cb41cbca64f 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -40,4 +40,27 @@ config MTD_ONENAND_OTP
OTP block is fully-guaranteed to be a valid block.
+config MTD_ONENAND_2X_PROGRAM
+ bool "OneNAND 2X program support"
+ help
+ The 2X Program is an extension of Program Operation.
+ Since the device is equipped with two DataRAMs, and two-plane NAND
+ Flash memory array, these two component enables simultaneous program
+ of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+ while Plane2 has only odd blocks such as block1, block3, block5.
+ So MTD regards it as 4KiB page size and 256KiB block size
+
+ Now the following chips support it. (KFXXX16Q2M)
+ Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M,
+ Mux: KFM2G16Q2M, KFN4G16Q2M,
+
+ And more recent chips
+
+config MTD_ONENAND_SIM
+ tristate "OneNAND simulator support"
+ depends on MTD_PARTITIONS
+ help
+ The simulator may simulate various OneNAND flash chips for the
+ OneNAND MTD layer.
+
endif # MTD_ONENAND
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile
index 269cfe46734..4d2eacfd7e1 100644
--- a/drivers/mtd/onenand/Makefile
+++ b/drivers/mtd/onenand/Makefile
@@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o
# Board specific.
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
+# Simulator
+obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o
+
onenand-objs = onenand_base.o onenand_bbt.o
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 0537fac8de7..dd283556909 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
default:
block = (int) (addr >> this->erase_shift);
page = (int) (addr >> this->page_shift);
+
+ if (ONENAND_IS_2PLANE(this)) {
+ /* Make the even block number */
+ block &= ~1;
+ /* Is it the odd plane? */
+ if (addr & this->writesize)
+ block++;
+ page >>= 1;
+ }
page &= this->page_mask;
break;
}
@@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
- /* Switch to the next data buffer */
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (ONENAND_IS_2PLANE(this))
+ /* It is always BufferRAM0 */
+ ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
return 0;
}
@@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
break;
default:
+ if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
+ cmd = ONENAND_CMD_2X_PROG;
dataram = ONENAND_CURRENT_BUFFERRAM(this);
break;
}
@@ -312,18 +327,20 @@ static int onenand_wait(struct mtd_info *mtd, int state)
printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
printk(KERN_ERR "onenand_wait: it's locked error.\n");
- return ctrl;
+ return -EIO;
}
if (interrupt & ONENAND_INT_READ) {
int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
if (ecc) {
- printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
mtd->ecc_stats.failed++;
- return ecc;
- } else if (ecc & ONENAND_ECC_1BIT_ALL)
+ return -EBADMSG;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+ printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
mtd->ecc_stats.corrected++;
+ }
}
} else if (state == FL_READING) {
printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
@@ -445,8 +462,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
struct onenand_chip *this = mtd->priv;
if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ /* Note: the 'this->writesize' is a real page size */
if (area == ONENAND_DATARAM)
- return mtd->writesize;
+ return this->writesize;
if (area == ONENAND_SPARERAM)
return mtd->oobsize;
}
@@ -572,6 +590,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
}
/**
+ * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
+ * @param mtd MTD data structure
+ * @param addr address to check
+ * @return blockpage address
+ *
+ * Get blockpage address at 2x program mode
+ */
+static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blockpage, block, page;
+
+ /* Calculate the even block number */
+ block = (int) (addr >> this->erase_shift) & ~1;
+ /* Is it the odd plane? */
+ if (addr & this->writesize)
+ block++;
+ page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
+ blockpage = (block << 7) | page;
+
+ return blockpage;
+}
+
+/**
* onenand_check_bufferram - [GENERIC] Check BufferRAM information
* @param mtd MTD data structure
* @param addr address to check
@@ -585,7 +627,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
int blockpage, found = 0;
unsigned int i;
- blockpage = (int) (addr >> this->page_shift);
+ if (ONENAND_IS_2PLANE(this))
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
+ else
+ blockpage = (int) (addr >> this->page_shift);
/* Is there valid data? */
i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -625,7 +670,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
int blockpage;
unsigned int i;
- blockpage = (int) (addr >> this->page_shift);
+ if (ONENAND_IS_2PLANE(this))
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
+ else
+ blockpage = (int) (addr >> this->page_shift);
/* Invalidate another BufferRAM */
i = ONENAND_NEXT_BUFFERRAM(this);
@@ -717,36 +765,86 @@ static void onenand_release_device(struct mtd_info *mtd)
}
/**
- * onenand_read - [MTD Interface] Read data from flash
+ * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param buf destination address
+ * @param column oob offset to read from
+ * @param thislen oob length to read
+ */
+static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
+ int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int readcol = column;
+ int readend = column + thislen;
+ int lastgap = 0;
+ unsigned int i;
+ uint8_t *oob_buf = this->oob_buf;
+
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ if (readcol >= lastgap)
+ readcol += free->offset - lastgap;
+ if (readend >= lastgap)
+ readend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ int free_end = free->offset + free->length;
+ if (free->offset < readend && free_end > readcol) {
+ int st = max_t(int,free->offset,readcol);
+ int ed = min_t(int,free_end,readend);
+ int n = ed - st;
+ memcpy(buf, oob_buf + st, n);
+ buf += n;
+ } else if (column == 0)
+ break;
+ }
+ return 0;
+}
+
+/**
+ * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
* @param mtd MTD device structure
* @param from offset to read from
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put data
+ * @param ops: oob operation description structure
*
- * Read with ecc
-*/
-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+ * OneNAND read main and/or out-of-band data
+ */
+static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
struct mtd_ecc_stats stats;
- int read = 0, column;
- int thislen;
+ size_t len = ops->len;
+ size_t ooblen = ops->ooblen;
+ u_char *buf = ops->datbuf;
+ u_char *oobbuf = ops->oobbuf;
+ int read = 0, column, thislen;
+ int oobread = 0, oobcolumn, thisooblen, oobsize;
int ret = 0, boundary = 0;
+ int writesize = this->writesize;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ if (ops->mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
+
+ oobcolumn = from & (mtd->oobsize - 1);
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
- printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
- *retlen = 0;
+ printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
+ ops->retlen = 0;
+ ops->oobretlen = 0;
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_READING);
-
stats = mtd->ecc_stats;
/* Read-while-load method */
@@ -754,22 +852,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* Do first load to bufferRAM */
if (read < len) {
if (!onenand_check_bufferram(mtd, from)) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
ret = this->wait(mtd, FL_READING);
onenand_update_bufferram(mtd, from, !ret);
}
}
- thislen = min_t(int, mtd->writesize, len - read);
- column = from & (mtd->writesize - 1);
- if (column + thislen > mtd->writesize)
- thislen = mtd->writesize - column;
+ thislen = min_t(int, writesize, len - read);
+ column = from & (writesize - 1);
+ if (column + thislen > writesize)
+ thislen = writesize - column;
while (!ret) {
/* If there is more to load then start next load */
from += thislen;
if (read + thislen < len) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
/*
* Chip boundary handling in DDP
* Now we issued chip 1 read and pointed chip 1
@@ -785,6 +883,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/* While load is going, read from last bufferRAM */
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+
+ /* Read oob area if needed */
+ if (oobbuf) {
+ thisooblen = oobsize - oobcolumn;
+ thisooblen = min_t(int, thisooblen, ooblen - oobread);
+
+ if (ops->mode == MTD_OOB_AUTO)
+ onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
+ else
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
+ oobread += thisooblen;
+ oobbuf += thisooblen;
+ oobcolumn = 0;
+ }
+
/* See if we are done */
read += thislen;
if (read == len)
@@ -794,7 +907,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
- thislen = min_t(int, mtd->writesize, len - read);
+ thislen = min_t(int, writesize, len - read);
column = 0;
cond_resched();
/* Now wait for load */
@@ -802,15 +915,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
onenand_update_bufferram(mtd, from, !ret);
}
- /* Deselect and wake up anyone waiting on the device */
- onenand_release_device(mtd);
-
/*
* Return success, if no ECC failures, else -EBADMSG
* fs driver will take care of that, because
* retlen == desired len and result == -EBADMSG
*/
- *retlen = read;
+ ops->retlen = read;
+ ops->oobretlen = oobread;
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
@@ -822,69 +933,29 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/**
- * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param buf destination address
- * @param column oob offset to read from
- * @param thislen oob length to read
- */
-static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
- int thislen)
-{
- struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
- int readcol = column;
- int readend = column + thislen;
- int lastgap = 0;
- unsigned int i;
- uint8_t *oob_buf = this->oob_buf;
-
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- if (readcol >= lastgap)
- readcol += free->offset - lastgap;
- if (readend >= lastgap)
- readend += free->offset - lastgap;
- lastgap = free->offset + free->length;
- }
- this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < readend && free_end > readcol) {
- int st = max_t(int,free->offset,readcol);
- int ed = min_t(int,free_end,readend);
- int n = ed - st;
- memcpy(buf, oob_buf + st, n);
- buf += n;
- } else if (column == 0)
- break;
- }
- return 0;
-}
-
-/**
- * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
* @param mtd MTD device structure
* @param from offset to read from
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put data
- * @param mode operation mode
+ * @param ops: oob operation description structure
*
* OneNAND read out-of-band data from the spare area
*/
-static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
+static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column, oobsize;
+ size_t len = ops->ooblen;
+ mtd_oob_mode_t mode = ops->mode;
+ u_char *buf = ops->oobbuf;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ from += ops->ooboffs;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
/* Initialize return length value */
- *retlen = 0;
+ ops->oobretlen = 0;
if (mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -894,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
column = from & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
+ printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
return -EINVAL;
}
@@ -902,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
if (unlikely(from >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(from >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
+ printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_READING);
-
while (read < len) {
cond_resched();
@@ -928,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
if (ret) {
- printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
+ printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
break;
}
@@ -947,22 +1015,52 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
}
}
- /* Deselect and wake up anyone waiting on the device */
+ ops->oobretlen = read;
+ return ret;
+}
+
+/**
+ * onenand_read - [MTD Interface] Read data from flash
+ * @param mtd MTD device structure
+ * @param from offset to read from
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put data
+ *
+ * Read with ecc
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = buf,
+ .oobbuf = NULL,
+ };
+ int ret;
+
+ onenand_get_device(mtd, FL_READING);
+ ret = onenand_read_ops_nolock(mtd, from, &ops);
onenand_release_device(mtd);
- *retlen = read;
+ *retlen = ops.retlen;
return ret;
}
/**
- * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
+ * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
* @param mtd: MTD device structure
* @param from: offset to read from
* @param ops: oob operation description structure
+
+ * Read main and/or out-of-band
*/
static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
+ int ret;
+
switch (ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
@@ -972,8 +1070,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
default:
return -EINVAL;
}
- return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf, ops->mode);
+
+ onenand_get_device(mtd, FL_READING);
+ if (ops->datbuf)
+ ret = onenand_read_ops_nolock(mtd, from, ops);
+ else
+ ret = onenand_read_oob_nolock(mtd, from, ops);
+ onenand_release_device(mtd);
+
+ return ret;
}
/**
@@ -1079,7 +1184,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
/* Read more? */
if (read < len) {
/* Update Page size */
- from += mtd->writesize;
+ from += this->writesize;
column = 0;
}
}
@@ -1097,7 +1202,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
* @param mtd MTD device structure
* @param buf the databuffer to verify
* @param to offset to read from
- *
*/
static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
{
@@ -1125,7 +1229,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
* @param buf the databuffer to verify
* @param addr offset to read from
* @param len number of bytes to read and compare
- *
*/
static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
{
@@ -1135,12 +1238,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
int thislen, column;
while (len != 0) {
- thislen = min_t(int, mtd->writesize, len);
- column = addr & (mtd->writesize - 1);
- if (column + thislen > mtd->writesize)
- thislen = mtd->writesize - column;
+ thislen = min_t(int, this->writesize, len);
+ column = addr & (this->writesize - 1);
+ if (column + thislen > this->writesize)
+ thislen = this->writesize - column;
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
onenand_update_bufferram(mtd, addr, 0);
@@ -1171,50 +1274,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
/**
- * onenand_write - [MTD Interface] write buffer to FLASH
+ * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param oob_buf oob buffer
+ * @param buf source address
+ * @param column oob offset to write to
+ * @param thislen oob length to write
+ */
+static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
+ const u_char *buf, int column, int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int writecol = column;
+ int writeend = column + thislen;
+ int lastgap = 0;
+ unsigned int i;
+
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ if (writecol >= lastgap)
+ writecol += free->offset - lastgap;
+ if (writeend >= lastgap)
+ writeend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ int free_end = free->offset + free->length;
+ if (free->offset < writeend && free_end > writecol) {
+ int st = max_t(int,free->offset,writecol);
+ int ed = min_t(int,free_end,writeend);
+ int n = ed - st;
+ memcpy(oob_buf + st, buf, n);
+ buf += n;
+ } else if (column == 0)
+ break;
+ }
+ return 0;
+}
+
+/**
+ * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
* @param mtd MTD device structure
* @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
+ * @param ops oob operation description structure
*
- * Write with ECC
+ * Write main and/or oob with ECC
*/
-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
- int written = 0;
+ int written = 0, column, thislen, subpage;
+ int oobwritten = 0, oobcolumn, thisooblen, oobsize;
+ size_t len = ops->len;
+ size_t ooblen = ops->ooblen;
+ const u_char *buf = ops->datbuf;
+ const u_char *oob = ops->oobbuf;
+ u_char *oobbuf;
int ret = 0;
- int column, subpage;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
- *retlen = 0;
+ ops->retlen = 0;
+ ops->oobretlen = 0;
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
+ printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
- printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
+ printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
return -EINVAL;
}
- column = to & (mtd->writesize - 1);
+ if (ops->mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_WRITING);
+ oobcolumn = to & (mtd->oobsize - 1);
+
+ column = to & (mtd->writesize - 1);
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->writesize - column, len - written);
u_char *wbuf = (u_char *) buf;
+ thislen = min_t(int, mtd->writesize - column, len - written);
+ thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
+
cond_resched();
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
@@ -1228,7 +1382,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
}
this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
- this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+ if (oob) {
+ oobbuf = this->oob_buf;
+
+ /* We send data to spare ram with oobsize
+ * to prevent byte access */
+ memset(oobbuf, 0xff, mtd->oobsize);
+ if (ops->mode == MTD_OOB_AUTO)
+ onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
+ else
+ memcpy(oobbuf + oobcolumn, oob, thisooblen);
+
+ oobwritten += thisooblen;
+ oob += thisooblen;
+ oobcolumn = 0;
+ } else
+ oobbuf = (u_char *) ffchars;
+
+ this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
@@ -1236,16 +1408,20 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
+ if (ONENAND_IS_2PLANE(this)) {
+ ONENAND_SET_BUFFERRAM1(this);
+ onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
+ }
if (ret) {
- printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
+ printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
}
/* Only check verify write turn on */
ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
if (ret) {
- printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}
@@ -1262,54 +1438,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
- *retlen = written;
+ ops->retlen = written;
return ret;
}
-/**
- * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param oob_buf oob buffer
- * @param buf source address
- * @param column oob offset to write to
- * @param thislen oob length to write
- */
-static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
- const u_char *buf, int column, int thislen)
-{
- struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
- int writecol = column;
- int writeend = column + thislen;
- int lastgap = 0;
- unsigned int i;
-
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- if (writecol >= lastgap)
- writecol += free->offset - lastgap;
- if (writeend >= lastgap)
- writeend += free->offset - lastgap;
- lastgap = free->offset + free->length;
- }
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < writeend && free_end > writecol) {
- int st = max_t(int,free->offset,writecol);
- int ed = min_t(int,free_end,writeend);
- int n = ed - st;
- memcpy(oob_buf + st, buf, n);
- buf += n;
- } else if (column == 0)
- break;
- }
- return 0;
-}
/**
- * onenand_do_write_oob - [Internal] OneNAND write out-of-band
+ * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
@@ -1319,18 +1455,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
*
* OneNAND write out-of-band
*/
-static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, mtd_oob_mode_t mode)
+static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
int written = 0;
u_char *oobbuf;
+ size_t len = ops->ooblen;
+ const u_char *buf = ops->oobbuf;
+ mtd_oob_mode_t mode = ops->mode;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ to += ops->ooboffs;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
- *retlen = 0;
+ ops->oobretlen = 0;
if (mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -1340,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
column = to & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
+ printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
return -EINVAL;
}
/* For compatibility with NAND: Do not allow write past end of page */
if (unlikely(column + len > oobsize)) {
- printk(KERN_ERR "onenand_write_oob: "
+ printk(KERN_ERR "onenand_write_oob_nolock: "
"Attempt to write past end of page\n");
return -EINVAL;
}
@@ -1355,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
if (unlikely(to >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(to >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
+ printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_WRITING);
-
oobbuf = this->oob_buf;
/* Loop until all data write */
@@ -1384,16 +1522,20 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
+ if (ONENAND_IS_2PLANE(this)) {
+ ONENAND_SET_BUFFERRAM1(this);
+ onenand_update_bufferram(mtd, to + this->writesize, 0);
+ }
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
break;
}
ret = onenand_verify_oob(mtd, oobbuf, to);
if (ret) {
- printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
break;
}
@@ -1406,11 +1548,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
column = 0;
}
- /* Deselect and wake up anyone waiting on the device */
- onenand_release_device(mtd);
+ ops->oobretlen = written;
- *retlen = written;
+ return ret;
+}
+/**
+ * onenand_write - [MTD Interface] write buffer to FLASH
+ * @param mtd MTD device structure
+ * @param to offset to write to
+ * @param len number of bytes to write
+ * @param retlen pointer to variable to store the number of written bytes
+ * @param buf the data to write
+ *
+ * Write with ECC
+ */
+static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = (u_char *) buf,
+ .oobbuf = NULL,
+ };
+ int ret;
+
+ onenand_get_device(mtd, FL_WRITING);
+ ret = onenand_write_ops_nolock(mtd, to, &ops);
+ onenand_release_device(mtd);
+
+ *retlen = ops.retlen;
return ret;
}
@@ -1423,6 +1591,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
+ int ret;
+
switch (ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
@@ -1432,21 +1602,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
default:
return -EINVAL;
}
- return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf, ops->mode);
+
+ onenand_get_device(mtd, FL_WRITING);
+ if (ops->datbuf)
+ ret = onenand_write_ops_nolock(mtd, to, ops);
+ else
+ ret = onenand_write_oob_nolock(mtd, to, ops);
+ onenand_release_device(mtd);
+
+ return ret;
}
/**
- * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
* @param mtd MTD device structure
* @param ofs offset from device start
- * @param getchip 0, if the chip is already selected
* @param allowbbt 1, if its allowed to access the bbt area
*
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm = this->bbm;
@@ -1507,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
cond_resched();
/* Check if we have a bad block, we do not erase bad blocks */
- if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+ if (onenand_block_isbad_nolock(mtd, addr, 0)) {
printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
@@ -1535,13 +1711,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
return ret;
}
@@ -1571,11 +1748,16 @@ static void onenand_sync(struct mtd_info *mtd)
*/
static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
+ int ret;
+
/* Check for invalid offset */
if (ofs > mtd->size)
return -EINVAL;
- return onenand_block_checkbad(mtd, ofs, 1, 0);
+ onenand_get_device(mtd, FL_READING);
+ ret = onenand_block_isbad_nolock(mtd, ofs, 0);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1591,7 +1773,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm = this->bbm;
u_char buf[2] = {0, 0};
- size_t retlen;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooblen = 2,
+ .oobbuf = buf,
+ .ooboffs = 0,
+ };
int block;
/* Get block number */
@@ -1601,7 +1788,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit access */
ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
- return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE);
+ return onenand_write_oob_nolock(mtd, ofs, &ops);
}
/**
@@ -1624,7 +1811,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
- return this->block_markbad(mtd, ofs);
+ onenand_get_device(mtd, FL_WRITING);
+ ret = this->block_markbad(mtd, ofs);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1715,7 +1905,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
*/
static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
- return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+ int ret;
+
+ onenand_get_device(mtd, FL_LOCKING);
+ ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1728,7 +1923,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
*/
static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
- return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+ int ret;
+
+ onenand_get_device(mtd, FL_LOCKING);
+ ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1790,7 +1990,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
loff_t ofs = this->chipsize >> 1;
size_t len = mtd->erasesize;
- onenand_unlock(mtd, ofs, len);
+ onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
}
onenand_check_lock_status(this);
@@ -1798,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
return 0;
}
- onenand_unlock(mtd, 0x0, this->chipsize);
+ onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK);
return 0;
}
@@ -1823,13 +2023,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = buf,
+ .oobbuf = NULL,
+ };
int ret;
/* Enter OTP access mode */
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = mtd->read(mtd, from, len, retlen, buf);
+ ret = onenand_read_ops_nolock(mtd, from, &ops);
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1841,19 +2047,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
/**
* do_otp_write - [DEFAULT] Write OTP block area
* @param mtd MTD device structure
- * @param from The offset to write
+ * @param to The offset to write
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of write bytes
* @param buf the databuffer to put/get data
*
* Write OTP block area.
*/
-static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
unsigned char *pbuf = buf;
int ret;
+ struct mtd_oob_ops ops;
/* Force buffer page aligned */
if (len < mtd->writesize) {
@@ -1867,7 +2074,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = mtd->write(mtd, from, len, retlen, pbuf);
+ ops.len = len;
+ ops.ooblen = 0;
+ ops.datbuf = pbuf;
+ ops.oobbuf = NULL;
+ ret = onenand_write_ops_nolock(mtd, to, &ops);
+ *retlen = ops.retlen;
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1890,13 +2102,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooblen = len,
+ .oobbuf = buf,
+ .ooboffs = 0,
+ };
int ret;
/* Enter OTP access mode */
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE);
+ ret = onenand_write_oob_nolock(mtd, from, &ops);
+
+ *retlen = ops.oobretlen;
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1943,13 +2163,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
if (((mtd->writesize * otp_pages) - (from + len)) < 0)
return 0;
+ onenand_get_device(mtd, FL_OTPING);
while (len > 0 && otp_pages > 0) {
if (!action) { /* OTP Info functions */
struct otp_info *otpinfo;
len -= sizeof(struct otp_info);
- if (len <= 0)
- return -ENOSPC;
+ if (len <= 0) {
+ ret = -ENOSPC;
+ break;
+ }
otpinfo = (struct otp_info *) buf;
otpinfo->start = from;
@@ -1969,13 +2192,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
len -= size;
*retlen += size;
- if (ret < 0)
- return ret;
+ if (ret)
+ break;
}
otp_pages--;
}
+ onenand_release_device(mtd);
- return 0;
+ return ret;
}
/**
@@ -2107,6 +2331,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
*
* Check and set OneNAND features
* - lock scheme
+ * - two plane
*/
static void onenand_check_features(struct mtd_info *mtd)
{
@@ -2118,19 +2343,35 @@ static void onenand_check_features(struct mtd_info *mtd)
process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
/* Lock scheme */
- if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
+ switch (density) {
+ case ONENAND_DEVICE_DENSITY_4Gb:
+ this->options |= ONENAND_HAS_2PLANE;
+
+ case ONENAND_DEVICE_DENSITY_2Gb:
+ /* 2Gb DDP don't have 2 plane */
+ if (!ONENAND_IS_DDP(this))
+ this->options |= ONENAND_HAS_2PLANE;
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
+
+ case ONENAND_DEVICE_DENSITY_1Gb:
/* A-Die has all block unlock */
- if (process) {
- printk(KERN_DEBUG "Chip support all block unlock\n");
+ if (process)
this->options |= ONENAND_HAS_UNLOCK_ALL;
- }
- } else {
- /* Some OneNAND has continues lock scheme */
- if (!process) {
- printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
+ break;
+
+ default:
+ /* Some OneNAND has continuous lock scheme */
+ if (!process)
this->options |= ONENAND_HAS_CONT_LOCK;
- }
+ break;
}
+
+ if (this->options & ONENAND_HAS_CONT_LOCK)
+ printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
+ if (this->options & ONENAND_HAS_UNLOCK_ALL)
+ printk(KERN_DEBUG "Chip support all block unlock\n");
+ if (this->options & ONENAND_HAS_2PLANE)
+ printk(KERN_DEBUG "Chip has 2 plane\n");
}
/**
@@ -2154,7 +2395,7 @@ static void onenand_print_device_info(int device, int version)
(16 << density),
vcc ? "2.65/3.3" : "1.8",
device);
- printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+ printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
}
static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -2257,6 +2498,8 @@ static int onenand_probe(struct mtd_info *mtd)
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
+ /* It's real page size */
+ this->writesize = mtd->writesize;
/* REVIST: Multichip handling */
@@ -2265,6 +2508,17 @@ static int onenand_probe(struct mtd_info *mtd)
/* Check OneNAND features */
onenand_check_features(mtd);
+ /*
+ * We emulate the 4KiB page and 256KiB erase block size
+ * But oobsize is still 64 bytes.
+ * It is only valid if you turn on 2X program support,
+ * Otherwise it will be ignored by compiler.
+ */
+ if (ONENAND_IS_2PLANE(this)) {
+ mtd->writesize <<= 1;
+ mtd->erasesize <<= 1;
+ }
+
return 0;
}
diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c
new file mode 100644
index 00000000000..0d89ad5776f
--- /dev/null
+++ b/drivers/mtd/onenand/onenand_sim.c
@@ -0,0 +1,495 @@
+/*
+ * linux/drivers/mtd/onenand/onenand_sim.c
+ *
+ * The OneNAND simulator
+ *
+ * Copyright © 2005-2007 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
+
+#include <linux/io.h>
+
+#ifndef CONFIG_ONENAND_SIM_MANUFACTURER
+#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec
+#endif
+#ifndef CONFIG_ONENAND_SIM_DEVICE_ID
+#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04
+#endif
+#ifndef CONFIG_ONENAND_SIM_VERSION_ID
+#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e
+#endif
+
+static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER;
+static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID;
+static int version_id = CONFIG_ONENAND_SIM_VERSION_ID;
+
+struct onenand_flash {
+ void __iomem *base;
+ void __iomem *data;
+};
+
+#define ONENAND_CORE(flash) (flash->data)
+#define ONENAND_CORE_SPARE(flash, this, offset) \
+ ((flash->data) + (this->chipsize) + (offset >> 5))
+
+#define ONENAND_MAIN_AREA(this, offset) \
+ (this->base + ONENAND_DATARAM + offset)
+
+#define ONENAND_SPARE_AREA(this, offset) \
+ (this->base + ONENAND_SPARERAM + offset)
+
+#define ONENAND_GET_WP_STATUS(this) \
+ (readw(this->base + ONENAND_REG_WP_STATUS))
+
+#define ONENAND_SET_WP_STATUS(v, this) \
+ (writew(v, this->base + ONENAND_REG_WP_STATUS))
+
+/* It has all 0xff chars */
+#define MAX_ONENAND_PAGESIZE (2048 + 64)
+static unsigned char *ffchars;
+
+static struct mtd_partition os_partitions[] = {
+ {
+ .name = "OneNAND simulator partition",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+/*
+ * OneNAND simulator mtd
+ */
+struct onenand_info {
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct onenand_chip onenand;
+ struct onenand_flash flash;
+};
+
+static struct onenand_info *info;
+
+#define DPRINTK(format, args...) \
+do { \
+ printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \
+ __LINE__, ##args); \
+} while (0)
+
+/**
+ * onenand_lock_handle - Handle Lock scheme
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Send lock command to OneNAND device.
+ * The lock scheme is depends on chip type.
+ */
+static void onenand_lock_handle(struct onenand_chip *this, int cmd)
+{
+ int block_lock_scheme;
+ int status;
+
+ status = ONENAND_GET_WP_STATUS(this);
+ block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK);
+
+ switch (cmd) {
+ case ONENAND_CMD_UNLOCK:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_US, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this);
+ break;
+
+ case ONENAND_CMD_LOCK:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this);
+ break;
+
+ case ONENAND_CMD_LOCK_TIGHT:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_bootram_handle - Handle BootRAM area
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Emulate BootRAM area. It is possible to do basic operation using BootRAM.
+ */
+static void onenand_bootram_handle(struct onenand_chip *this, int cmd)
+{
+ switch (cmd) {
+ case ONENAND_CMD_READID:
+ writew(manuf_id, this->base);
+ writew(device_id, this->base + 2);
+ writew(version_id, this->base + 4);
+ break;
+
+ default:
+ /* REVIST: Handle other commands */
+ break;
+ }
+}
+
+/**
+ * onenand_update_interrupt - Set interrupt register
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Update interrupt register. The status is depends on command.
+ */
+static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
+{
+ int interrupt = ONENAND_INT_MASTER;
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ case ONENAND_CMD_READOOB:
+ interrupt |= ONENAND_INT_READ;
+ break;
+
+ case ONENAND_CMD_PROG:
+ case ONENAND_CMD_PROGOOB:
+ interrupt |= ONENAND_INT_WRITE;
+ break;
+
+ case ONENAND_CMD_ERASE:
+ interrupt |= ONENAND_INT_ERASE;
+ break;
+
+ case ONENAND_CMD_RESET:
+ interrupt |= ONENAND_INT_RESET;
+ break;
+
+ default:
+ break;
+ }
+
+ writew(interrupt, this->base + ONENAND_REG_INTERRUPT);
+}
+
+/**
+ * onenand_check_overwrite - Check over-write if happend
+ * @param dest The destination pointer
+ * @param src The source pointer
+ * @param count The length to be check
+ * @return 0 on same, otherwise 1
+ *
+ * Compare the source with destination
+ */
+static int onenand_check_overwrite(void *dest, void *src, size_t count)
+{
+ unsigned int *s = (unsigned int *) src;
+ unsigned int *d = (unsigned int *) dest;
+ int i;
+
+ count >>= 2;
+ for (i = 0; i < count; i++)
+ if ((*s++ ^ *d++) != 0)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * onenand_data_handle - Handle OneNAND Core and DataRAM
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ * @param dataram Which dataram used
+ * @param offset The offset to OneNAND Core
+ *
+ * Copy data from OneNAND Core to DataRAM (read)
+ * Copy data from DataRAM to OneNAND Core (write)
+ * Erase the OneNAND Core (erase)
+ */
+static void onenand_data_handle(struct onenand_chip *this, int cmd,
+ int dataram, unsigned int offset)
+{
+ struct mtd_info *mtd = &info->mtd;
+ struct onenand_flash *flash = this->priv;
+ int main_offset, spare_offset;
+ void __iomem *src;
+ void __iomem *dest;
+ unsigned int i;
+
+ if (dataram) {
+ main_offset = mtd->writesize;
+ spare_offset = mtd->oobsize;
+ } else {
+ main_offset = 0;
+ spare_offset = 0;
+ }
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ src = ONENAND_CORE(flash) + offset;
+ dest = ONENAND_MAIN_AREA(this, main_offset);
+ memcpy(dest, src, mtd->writesize);
+ /* Fall through */
+
+ case ONENAND_CMD_READOOB:
+ src = ONENAND_CORE_SPARE(flash, this, offset);
+ dest = ONENAND_SPARE_AREA(this, spare_offset);
+ memcpy(dest, src, mtd->oobsize);
+ break;
+
+ case ONENAND_CMD_PROG:
+ src = ONENAND_MAIN_AREA(this, main_offset);
+ dest = ONENAND_CORE(flash) + offset;
+ /* To handle partial write */
+ for (i = 0; i < (1 << mtd->subpage_sft); i++) {
+ int off = i * this->subpagesize;
+ if (!memcmp(src + off, ffchars, this->subpagesize))
+ continue;
+ if (memcmp(dest + off, ffchars, this->subpagesize) &&
+ onenand_check_overwrite(dest + off, src + off, this->subpagesize))
+ printk(KERN_ERR "over-write happend at 0x%08x\n", offset);
+ memcpy(dest + off, src + off, this->subpagesize);
+ }
+ /* Fall through */
+
+ case ONENAND_CMD_PROGOOB:
+ src = ONENAND_SPARE_AREA(this, spare_offset);
+ /* Check all data is 0xff chars */
+ if (!memcmp(src, ffchars, mtd->oobsize))
+ break;
+
+ dest = ONENAND_CORE_SPARE(flash, this, offset);
+ if (memcmp(dest, ffchars, mtd->oobsize) &&
+ onenand_check_overwrite(dest, src, mtd->oobsize))
+ printk(KERN_ERR "OOB: over-write happend at 0x%08x\n",
+ offset);
+ memcpy(dest, src, mtd->oobsize);
+ break;
+
+ case ONENAND_CMD_ERASE:
+ memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize);
+ memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff,
+ (mtd->erasesize >> 5));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_command_handle - Handle command
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Emulate OneNAND command.
+ */
+static void onenand_command_handle(struct onenand_chip *this, int cmd)
+{
+ unsigned long offset = 0;
+ int block = -1, page = -1, bufferram = -1;
+ int dataram = 0;
+
+ switch (cmd) {
+ case ONENAND_CMD_UNLOCK:
+ case ONENAND_CMD_LOCK:
+ case ONENAND_CMD_LOCK_TIGHT:
+ case ONENAND_CMD_UNLOCK_ALL:
+ onenand_lock_handle(this, cmd);
+ break;
+
+ case ONENAND_CMD_BUFFERRAM:
+ /* Do nothing */
+ return;
+
+ default:
+ block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1);
+ if (block & (1 << ONENAND_DDP_SHIFT)) {
+ block &= ~(1 << ONENAND_DDP_SHIFT);
+ /* The half of chip block */
+ block += this->chipsize >> (this->erase_shift + 1);
+ }
+ if (cmd == ONENAND_CMD_ERASE)
+ break;
+
+ page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8);
+ page = (page >> ONENAND_FPA_SHIFT);
+ bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER);
+ bufferram >>= ONENAND_BSA_SHIFT;
+ bufferram &= ONENAND_BSA_DATARAM1;
+ dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0;
+ break;
+ }
+
+ if (block != -1)
+ offset += block << this->erase_shift;
+
+ if (page != -1)
+ offset += page << this->page_shift;
+
+ onenand_data_handle(this, cmd, dataram, offset);
+
+ onenand_update_interrupt(this, cmd);
+}
+
+/**
+ * onenand_writew - [OneNAND Interface] Emulate write operation
+ * @param value value to write
+ * @param addr address to write
+ *
+ * Write OneNAND register with value
+ */
+static void onenand_writew(unsigned short value, void __iomem * addr)
+{
+ struct onenand_chip *this = info->mtd.priv;
+
+ /* BootRAM handling */
+ if (addr < this->base + ONENAND_DATARAM) {
+ onenand_bootram_handle(this, value);
+ return;
+ }
+ /* Command handling */
+ if (addr == this->base + ONENAND_REG_COMMAND)
+ onenand_command_handle(this, value);
+
+ writew(value, addr);
+}
+
+/**
+ * flash_init - Initialize OneNAND simulator
+ * @param flash OneNAND simulaotr data strucutres
+ *
+ * Initialize OneNAND simulator.
+ */
+static int __init flash_init(struct onenand_flash *flash)
+{
+ int density, size;
+ int buffer_size;
+
+ flash->base = kzalloc(131072, GFP_KERNEL);
+ if (!flash->base) {
+ printk(KERN_ERR "Unable to allocate base address.\n");
+ return -ENOMEM;
+ }
+
+ density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ size = ((16 << 20) << density);
+
+ ONENAND_CORE(flash) = vmalloc(size + (size >> 5));
+ if (!ONENAND_CORE(flash)) {
+ printk(KERN_ERR "Unable to allocate nand core address.\n");
+ kfree(flash->base);
+ return -ENOMEM;
+ }
+
+ memset(ONENAND_CORE(flash), 0xff, size + (size >> 5));
+
+ /* Setup registers */
+ writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID);
+ writew(device_id, flash->base + ONENAND_REG_DEVICE_ID);
+ writew(version_id, flash->base + ONENAND_REG_VERSION_ID);
+
+ if (density < 2)
+ buffer_size = 0x0400; /* 1KiB page */
+ else
+ buffer_size = 0x0800; /* 2KiB page */
+ writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE);
+
+ return 0;
+}
+
+/**
+ * flash_exit - Clean up OneNAND simulator
+ * @param flash OneNAND simulaotr data strucutres
+ *
+ * Clean up OneNAND simulator.
+ */
+static void flash_exit(struct onenand_flash *flash)
+{
+ vfree(ONENAND_CORE(flash));
+ kfree(flash->base);
+ kfree(flash);
+}
+
+static int __init onenand_sim_init(void)
+{
+ /* Allocate all 0xff chars pointer */
+ ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL);
+ if (!ffchars) {
+ printk(KERN_ERR "Unable to allocate ff chars.\n");
+ return -ENOMEM;
+ }
+ memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE);
+
+ /* Allocate OneNAND simulator mtd pointer */
+ info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "Unable to allocate core structures.\n");
+ kfree(ffchars);
+ return -ENOMEM;
+ }
+
+ /* Override write_word function */
+ info->onenand.write_word = onenand_writew;
+
+ if (flash_init(&info->flash)) {
+ printk(KERN_ERR "Unable to allocat flash.\n");
+ kfree(ffchars);
+ kfree(info);
+ return -ENOMEM;
+ }
+
+ info->parts = os_partitions;
+
+ info->onenand.base = info->flash.base;
+ info->onenand.priv = &info->flash;
+
+ info->mtd.name = "OneNAND simulator";
+ info->mtd.priv = &info->onenand;
+ info->mtd.owner = THIS_MODULE;
+
+ if (onenand_scan(&info->mtd, 1)) {
+ flash_exit(&info->flash);
+ kfree(ffchars);
+ kfree(info);
+ return -ENXIO;
+ }
+
+ add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions));
+
+ return 0;
+}
+
+static void __exit onenand_sim_exit(void)
+{
+ struct onenand_chip *this = info->mtd.priv;
+ struct onenand_flash *flash = this->priv;
+
+ onenand_release(&info->mtd);
+ flash_exit(flash);
+ kfree(ffchars);
+ kfree(info);
+}
+
+module_init(onenand_sim_init);
+module_exit(onenand_sim_exit);
+
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("The OneNAND flash simulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 006c03aacb5..823fba4e6d2 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -779,10 +779,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
else {
if (!mtd->erasesize) {
printk(KERN_WARNING PREFIX "please provide block_size");
- kfree(part);
- return;
- }
- else
+ goto out;
+ } else
part->block_size = mtd->erasesize;
}
@@ -804,7 +802,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (!add_mtd_blktrans_dev((void*)part))
return;
}
-
+out:
kfree(part);
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 1cb22bfae75..023653977a1 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
}
ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!ubi) {
err = -ENOMEM;
goto out_mtd;
@@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err)
goto out_free;
+ mutex_init(&ubi->buf_mutex);
+ ubi->peb_buf1 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf1)
+ goto out_free;
+
+ ubi->peb_buf2 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf2)
+ goto out_free;
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+ mutex_init(&ubi->dbg_buf_mutex);
+ ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
+ if (!ubi->dbg_peb_buf)
+ goto out_free;
+#endif
+
err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
@@ -630,6 +646,11 @@ out_detach:
ubi_wl_close(ubi);
vfree(ubi->vtbl);
out_free:
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
kfree(ubi);
out_mtd:
put_mtd_device(mtd);
@@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi)
ubi_wl_close(ubi);
vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL;
ubi_devices_cnt -= 1;
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 310341e5cd4..56956ec2845 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
- ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ec_hdr, UBI_EC_HDR_SIZE, 1);
}
/**
@@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
dbg_msg("the 1st 16 characters of the name: %s", nm);
}
-#define BYTES_PER_LINE 32
-
-/**
- * ubi_dbg_hexdump - dump a buffer.
- * @ptr: the buffer to dump
- * @size: buffer size which must be multiple of 4 bytes
- */
-void ubi_dbg_hexdump(const void *ptr, int size)
-{
- int i, k = 0, rows, columns;
- const uint8_t *p = ptr;
-
- size = ALIGN(size, 4);
- rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
- for (i = 0; i < rows; i++) {
- int j;
-
- cond_resched();
- columns = min(size - k, BYTES_PER_LINE) / 4;
- if (columns == 0)
- break;
- printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE);
- for (j = 0; j < columns; j++) {
- int n, N;
-
- N = size - k > 4 ? 4 : size - k;
- for (n = 0; n < N; n++)
- printk("%02x", p[k++]);
- printk(" ");
- }
- printk("\n");
- }
-}
-
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ff8f39548cd..467722eb618 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_hexdump(const void *buf, int size);
#else
@@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
-#define ubi_dbg_hexdump(buf, size) ({})
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c5e29eaf11..1297732f4db 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -46,6 +46,9 @@
#include <linux/err.h>
#include "ubi.h"
+/* Number of physical eraseblocks reserved for atomic LEB change operation */
+#define EBA_RESERVED_PEBS 1
+
/**
* struct ltree_entry - an entry in the lock tree.
* @rb: links RB-tree nodes
@@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
{
struct ltree_entry *le, *le1, *le_free;
- le = kmem_cache_alloc(ltree_slab, GFP_KERNEL);
+ le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
if (!le)
return ERR_PTR(-ENOMEM);
@@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
retry:
if (check) {
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
err = -ENOMEM;
goto out_unlock;
@@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
struct ubi_volume *vol = ubi->volumes[idx];
struct ubi_vid_hdr *vid_hdr;
- unsigned char *new_buf;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
return -ENOMEM;
}
+ mutex_lock(&ubi->buf_mutex);
+
retry:
new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
if (new_pnum < 0) {
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
return new_pnum;
}
@@ -524,31 +529,22 @@ retry:
goto write_error;
data_size = offset + len;
- new_buf = vmalloc(data_size);
- if (!new_buf) {
- err = -ENOMEM;
- goto out_put;
- }
- memset(new_buf + offset, 0xFF, len);
+ memset(ubi->peb_buf1 + offset, 0xFF, len);
/* Read everything before the area where the write failure happened */
if (offset > 0) {
- err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
- if (err && err != UBI_IO_BITFLIPS) {
- vfree(new_buf);
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+ if (err && err != UBI_IO_BITFLIPS)
goto out_put;
- }
}
- memcpy(new_buf + offset, buf, len);
+ memcpy(ubi->peb_buf1 + offset, buf, len);
- err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
- if (err) {
- vfree(new_buf);
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+ if (err)
goto write_error;
- }
- vfree(new_buf);
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
@@ -558,6 +554,7 @@ retry:
return 0;
out_put:
+ mutex_unlock(&ubi->buf_mutex);
ubi_wl_put_peb(ubi, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -570,6 +567,7 @@ write_error:
ubi_warn("failed to write to PEB %d", new_pnum);
ubi_wl_put_peb(ubi, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) {
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
}
@@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
* The logical eraseblock is not mapped. We have to get a free physical
* eraseblock and write the volume identifier header there first.
*/
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
leb_write_unlock(ubi, vol_id, lnum);
return -ENOMEM;
@@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
else
ubi_assert(len % ubi->min_io_size == 0);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -832,6 +830,9 @@ write_error:
* data, which has to be aligned. This function guarantees that in case of an
* unclean reboot the old contents is preserved. Returns zero in case of
* success and a negative error code in case of failure.
+ *
+ * UBI reserves one LEB for the "atomic LEB change" operation, so only one
+ * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
*/
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
const void *buf, int len, int dtype)
@@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
if (ubi->ro_mode)
return -EROFS;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
+ mutex_lock(&ubi->alc_mutex);
err = leb_write_lock(ubi, vol_id, lnum);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
- }
+ if (err)
+ goto out_mutex;
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_be32(vol_id);
@@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
if (pnum < 0) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return pnum;
+ err = pnum;
+ goto out_leb_unlock;
}
dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
@@ -893,17 +892,18 @@ retry:
if (vol->eba_tbl[lnum] >= 0) {
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return err;
- }
+ if (err)
+ goto out_leb_unlock;
}
vol->eba_tbl[lnum] = pnum;
+
+out_leb_unlock:
leb_write_unlock(ubi, vol_id, lnum);
+out_mutex:
+ mutex_unlock(&ubi->alc_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
- return 0;
+ return err;
write_error:
if (err != -EIO || !ubi->bad_allowed) {
@@ -913,17 +913,13 @@ write_error:
* mode just in case.
*/
ubi_ro_mode(ubi);
- leb_write_unlock(ubi, vol_id, lnum);
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
+ goto out_leb_unlock;
}
err = ubi_wl_put_peb(ubi, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
- leb_write_unlock(ubi, vol_id, lnum);
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
+ goto out_leb_unlock;
}
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
@@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
struct ubi_volume *vol;
uint32_t crc;
- void *buf, *buf1 = NULL;
vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = be32_to_cpu(vid_hdr->lnum);
@@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
data_size = aldata_size =
ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
- buf = vmalloc(aldata_size);
- if (!buf)
- return -ENOMEM;
-
/*
* We do not want anybody to write to this logical eraseblock while we
* are moving it, so we lock it.
*/
err = leb_write_lock(ubi, vol_id, lnum);
- if (err) {
- vfree(buf);
+ if (err)
return err;
- }
+
+ mutex_lock(&ubi->buf_mutex);
/*
* But the logical eraseblock might have been put by this time.
@@ -1023,7 +1014,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
/* OK, now the LEB is locked and we can safely start moving it */
dbg_eba("read %d bytes of data", aldata_size);
- err = ubi_io_read_data(ubi, buf, from, 0, aldata_size);
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
if (err && err != UBI_IO_BITFLIPS) {
ubi_warn("error %d while reading data from PEB %d",
err, from);
@@ -1042,10 +1033,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
aldata_size = data_size =
- ubi_calc_data_len(ubi, buf, data_size);
+ ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
cond_resched();
- crc = crc32(UBI_CRC32_INIT, buf, data_size);
+ crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
cond_resched();
/*
@@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
}
if (data_size > 0) {
- err = ubi_io_write_data(ubi, buf, to, 0, aldata_size);
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
if (err)
goto out_unlock;
+ cond_resched();
+
/*
* We've written the data and are going to read it back to make
* sure it was written correctly.
*/
- buf1 = vmalloc(aldata_size);
- if (!buf1) {
- err = -ENOMEM;
- goto out_unlock;
- }
-
- cond_resched();
- err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size);
+ err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
if (err) {
if (err != UBI_IO_BITFLIPS)
ubi_warn("cannot read data back from PEB %d",
@@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
cond_resched();
- if (memcmp(buf, buf1, aldata_size)) {
+ if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
ubi_warn("read data back from PEB %d - it is different",
to);
goto out_unlock;
@@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
ubi_assert(vol->eba_tbl[lnum] == from);
vol->eba_tbl[lnum] = to;
- leb_write_unlock(ubi, vol_id, lnum);
- vfree(buf);
- vfree(buf1);
-
- return 0;
-
out_unlock:
+ mutex_unlock(&ubi->buf_mutex);
leb_write_unlock(ubi, vol_id, lnum);
- vfree(buf);
- vfree(buf1);
return err;
}
@@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
dbg_eba("initialize EBA unit");
spin_lock_init(&ubi->ltree_lock);
+ mutex_init(&ubi->alc_mutex);
ubi->ltree = RB_ROOT;
if (ubi_devices_cnt == 0) {
@@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->rsvd_pebs += ubi->beb_rsvd_pebs;
}
+ if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
+ ubi_err("no enough physical eraseblocks (%d, need %d)",
+ ubi->avail_pebs, EBA_RESERVED_PEBS);
+ err = -ENOSPC;
+ goto out_free;
+ }
+ ubi->avail_pebs -= EBA_RESERVED_PEBS;
+ ubi->rsvd_pebs += EBA_RESERVED_PEBS;
+
dbg_eba("EBA unit is initialized");
return 0;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index b0d8f4cede9..7c304eec78b 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr);
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
- int offset, int len);
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len);
#else
#define paranoid_check_not_bad(ubi, pnum) 0
#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
@@ -202,8 +202,8 @@ retry:
* Note, in case of an error, it is possible that something was still written
* to the flash media, but may be some garbage.
*/
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len)
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len)
{
int err;
size_t written;
@@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei)
* zero in case of success and a negative error code in case of failure. If
* %-EIO is returned, the physical eraseblock most probably went bad.
*/
-static int do_sync_erase(const struct ubi_device *ubi, int pnum)
+static int do_sync_erase(struct ubi_device *ubi, int pnum)
{
int err, retries = 0;
struct erase_info ei;
@@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
* test, a positive number of erase operations done if the test was
* successfully passed, and other negative error codes in case of other errors.
*/
-static int torture_peb(const struct ubi_device *ubi, int pnum)
+static int torture_peb(struct ubi_device *ubi, int pnum)
{
- void *buf;
int err, i, patt_count;
- buf = vmalloc(ubi->peb_size);
- if (!buf)
- return -ENOMEM;
-
patt_count = ARRAY_SIZE(patterns);
ubi_assert(patt_count > 0);
+ mutex_lock(&ubi->buf_mutex);
for (i = 0; i < patt_count; i++) {
err = do_sync_erase(ubi, pnum);
if (err)
goto out;
/* Make sure the PEB contains only 0xFF bytes */
- err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- err = check_pattern(buf, 0xFF, ubi->peb_size);
+ err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
if (err == 0) {
ubi_err("erased PEB %d, but a non-0xFF byte found",
pnum);
@@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
}
/* Write a pattern and check it */
- memset(buf, patterns[i], ubi->peb_size);
- err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size);
+ memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
+ err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- memset(buf, ~patterns[i], ubi->peb_size);
- err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+ memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- err = check_pattern(buf, patterns[i], ubi->peb_size);
+ err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size);
if (err == 0) {
ubi_err("pattern %x checking failed for PEB %d",
patterns[i], pnum);
@@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
err = patt_count;
out:
- if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+ mutex_unlock(&ubi->buf_mutex);
+ if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
/*
* If a bit-flip or data integrity error was detected, the test
* has not passed because it happened on a freshly erased
* physical eraseblock which means something is wrong with it.
*/
+ ubi_err("read problems on freshly erased PEB %d, must be bad",
+ pnum);
err = -EIO;
- vfree(buf);
+ }
return err;
}
@@ -457,7 +456,7 @@ out:
* codes in case of other errors. Note, %-EIO means that the physical
* eraseblock is bad.
*/
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture)
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
{
int err, ret = 0;
@@ -614,7 +613,7 @@ bad:
* o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
* o a negative error code in case of failure.
*/
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose)
{
int err, read_err = 0;
@@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock most probably
* went bad.
*/
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr)
{
int err;
@@ -886,7 +885,7 @@ bad:
* header there);
* o a negative error code in case of failure.
*/
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose)
{
int err, read_err = 0;
@@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock probably went
* bad.
*/
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr)
{
int err;
@@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
uint32_t crc, hdr_crc;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
struct ubi_vid_hdr *vid_hdr;
void *p;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -1216,44 +1215,40 @@ exit:
* @offset of the physical eraseblock @pnum, %1 if not, and a negative error
* code if an error occurred.
*/
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
- int offset, int len)
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len)
{
size_t read;
int err;
- void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- buf = vmalloc(len);
- if (!buf)
- return -ENOMEM;
- memset(buf, 0, len);
-
- err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+ mutex_lock(&ubi->dbg_buf_mutex);
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
if (err && err != -EUCLEAN) {
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read);
goto error;
}
- err = check_pattern(buf, 0xFF, len);
+ err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not "
"contain all 0xFF bytes", pnum, offset, len);
goto fail;
}
+ mutex_unlock(&ubi->dbg_buf_mutex);
- vfree(buf);
return 0;
fail:
ubi_err("paranoid check failed for PEB %d", pnum);
dbg_msg("hex dump of the %d-%d region", offset, offset + len);
- ubi_dbg_hexdump(buf, len);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ubi->dbg_peb_buf, len, 1);
err = 1;
error:
ubi_dbg_dump_stack();
- vfree(buf);
+ mutex_unlock(&ubi->dbg_buf_mutex);
return err;
}
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 4a458e83e4e..03c774f4154 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
{
int err;
struct ubi_volume_desc *desc;
- struct ubi_device *ubi = ubi_devices[ubi_num];
+ struct ubi_device *ubi;
struct ubi_volume *vol;
dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
err = -ENODEV;
+ if (ubi_num < 0)
+ return ERR_PTR(err);
+
+ ubi = ubi_devices[ubi_num];
+
if (!try_module_get(THIS_MODULE))
return ERR_PTR(err);
- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi)
+ if (ubi_num >= UBI_MAX_DEVICES || !ubi)
goto out_put;
err = -EINVAL;
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 94ee5493441..c7b0afc9d28 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -45,8 +45,7 @@
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_si(const struct ubi_device *ubi,
- struct ubi_scan_info *si);
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
#else
#define paranoid_check_si(ubi, si) 0
#endif
@@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* o bit 2 is cleared: the older LEB is not corrupted;
* o bit 2 is set: the older LEB is corrupted.
*/
-static int compare_lebs(const struct ubi_device *ubi,
- const struct ubi_scan_leb *seb, int pnum,
- const struct ubi_vid_hdr *vid_hdr)
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+ int pnum, const struct ubi_vid_hdr *vid_hdr)
{
void *buf;
int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc;
- struct ubi_vid_hdr *vidh = NULL;
+ struct ubi_vid_hdr *vh = NULL;
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) {
@@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi,
} else {
pnum = seb->pnum;
- vidh = ubi_zalloc_vid_hdr(ubi);
- if (!vidh)
+ vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vh)
return -ENOMEM;
- err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+ err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) {
if (err == UBI_IO_BITFLIPS)
bitflips = 1;
@@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi,
}
}
- if (!vidh->copy_flag) {
+ if (!vh->copy_flag) {
/* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset",
pnum);
@@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi,
goto out_free_vidh;
}
- vid_hdr = vidh;
+ vid_hdr = vh;
}
/* Read the data of the copy and check the CRC */
@@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi,
}
vfree(buf);
- ubi_free_vid_hdr(ubi, vidh);
+ ubi_free_vid_hdr(ubi, vh);
if (second_is_newer)
dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
@@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
out_free_buf:
vfree(buf);
out_free_vidh:
- ubi_free_vid_hdr(ubi, vidh);
+ ubi_free_vid_hdr(ubi, vh);
ubi_assert(err < 0);
return err;
}
@@ -413,7 +411,7 @@ out_free_vidh:
* to be picked, while the older one has to be dropped. This function returns
* zero in case of success and a negative error code in case of failure.
*/
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips)
{
@@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* function returns zero in case of success and a negative error code in case
* of failure.
*/
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
- const struct ubi_scan_info *si, int pnum, int ec)
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec)
{
int err;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
- if (!ec_hdr)
- return -ENOMEM;
-
if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
/*
* Erase counter overflow. Upgrade UBI and use 64-bit
@@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL;
}
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ if (!ec_hdr)
+ return -ENOMEM;
+
ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0);
@@ -712,7 +710,7 @@ out_free:
* This function returns scanning physical eraseblock information in case of
* success and an error code in case of failure.
*/
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si)
{
int err = 0, i;
@@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
if (!ech)
goto out_si;
- vidh = ubi_zalloc_vid_hdr(ubi);
+ vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
goto out_ech;
@@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
* This function returns zero if the scanning information is all right, %1 if
* not and a negative error code if an error occurred.
*/
-static int paranoid_check_si(const struct ubi_device *ubi,
- struct ubi_scan_info *si)
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
{
int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2;
@@ -1314,11 +1311,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
* Make sure that all the physical eraseblocks are in one of the lists
* or trees.
*/
- buf = kmalloc(ubi->peb_count, GFP_KERNEL);
+ buf = kzalloc(ubi->peb_count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum);
if (err < 0) {
@@ -1326,28 +1322,28 @@ static int paranoid_check_si(const struct ubi_device *ubi,
return err;
}
else if (err)
- buf[pnum] = 0;
+ buf[pnum] = 1;
}
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->free, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->corr, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->erase, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->alien, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
err = 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++)
- if (buf[pnum]) {
+ if (!buf[pnum]) {
ubi_err("PEB %d is not referred", pnum);
err = 1;
}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 140e82e2653..46d444af471 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,7 +147,7 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list);
}
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips);
struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
@@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
int lnum);
void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si);
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
- const struct ubi_scan_info *si, int pnum, int ec);
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec);
struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
void ubi_scan_destroy_si(struct ubi_scan_info *si);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 5959f91be24..5e941a63303 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -221,14 +221,15 @@ struct ubi_wl_entry;
* @vtbl_slots: how many slots are available in the volume table
* @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy
+ * @vtbl_mutex: protects on-flash volume table
*
* @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value
*
- * global_sqnum: global sequence number
+ * @global_sqnum: global sequence number
* @ltree_lock: protects the lock tree and @global_sqnum
* @ltree: the lock tree
- * @vtbl_mutex: protects on-flash volume table
+ * @alc_mutex: serializes "atomic LEB change" operations
*
* @used: RB-tree of used physical eraseblocks
* @free: RB-tree of free physical eraseblocks
@@ -274,6 +275,12 @@ struct ubi_wl_entry;
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
* not
* @mtd: MTD device descriptor
+ *
+ * @peb_buf1: a buffer of PEB size used for different purposes
+ * @peb_buf2: another buffer of PEB size used for different purposes
+ * @buf_mutex: proptects @peb_buf1 and @peb_buf2
+ * @dbg_peb_buf: buffer of PEB size used for debugging
+ * @dbg_buf_mutex: proptects @dbg_peb_buf
*/
struct ubi_device {
struct cdev cdev;
@@ -302,6 +309,7 @@ struct ubi_device {
unsigned long long global_sqnum;
spinlock_t ltree_lock;
struct rb_root ltree;
+ struct mutex alc_mutex;
/* Wear-leveling unit's stuff */
struct rb_root used;
@@ -343,6 +351,14 @@ struct ubi_device {
int vid_hdr_shift;
int bad_allowed;
struct mtd_info *mtd;
+
+ void *peb_buf1;
+ void *peb_buf2;
+ struct mutex buf_mutex;
+#ifdef CONFIG_MTD_UBI_DEBUG
+ void *dbg_peb_buf;
+ struct mutex dbg_buf_mutex;
+#endif
};
extern struct file_operations ubi_cdev_operations;
@@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi);
/* io.c */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len);
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len);
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len);
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose);
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr);
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose);
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr);
/*
@@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object
+ * @gfp_flags: GFP flags to allocate with
*
* This function returns a pointer to the newly allocated and zero-filled
* volume identifier header object in case of success and %NULL in case of
* failure.
*/
-static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi)
+static inline struct ubi_vid_hdr *
+ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
{
void *vid_hdr;
- vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL);
+ vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
if (!vid_hdr)
return NULL;
@@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
* the beginning of the logical eraseblock, not to the beginning of the
* physical eraseblock.
*/
-static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf,
+static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
int pnum, int offset, int len)
{
ubi_assert(offset >= 0);
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index ea0d5c825ab..88629a320c2 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
-static struct device_attribute vol_reserved_ebs =
+static struct device_attribute attr_vol_reserved_ebs =
__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_type =
+static struct device_attribute attr_vol_type =
__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_name =
+static struct device_attribute attr_vol_name =
__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_corrupted =
+static struct device_attribute attr_vol_corrupted =
__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_alignment =
+static struct device_attribute attr_vol_alignment =
__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_usable_eb_size =
+static struct device_attribute attr_vol_usable_eb_size =
__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_data_bytes =
+static struct device_attribute attr_vol_data_bytes =
__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_upd_marker =
+static struct device_attribute attr_vol_upd_marker =
__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
/*
@@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev,
spin_unlock(&vol->ubi->volumes_lock);
return -ENODEV;
}
- if (attr == &vol_reserved_ebs)
+ if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs);
- else if (attr == &vol_type) {
+ else if (attr == &attr_vol_type) {
const char *tp;
- tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static";
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ tp = "dynamic";
+ else
+ tp = "static";
ret = sprintf(buf, "%s\n", tp);
- } else if (attr == &vol_name)
+ } else if (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name);
- else if (attr == &vol_corrupted)
+ else if (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted);
- else if (attr == &vol_alignment)
+ else if (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment);
- else if (attr == &vol_usable_eb_size) {
+ else if (attr == &attr_vol_usable_eb_size) {
ret = sprintf(buf, "%d\n", vol->usable_leb_size);
- } else if (attr == &vol_data_bytes)
+ } else if (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes);
- else if (attr == &vol_upd_marker)
+ else if (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker);
else
BUG();
@@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
- err = device_create_file(&vol->dev, &vol_reserved_ebs);
+ err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_type);
+ err = device_create_file(&vol->dev, &attr_vol_type);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_name);
+ err = device_create_file(&vol->dev, &attr_vol_name);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_corrupted);
+ err = device_create_file(&vol->dev, &attr_vol_corrupted);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_alignment);
+ err = device_create_file(&vol->dev, &attr_vol_alignment);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_usable_eb_size);
+ err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_data_bytes);
+ err = device_create_file(&vol->dev, &attr_vol_data_bytes);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_upd_marker);
+ err = device_create_file(&vol->dev, &attr_vol_upd_marker);
if (err)
return err;
return 0;
@@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
*/
static void volume_sysfs_close(struct ubi_volume *vol)
{
- device_remove_file(&vol->dev, &vol_upd_marker);
- device_remove_file(&vol->dev, &vol_data_bytes);
- device_remove_file(&vol->dev, &vol_usable_eb_size);
- device_remove_file(&vol->dev, &vol_alignment);
- device_remove_file(&vol->dev, &vol_corrupted);
- device_remove_file(&vol->dev, &vol_name);
- device_remove_file(&vol->dev, &vol_type);
- device_remove_file(&vol->dev, &vol_reserved_ebs);
+ device_remove_file(&vol->dev, &attr_vol_upd_marker);
+ device_remove_file(&vol->dev, &attr_vol_data_bytes);
+ device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
+ device_remove_file(&vol->dev, &attr_vol_alignment);
+ device_remove_file(&vol->dev, &attr_vol_corrupted);
+ device_remove_file(&vol->dev, &attr_vol_name);
+ device_remove_file(&vol->dev, &attr_vol_type);
+ device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
device_unregister(&vol->dev);
}
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index bc5df50813d..25b3bd61c7e 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -254,7 +254,7 @@ bad:
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
int copy, void *vtbl)
{
int err, tries = 0;
@@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
ubi_msg("create volume table (copy #%d)", copy + 1);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vid_hdr)
return -ENOMEM;
@@ -339,7 +339,7 @@ out_free:
* not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure.
*/
-static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si,
struct ubi_scan_volume *sv)
{
@@ -453,7 +453,7 @@ out_free:
* This function returns volume table contents in case of success and a
* negative error code in case of failure.
*/
-static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si)
{
int i;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index a5a9b8d8730..a4f1bf33164 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -208,7 +208,7 @@ struct ubi_work {
};
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec);
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root);
#else
@@ -220,17 +220,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
static struct kmem_cache *wl_entries_slab;
/**
- * tree_empty - a helper function to check if an RB-tree is empty.
- * @root: the root of the tree
- *
- * This function returns non-zero if the RB-tree is empty and zero if not.
- */
-static inline int tree_empty(struct rb_root *root)
-{
- return root->rb_node == NULL;
-}
-
-/**
* wl_tree_add - add a wear-leveling entry to a WL RB-tree.
* @e: the wear-leveling entry to add
* @root: the root of the tree
@@ -266,45 +255,6 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
rb_insert_color(&e->rb, root);
}
-
-/*
- * Helper functions to add and delete wear-leveling entries from different
- * trees.
- */
-
-static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->free);
-}
-static inline void used_tree_add(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->used);
-}
-static inline void scrub_tree_add(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->scrub);
-}
-static inline void free_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->free);
- rb_erase(&e->rb, &ubi->free);
-}
-static inline void used_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->used);
- rb_erase(&e->rb, &ubi->used);
-}
-static inline void scrub_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->scrub);
- rb_erase(&e->rb, &ubi->scrub);
-}
-
/**
* do_work - do one pending work.
* @ubi: UBI device description object
@@ -358,7 +308,7 @@ static int produce_free_peb(struct ubi_device *ubi)
int err;
spin_lock(&ubi->wl_lock);
- while (tree_empty(&ubi->free)) {
+ while (!ubi->free.rb_node) {
spin_unlock(&ubi->wl_lock);
dbg_wl("do one work synchronously");
@@ -508,13 +458,13 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
dtype == UBI_UNKNOWN);
- pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL);
+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
if (!pe)
return -ENOMEM;
retry:
spin_lock(&ubi->wl_lock);
- if (tree_empty(&ubi->free)) {
+ if (!ubi->free.rb_node) {
if (ubi->works_count == 0) {
ubi_assert(list_empty(&ubi->works));
ubi_err("no free eraseblocks");
@@ -585,7 +535,8 @@ retry:
* Move the physical eraseblock to the protection trees where it will
* be protected from being moved for some time.
*/
- free_tree_del(ubi, e);
+ paranoid_check_in_wl_tree(e, &ubi->free);
+ rb_erase(&e->rb, &ubi->free);
prot_tree_add(ubi, e, pe, protect);
dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect);
@@ -645,7 +596,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
if (err > 0)
return -EINVAL;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -704,7 +655,7 @@ static void check_protection_over(struct ubi_device *ubi)
*/
while (1) {
spin_lock(&ubi->wl_lock);
- if (tree_empty(&ubi->prot.aec)) {
+ if (!ubi->prot.aec.rb_node) {
spin_unlock(&ubi->wl_lock);
break;
}
@@ -721,7 +672,7 @@ static void check_protection_over(struct ubi_device *ubi)
pe->e->pnum, ubi->abs_ec, pe->abs_ec);
rb_erase(&pe->rb_aec, &ubi->prot.aec);
rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
- used_tree_add(ubi, pe->e);
+ wl_tree_add(pe->e, &ubi->used);
spin_unlock(&ubi->wl_lock);
kfree(pe);
@@ -768,7 +719,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
e->pnum, e->ec, torture);
- wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wl_wrk)
return -ENOMEM;
@@ -802,7 +753,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
if (cancel)
return 0;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -812,8 +763,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
* Only one WL worker at a time is supported at this implementation, so
* make sure a PEB is not being moved already.
*/
- if (ubi->move_to || tree_empty(&ubi->free) ||
- (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) {
+ if (ubi->move_to || !ubi->free.rb_node ||
+ (!ubi->used.rb_node && !ubi->scrub.rb_node)) {
/*
* Only one WL worker at a time is supported at this
* implementation, so if a LEB is already being moved, cancel.
@@ -828,14 +779,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
* triggered again.
*/
dbg_wl("cancel WL, a list is empty: free %d, used %d",
- tree_empty(&ubi->free), tree_empty(&ubi->used));
+ !ubi->free.rb_node, !ubi->used.rb_node);
ubi->wl_scheduled = 0;
spin_unlock(&ubi->wl_lock);
ubi_free_vid_hdr(ubi, vid_hdr);
return 0;
}
- if (tree_empty(&ubi->scrub)) {
+ if (!ubi->scrub.rb_node) {
/*
* Now pick the least worn-out used physical eraseblock and a
* highly worn-out free physical eraseblock. If the erase
@@ -852,17 +803,20 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi_free_vid_hdr(ubi, vid_hdr);
return 0;
}
- used_tree_del(ubi, e1);
+ paranoid_check_in_wl_tree(e1, &ubi->used);
+ rb_erase(&e1->rb, &ubi->used);
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
e1->pnum, e1->ec, e2->pnum, e2->ec);
} else {
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- scrub_tree_del(ubi, e1);
+ paranoid_check_in_wl_tree(e1, &ubi->scrub);
+ rb_erase(&e1->rb, &ubi->scrub);
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
}
- free_tree_del(ubi, e2);
+ paranoid_check_in_wl_tree(e2, &ubi->free);
+ rb_erase(&e2->rb, &ubi->free);
ubi_assert(!ubi->move_from && !ubi->move_to);
ubi_assert(!ubi->move_to_put && !ubi->move_from_put);
ubi->move_from = e1;
@@ -908,7 +862,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi_free_vid_hdr(ubi, vid_hdr);
spin_lock(&ubi->wl_lock);
if (!ubi->move_to_put)
- used_tree_add(ubi, e2);
+ wl_tree_add(e2, &ubi->used);
else
put = 1;
ubi->move_from = ubi->move_to = NULL;
@@ -953,7 +907,7 @@ error:
if (ubi->move_from_put)
put = 1;
else
- used_tree_add(ubi, e1);
+ wl_tree_add(e1, &ubi->used);
ubi->move_from = ubi->move_to = NULL;
ubi->move_from_put = ubi->move_to_put = 0;
spin_unlock(&ubi->wl_lock);
@@ -1005,8 +959,8 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
* If the ubi->scrub tree is not empty, scrubbing is needed, and the
* the WL worker has to be scheduled anyway.
*/
- if (tree_empty(&ubi->scrub)) {
- if (tree_empty(&ubi->used) || tree_empty(&ubi->free))
+ if (!ubi->scrub.rb_node) {
+ if (!ubi->used.rb_node || !ubi->free.rb_node)
/* No physical eraseblocks - no deal */
goto out_unlock;
@@ -1028,7 +982,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
ubi->wl_scheduled = 1;
spin_unlock(&ubi->wl_lock);
- wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wrk) {
err = -ENOMEM;
goto out_cancel;
@@ -1079,7 +1033,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
spin_lock(&ubi->wl_lock);
ubi->abs_ec += 1;
- free_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->free);
spin_unlock(&ubi->wl_lock);
/*
@@ -1093,6 +1047,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return err;
}
+ ubi_err("failed to erase PEB %d, error %d", pnum, err);
kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e);
@@ -1211,11 +1166,13 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
spin_unlock(&ubi->wl_lock);
return 0;
} else {
- if (in_wl_tree(e, &ubi->used))
- used_tree_del(ubi, e);
- else if (in_wl_tree(e, &ubi->scrub))
- scrub_tree_del(ubi, e);
- else
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else if (in_wl_tree(e, &ubi->scrub)) {
+ paranoid_check_in_wl_tree(e, &ubi->scrub);
+ rb_erase(&e->rb, &ubi->scrub);
+ } else
prot_tree_del(ubi, e->pnum);
}
spin_unlock(&ubi->wl_lock);
@@ -1223,7 +1180,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
err = schedule_erase(ubi, e, torture);
if (err) {
spin_lock(&ubi->wl_lock);
- used_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->used);
spin_unlock(&ubi->wl_lock);
}
@@ -1267,12 +1224,13 @@ retry:
goto retry;
}
- if (in_wl_tree(e, &ubi->used))
- used_tree_del(ubi, e);
- else
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else
prot_tree_del(ubi, pnum);
- scrub_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->scrub);
spin_unlock(&ubi->wl_lock);
/*
@@ -1488,7 +1446,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
e->pnum = seb->pnum;
e->ec = seb->ec;
ubi_assert(e->ec >= 0);
- free_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->free);
ubi->lookuptbl[e->pnum] = e;
}
@@ -1522,16 +1480,16 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (!seb->scrub) {
dbg_wl("add PEB %d EC %d to the used tree",
e->pnum, e->ec);
- used_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->used);
} else {
dbg_wl("add PEB %d EC %d to the scrub tree",
e->pnum, e->ec);
- scrub_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->scrub);
}
}
}
- if (WL_RESERVED_PEBS > ubi->avail_pebs) {
+ if (ubi->avail_pebs < WL_RESERVED_PEBS) {
ubi_err("no enough physical eraseblocks (%d, need %d)",
ubi->avail_pebs, WL_RESERVED_PEBS);
goto out_free;
@@ -1624,13 +1582,13 @@ void ubi_wl_close(struct ubi_device *ubi)
* is equivalent to @ec, %1 if not, and a negative error code if an error
* occurred.
*/
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
int err;
long long read_ec;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9c635a237a9..8f99a062661 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1780,6 +1780,15 @@ config SC92031
To compile this driver as a module, choose M here: the module
will be called sc92031. This is recommended.
+config CPMAC
+ tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+ depends on NET_ETHERNET && EXPERIMENTAL && AR7
+ select PHYLIB
+ select FIXED_PHY
+ select FIXED_MII_100_FDX
+ help
+ TI AR7 CPMAC Ethernet support
+
config NET_POCKET
bool "Pocket and portable adapters"
depends on PARPORT
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d2e0f35da42..22f78cbd126 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -159,6 +159,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_LAN_SAA9730) += saa9730.o
+obj-$(CONFIG_CPMAC) += cpmac.o
obj-$(CONFIG_DEPCA) += depca.o
obj-$(CONFIG_EWRK3) += ewrk3.o
obj-$(CONFIG_ATP) += atp.o
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index ebf1a3a88e1..b74dbeef805 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -1023,7 +1023,7 @@ static int lance_rx( struct net_device *dev )
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);
- printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ",
+ printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s "
"data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d\n",
dev->name, ((u_short *)data)[6],
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index b46c5d8a77b..185f98e3964 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -54,13 +54,16 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/phy.h>
+
+#include <asm/cpu.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/cpu.h>
+#include <au1000.h>
+#include <prom.h>
+
#include "au1000_eth.h"
#ifdef AU1000_ETH_DEBUG
@@ -96,11 +99,6 @@ static void mdio_write(struct net_device *, int, int, u16);
static void au1000_adjust_link(struct net_device *);
static void enable_mac(struct net_device *, int);
-// externs
-extern int get_ethernet_addr(char *ethernet_addr);
-extern void str2eaddr(unsigned char *ea, unsigned char *str);
-extern char * prom_getcmdline(void);
-
/*
* Theory of operation
*
@@ -619,7 +617,6 @@ static struct net_device * au1000_probe(int port_num)
struct au1000_private *aup = NULL;
struct net_device *dev = NULL;
db_dest_t *pDB, *pDBfree;
- char *pmac, *argptr;
char ethaddr[6];
int irq, i, err;
u32 base, macen;
@@ -677,21 +674,12 @@ static struct net_device * au1000_probe(int port_num)
au_macs[port_num] = aup;
if (port_num == 0) {
- /* Check the environment variables first */
- if (get_ethernet_addr(ethaddr) == 0)
+ if (prom_get_ethernet_addr(ethaddr) == 0)
memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
else {
- /* Check command line */
- argptr = prom_getcmdline();
- if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
- printk(KERN_INFO "%s: No MAC address found\n",
- dev->name);
+ printk(KERN_INFO "%s: No MAC address found\n",
+ dev->name);
/* Use the hard coded MAC addresses */
- else {
- str2eaddr(ethaddr, pmac + strlen("ethaddr="));
- memcpy(au1000_mac_addr, ethaddr,
- sizeof(au1000_mac_addr));
- }
}
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d68accea380..78ed633ceb8 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
REG_RD(bp, BNX2_HC_COMMAND);
}
- if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+ if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp);
- if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+ if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
work_done += bnx2_rx_int(bp, budget - work_done);
return work_done;
@@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
{
struct bnx2 *bp = container_of(napi, struct bnx2, napi);
int work_done = 0;
+ struct status_block *sblk = bp->status_blk;
while (1) {
work_done = bnx2_poll_work(bp, work_done, budget);
@@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
if (unlikely(work_done >= budget))
break;
+ /* bp->last_status_idx is used below to tell the hw how
+ * much work has been processed, so we must read it before
+ * checking for more work.
+ */
+ bp->last_status_idx = sblk->status_idx;
+ rmb();
if (likely(!bnx2_has_work(bp))) {
- bp->last_status_idx = bp->status_blk->status_idx;
- rmb();
-
netif_rx_complete(bp->dev, napi);
if (likely(bp->flags & USING_MSI_FLAG)) {
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
bp->last_status_idx);
- return 0;
+ break;
}
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 64bfec32e2a..db80f243dd3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -98,6 +98,7 @@ static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
static char *arp_validate = NULL;
+static int fail_over_mac = 0;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
@@ -131,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+module_param(fail_over_mac, int, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on.");
/*----------------------------- Global variables ----------------------------*/
@@ -1096,7 +1099,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (new_active) {
bond_set_slave_active_flags(new_active);
}
- bond_send_gratuitous_arp(bond);
+
+ /* when bonding does not set the slave MAC address, the bond MAC
+ * address is the one of the active slave.
+ */
+ if (new_active && bond->params.fail_over_mac)
+ memcpy(bond->dev->dev_addr, new_active->dev->dev_addr,
+ new_active->dev->addr_len);
+ if (bond->curr_active_slave &&
+ test_bit(__LINK_STATE_LINKWATCH_PENDING,
+ &bond->curr_active_slave->dev->state)) {
+ dprintk("delaying gratuitous arp on %s\n",
+ bond->curr_active_slave->dev->name);
+ bond->send_grat_arp = 1;
+ } else
+ bond_send_gratuitous_arp(bond);
}
}
@@ -1217,7 +1234,8 @@ static int bond_compute_features(struct bonding *bond)
struct slave *slave;
struct net_device *bond_dev = bond->dev;
unsigned long features = bond_dev->features;
- unsigned short max_hard_header_len = ETH_HLEN;
+ unsigned short max_hard_header_len = max((u16)ETH_HLEN,
+ bond_dev->hard_header_len);
int i;
features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
@@ -1238,6 +1256,23 @@ static int bond_compute_features(struct bonding *bond)
return 0;
}
+
+static void bond_setup_by_slave(struct net_device *bond_dev,
+ struct net_device *slave_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+
+ bond_dev->neigh_setup = slave_dev->neigh_setup;
+
+ bond_dev->type = slave_dev->type;
+ bond_dev->hard_header_len = slave_dev->hard_header_len;
+ bond_dev->addr_len = slave_dev->addr_len;
+
+ memcpy(bond_dev->broadcast, slave_dev->broadcast,
+ slave_dev->addr_len);
+ bond->setup_by_slave = 1;
+}
+
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@@ -1258,8 +1293,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* bond must be initialized by bond_open() before enslaving */
if (!(bond_dev->flags & IFF_UP)) {
- dprintk("Error, master_dev is not up\n");
- return -EPERM;
+ printk(KERN_WARNING DRV_NAME
+ " %s: master_dev is not up in bond_enslave\n",
+ bond_dev->name);
}
/* already enslaved */
@@ -1312,14 +1348,42 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_undo_flags;
}
+ /* set bonding device ether type by slave - bonding netdevices are
+ * created with ether_setup, so when the slave type is not ARPHRD_ETHER
+ * there is a need to override some of the type dependent attribs/funcs.
+ *
+ * bond ether type mutual exclusion - don't allow slaves of dissimilar
+ * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
+ */
+ if (bond->slave_cnt == 0) {
+ if (slave_dev->type != ARPHRD_ETHER)
+ bond_setup_by_slave(bond_dev, slave_dev);
+ } else if (bond_dev->type != slave_dev->type) {
+ printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different "
+ "from other slaves (%d), can not enslave it.\n",
+ slave_dev->name,
+ slave_dev->type, bond_dev->type);
+ res = -EINVAL;
+ goto err_undo_flags;
+ }
+
if (slave_dev->set_mac_address == NULL) {
- printk(KERN_ERR DRV_NAME
- ": %s: Error: The slave device you specified does "
- "not support setting the MAC address. "
- "Your kernel likely does not support slave "
- "devices.\n", bond_dev->name);
- res = -EOPNOTSUPP;
- goto err_undo_flags;
+ if (bond->slave_cnt == 0) {
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Warning: The first slave device "
+ "specified does not support setting the MAC "
+ "address. Enabling the fail_over_mac option.",
+ bond_dev->name);
+ bond->params.fail_over_mac = 1;
+ } else if (!bond->params.fail_over_mac) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Error: The slave device specified "
+ "does not support setting the MAC address, "
+ "but fail_over_mac is not enabled.\n"
+ , bond_dev->name);
+ res = -EOPNOTSUPP;
+ goto err_undo_flags;
+ }
}
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1340,16 +1404,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
- /*
- * Set slave to master's mac address. The application already
- * set the master's mac address to that of the first slave
- */
- memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
- addr.sa_family = slave_dev->type;
- res = dev_set_mac_address(slave_dev, &addr);
- if (res) {
- dprintk("Error %d calling set_mac_address\n", res);
- goto err_free;
+ if (!bond->params.fail_over_mac) {
+ /*
+ * Set slave to master's mac address. The application already
+ * set the master's mac address to that of the first slave
+ */
+ memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+ addr.sa_family = slave_dev->type;
+ res = dev_set_mac_address(slave_dev, &addr);
+ if (res) {
+ dprintk("Error %d calling set_mac_address\n", res);
+ goto err_free;
+ }
}
res = netdev_set_master(slave_dev, bond_dev);
@@ -1574,9 +1640,11 @@ err_close:
dev_close(slave_dev);
err_restore_mac:
- memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
err_free:
kfree(new_slave);
@@ -1749,10 +1817,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* close slave before restoring its mac address */
dev_close(slave_dev);
- /* restore original ("permanent") mac address */
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ /* restore original ("permanent") mac address */
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
@@ -1764,6 +1834,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
}
/*
+* Destroy a bonding device.
+* Must be under rtnl_lock when this function is called.
+*/
+void bond_destroy(struct bonding *bond)
+{
+ bond_deinit(bond->dev);
+ bond_destroy_sysfs_entry(bond);
+ unregister_netdevice(bond->dev);
+}
+
+/*
+* First release a slave and than destroy the bond if no more slaves iare left.
+* Must be under rtnl_lock when this function is called.
+*/
+int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+ int ret;
+
+ ret = bond_release(bond_dev, slave_dev);
+ if ((ret == 0) && (bond->slave_cnt == 0)) {
+ printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
+ bond_dev->name, bond_dev->name);
+ bond_destroy(bond);
+ }
+ return ret;
+}
+
+/*
* This function releases all slaves.
*/
static int bond_release_all(struct net_device *bond_dev)
@@ -1839,10 +1938,12 @@ static int bond_release_all(struct net_device *bond_dev)
/* close slave before restoring its mac address */
dev_close(slave_dev);
- /* restore original ("permanent") mac address*/
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ /* restore original ("permanent") mac address*/
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE);
@@ -2013,6 +2114,17 @@ void bond_mii_monitor(struct net_device *bond_dev)
* program could monitor the link itself if needed.
*/
+ if (bond->send_grat_arp) {
+ if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
+ &bond->curr_active_slave->dev->state))
+ dprintk("Needs to send gratuitous arp but not yet\n");
+ else {
+ dprintk("sending delayed gratuitous arp on on %s\n",
+ bond->curr_active_slave->dev->name);
+ bond_send_gratuitous_arp(bond);
+ bond->send_grat_arp = 0;
+ }
+ }
read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
@@ -2414,7 +2526,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
if (bond->master_ip) {
bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
- bond->master_ip, 0);
+ bond->master_ip, 0);
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
@@ -2951,9 +3063,15 @@ static void bond_info_show_master(struct seq_file *seq)
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
- seq_printf(seq, "Bonding Mode: %s\n",
+ seq_printf(seq, "Bonding Mode: %s",
bond_mode_name(bond->params.mode));
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
+ bond->params.fail_over_mac)
+ seq_printf(seq, " (fail_over_mac)");
+
+ seq_printf(seq, "\n");
+
if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) {
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
@@ -3248,6 +3366,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
* ... Or is it this?
*/
break;
+ case NETDEV_GOING_DOWN:
+ dprintk("slave %s is going down\n", slave_dev->name);
+ if (bond->setup_by_slave)
+ bond_release_and_destroy(bond_dev, slave_dev);
+ break;
case NETDEV_CHANGEMTU:
/*
* TODO: Should slaves be allowed to
@@ -3880,6 +4003,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
+ /*
+ * If fail_over_mac is enabled, do nothing and return success.
+ * Returning an error causes ifenslave to fail.
+ */
+ if (bond->params.fail_over_mac)
+ return 0;
+
if (!is_valid_ether_addr(sa->sa_data)) {
return -EADDRNOTAVAIL;
}
@@ -4217,6 +4347,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
bond->current_arp_slave = NULL;
bond->primary_slave = NULL;
bond->dev = bond_dev;
+ bond->send_grat_arp = 0;
+ bond->setup_by_slave = 0;
INIT_LIST_HEAD(&bond->vlan_list);
/* Initialize the device entry points */
@@ -4265,7 +4397,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
#endif
-
list_add_tail(&bond->bond_list, &bond_dev_list);
return 0;
@@ -4599,6 +4730,11 @@ static int bond_check_params(struct bond_params *params)
primary = NULL;
}
+ if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: fail_over_mac only affects "
+ "active-backup mode.\n");
+
/* fill params struct with the proper values */
params->mode = bond_mode;
params->xmit_policy = xmit_hashtype;
@@ -4610,6 +4746,7 @@ static int bond_check_params(struct bond_params *params)
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
+ params->fail_over_mac = fail_over_mac;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 6f49ca7e9b6..80c0c8c415e 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
- bond_deinit(bond->dev);
- bond_destroy_sysfs_entry(bond);
- unregister_netdevice(bond->dev);
+ bond_destroy(bond);
rtnl_unlock();
goto out;
}
@@ -260,17 +258,16 @@ static ssize_t bonding_store_slaves(struct device *d,
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int i, res, found, ret = count;
+ u32 original_mtu;
struct slave *slave;
struct net_device *dev = NULL;
struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
if (!(bond->dev->flags & IFF_UP)) {
- printk(KERN_ERR DRV_NAME
- ": %s: Unable to update slaves because interface is down.\n",
+ printk(KERN_WARNING DRV_NAME
+ ": %s: doing slave updates when interface is down.\n",
bond->dev->name);
- ret = -EPERM;
- goto out;
}
/* Note: We can't hold bond->lock here, as bond_create grabs it. */
@@ -327,6 +324,7 @@ static ssize_t bonding_store_slaves(struct device *d,
}
/* Set the slave's MTU to match the bond */
+ original_mtu = dev->mtu;
if (dev->mtu != bond->dev->mtu) {
if (dev->change_mtu) {
res = dev->change_mtu(dev,
@@ -341,6 +339,9 @@ static ssize_t bonding_store_slaves(struct device *d,
}
rtnl_lock();
res = bond_enslave(bond->dev, dev);
+ bond_for_each_slave(bond, slave, i)
+ if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
+ slave->original_mtu = original_mtu;
rtnl_unlock();
if (res) {
ret = res;
@@ -353,13 +354,17 @@ static ssize_t bonding_store_slaves(struct device *d,
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
dev = slave->dev;
+ original_mtu = slave->original_mtu;
break;
}
if (dev) {
printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
bond->dev->name, dev->name);
rtnl_lock();
- res = bond_release(bond->dev, dev);
+ if (bond->setup_by_slave)
+ res = bond_release_and_destroy(bond->dev, dev);
+ else
+ res = bond_release(bond->dev, dev);
rtnl_unlock();
if (res) {
ret = res;
@@ -367,9 +372,9 @@ static ssize_t bonding_store_slaves(struct device *d,
}
/* set the slave MTU to the default */
if (dev->change_mtu) {
- dev->change_mtu(dev, 1500);
+ dev->change_mtu(dev, original_mtu);
} else {
- dev->mtu = 1500;
+ dev->mtu = original_mtu;
}
}
else {
@@ -563,6 +568,54 @@ static ssize_t bonding_store_arp_validate(struct device *d,
static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
/*
+ * Show and store fail_over_mac. User only allowed to change the
+ * value when there are no slaves.
+ */
+static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+}
+
+static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int new_value;
+ int ret = count;
+ struct bonding *bond = to_bond(d);
+
+ if (bond->slave_cnt != 0) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Can't alter fail_over_mac with slaves in bond.\n",
+ bond->dev->name);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: no fail_over_mac value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if ((new_value == 0) || (new_value == 1)) {
+ bond->params.fail_over_mac = new_value;
+ printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
+ bond->dev->name, new_value);
+ } else {
+ printk(KERN_INFO DRV_NAME
+ ": %s: Ignoring invalid fail_over_mac value %d.\n",
+ bond->dev->name, new_value);
+ }
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
+
+/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
@@ -1383,6 +1436,7 @@ static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
+ &dev_attr_fail_over_mac.attr,
&dev_attr_arp_validate.attr,
&dev_attr_arp_interval.attr,
&dev_attr_arp_ip_target.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2a6af7d2372..a8bbd563265 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.1.3"
-#define DRV_RELDATE "June 13, 2007"
+#define DRV_VERSION "3.2.0"
+#define DRV_RELDATE "September 13, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -128,6 +128,7 @@ struct bond_params {
int arp_interval;
int arp_validate;
int use_carrier;
+ int fail_over_mac;
int updelay;
int downdelay;
int lacp_fast;
@@ -156,6 +157,7 @@ struct slave {
s8 link; /* one of BOND_LINK_XXXX */
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
+ u32 original_mtu;
u32 link_failure_count;
u16 speed;
u8 duplex;
@@ -185,6 +187,8 @@ struct bonding {
struct timer_list mii_timer;
struct timer_list arp_timer;
s8 kill_timers;
+ s8 send_grat_arp;
+ s8 setup_by_slave;
struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
@@ -292,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
+void bond_destroy(struct bonding *bond);
+int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
void bond_deinit(struct net_device *bond_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 563bf5f6fa2..7df31b5561c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4443,7 +4443,7 @@ static struct {
{REG_MAC_COLL_EXCESS},
{REG_MAC_COLL_LATE}
};
-#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int))
+#define CAS_REG_LEN ARRAY_SIZE(ethtool_register_table)
#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN)
static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
new file mode 100644
index 00000000000..ed53aaab4c0
--- /dev/null
+++ b/drivers/net/cpmac.c
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/gpio.h>
+
+MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
+MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
+MODULE_LICENSE("GPL");
+
+static int debug_level = 8;
+static int dumb_switch;
+
+/* Next 2 are only used in cpmac_probe, so it's pointless to change them */
+module_param(debug_level, int, 0444);
+module_param(dumb_switch, int, 0444);
+
+MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable");
+MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
+
+#define CPMAC_VERSION "0.5.0"
+/* stolen from net/ieee80211.h */
+#ifndef MAC_FMT
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
+ ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+#endif
+/* frame size + 802.1q tag */
+#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4)
+#define CPMAC_QUEUES 8
+
+/* Ethernet registers */
+#define CPMAC_TX_CONTROL 0x0004
+#define CPMAC_TX_TEARDOWN 0x0008
+#define CPMAC_RX_CONTROL 0x0014
+#define CPMAC_RX_TEARDOWN 0x0018
+#define CPMAC_MBP 0x0100
+# define MBP_RXPASSCRC 0x40000000
+# define MBP_RXQOS 0x20000000
+# define MBP_RXNOCHAIN 0x10000000
+# define MBP_RXCMF 0x01000000
+# define MBP_RXSHORT 0x00800000
+# define MBP_RXCEF 0x00400000
+# define MBP_RXPROMISC 0x00200000
+# define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16)
+# define MBP_RXBCAST 0x00002000
+# define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8)
+# define MBP_RXMCAST 0x00000020
+# define MBP_MCASTCHAN(channel) ((channel) & 0x7)
+#define CPMAC_UNICAST_ENABLE 0x0104
+#define CPMAC_UNICAST_CLEAR 0x0108
+#define CPMAC_MAX_LENGTH 0x010c
+#define CPMAC_BUFFER_OFFSET 0x0110
+#define CPMAC_MAC_CONTROL 0x0160
+# define MAC_TXPTYPE 0x00000200
+# define MAC_TXPACE 0x00000040
+# define MAC_MII 0x00000020
+# define MAC_TXFLOW 0x00000010
+# define MAC_RXFLOW 0x00000008
+# define MAC_MTEST 0x00000004
+# define MAC_LOOPBACK 0x00000002
+# define MAC_FDX 0x00000001
+#define CPMAC_MAC_STATUS 0x0164
+# define MAC_STATUS_QOS 0x00000004
+# define MAC_STATUS_RXFLOW 0x00000002
+# define MAC_STATUS_TXFLOW 0x00000001
+#define CPMAC_TX_INT_ENABLE 0x0178
+#define CPMAC_TX_INT_CLEAR 0x017c
+#define CPMAC_MAC_INT_VECTOR 0x0180
+# define MAC_INT_STATUS 0x00080000
+# define MAC_INT_HOST 0x00040000
+# define MAC_INT_RX 0x00020000
+# define MAC_INT_TX 0x00010000
+#define CPMAC_MAC_EOI_VECTOR 0x0184
+#define CPMAC_RX_INT_ENABLE 0x0198
+#define CPMAC_RX_INT_CLEAR 0x019c
+#define CPMAC_MAC_INT_ENABLE 0x01a8
+#define CPMAC_MAC_INT_CLEAR 0x01ac
+#define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4)
+#define CPMAC_MAC_ADDR_MID 0x01d0
+#define CPMAC_MAC_ADDR_HI 0x01d4
+#define CPMAC_MAC_HASH_LO 0x01d8
+#define CPMAC_MAC_HASH_HI 0x01dc
+#define CPMAC_TX_PTR(channel) (0x0600 + (channel) * 4)
+#define CPMAC_RX_PTR(channel) (0x0620 + (channel) * 4)
+#define CPMAC_TX_ACK(channel) (0x0640 + (channel) * 4)
+#define CPMAC_RX_ACK(channel) (0x0660 + (channel) * 4)
+#define CPMAC_REG_END 0x0680
+/*
+ * Rx/Tx statistics
+ * TODO: use some of them to fill stats in cpmac_stats()
+ */
+#define CPMAC_STATS_RX_GOOD 0x0200
+#define CPMAC_STATS_RX_BCAST 0x0204
+#define CPMAC_STATS_RX_MCAST 0x0208
+#define CPMAC_STATS_RX_PAUSE 0x020c
+#define CPMAC_STATS_RX_CRC 0x0210
+#define CPMAC_STATS_RX_ALIGN 0x0214
+#define CPMAC_STATS_RX_OVER 0x0218
+#define CPMAC_STATS_RX_JABBER 0x021c
+#define CPMAC_STATS_RX_UNDER 0x0220
+#define CPMAC_STATS_RX_FRAG 0x0224
+#define CPMAC_STATS_RX_FILTER 0x0228
+#define CPMAC_STATS_RX_QOSFILTER 0x022c
+#define CPMAC_STATS_RX_OCTETS 0x0230
+
+#define CPMAC_STATS_TX_GOOD 0x0234
+#define CPMAC_STATS_TX_BCAST 0x0238
+#define CPMAC_STATS_TX_MCAST 0x023c
+#define CPMAC_STATS_TX_PAUSE 0x0240
+#define CPMAC_STATS_TX_DEFER 0x0244
+#define CPMAC_STATS_TX_COLLISION 0x0248
+#define CPMAC_STATS_TX_SINGLECOLL 0x024c
+#define CPMAC_STATS_TX_MULTICOLL 0x0250
+#define CPMAC_STATS_TX_EXCESSCOLL 0x0254
+#define CPMAC_STATS_TX_LATECOLL 0x0258
+#define CPMAC_STATS_TX_UNDERRUN 0x025c
+#define CPMAC_STATS_TX_CARRIERSENSE 0x0260
+#define CPMAC_STATS_TX_OCTETS 0x0264
+
+#define cpmac_read(base, reg) (readl((void __iomem *)(base) + (reg)))
+#define cpmac_write(base, reg, val) (writel(val, (void __iomem *)(base) + \
+ (reg)))
+
+/* MDIO bus */
+#define CPMAC_MDIO_VERSION 0x0000
+#define CPMAC_MDIO_CONTROL 0x0004
+# define MDIOC_IDLE 0x80000000
+# define MDIOC_ENABLE 0x40000000
+# define MDIOC_PREAMBLE 0x00100000
+# define MDIOC_FAULT 0x00080000
+# define MDIOC_FAULTDETECT 0x00040000
+# define MDIOC_INTTEST 0x00020000
+# define MDIOC_CLKDIV(div) ((div) & 0xff)
+#define CPMAC_MDIO_ALIVE 0x0008
+#define CPMAC_MDIO_LINK 0x000c
+#define CPMAC_MDIO_ACCESS(channel) (0x0080 + (channel) * 8)
+# define MDIO_BUSY 0x80000000
+# define MDIO_WRITE 0x40000000
+# define MDIO_REG(reg) (((reg) & 0x1f) << 21)
+# define MDIO_PHY(phy) (((phy) & 0x1f) << 16)
+# define MDIO_DATA(data) ((data) & 0xffff)
+#define CPMAC_MDIO_PHYSEL(channel) (0x0084 + (channel) * 8)
+# define PHYSEL_LINKSEL 0x00000040
+# define PHYSEL_LINKINT 0x00000020
+
+struct cpmac_desc {
+ u32 hw_next;
+ u32 hw_data;
+ u16 buflen;
+ u16 bufflags;
+ u16 datalen;
+ u16 dataflags;
+#define CPMAC_SOP 0x8000
+#define CPMAC_EOP 0x4000
+#define CPMAC_OWN 0x2000
+#define CPMAC_EOQ 0x1000
+ struct sk_buff *skb;
+ struct cpmac_desc *next;
+ dma_addr_t mapping;
+ dma_addr_t data_mapping;
+};
+
+struct cpmac_priv {
+ spinlock_t lock;
+ spinlock_t rx_lock;
+ struct cpmac_desc *rx_head;
+ int ring_size;
+ struct cpmac_desc *desc_ring;
+ dma_addr_t dma_ring;
+ void __iomem *regs;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy;
+ char phy_name[BUS_ID_SIZE];
+ int oldlink, oldspeed, oldduplex;
+ u32 msg_enable;
+ struct net_device *dev;
+ struct work_struct reset_work;
+ struct platform_device *pdev;
+};
+
+static irqreturn_t cpmac_irq(int, void *);
+static void cpmac_hw_start(struct net_device *dev);
+static void cpmac_hw_stop(struct net_device *dev);
+static int cpmac_stop(struct net_device *dev);
+static int cpmac_open(struct net_device *dev);
+
+static void cpmac_dump_regs(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ for (i = 0; i < CPMAC_REG_END; i += 4) {
+ if (i % 16 == 0) {
+ if (i)
+ printk("\n");
+ printk(KERN_DEBUG "%s: reg[%p]:", dev->name,
+ priv->regs + i);
+ }
+ printk(" %08x", cpmac_read(priv->regs, i));
+ }
+ printk("\n");
+}
+
+static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc)
+{
+ int i;
+ printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc);
+ for (i = 0; i < sizeof(*desc) / 4; i++)
+ printk(" %08x", ((u32 *)desc)[i]);
+ printk("\n");
+}
+
+static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ int i;
+ printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len);
+ for (i = 0; i < skb->len; i++) {
+ if (i % 16 == 0) {
+ if (i)
+ printk("\n");
+ printk(KERN_DEBUG "%s: data[%p]:", dev->name,
+ skb->data + i);
+ }
+ printk(" %02x", ((u8 *)skb->data)[i]);
+ }
+ printk("\n");
+}
+
+static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ u32 val;
+
+ while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+ cpu_relax();
+ cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_REG(reg) |
+ MDIO_PHY(phy_id));
+ while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY)
+ cpu_relax();
+ return MDIO_DATA(val);
+}
+
+static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
+ int reg, u16 val)
+{
+ while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+ cpu_relax();
+ cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE |
+ MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val));
+ return 0;
+}
+
+static int cpmac_mdio_reset(struct mii_bus *bus)
+{
+ ar7_device_reset(AR7_RESET_BIT_MDIO);
+ cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
+ MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
+ return 0;
+}
+
+static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
+
+static struct mii_bus cpmac_mii = {
+ .name = "cpmac-mii",
+ .read = cpmac_mdio_read,
+ .write = cpmac_mdio_write,
+ .reset = cpmac_mdio_reset,
+ .irq = mii_irqs,
+};
+
+static int cpmac_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* Don't allow changing the I/O address */
+ if (map->base_addr != dev->base_addr)
+ return -EOPNOTSUPP;
+
+ /* ignore other fields */
+ return 0;
+}
+
+static void cpmac_set_multicast_list(struct net_device *dev)
+{
+ struct dev_mc_list *iter;
+ int i;
+ u8 tmp;
+ u32 mbp, bit, hash[2] = { 0, };
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ mbp = cpmac_read(priv->regs, CPMAC_MBP);
+ if (dev->flags & IFF_PROMISC) {
+ cpmac_write(priv->regs, CPMAC_MBP, (mbp & ~MBP_PROMISCCHAN(0)) |
+ MBP_RXPROMISC);
+ } else {
+ cpmac_write(priv->regs, CPMAC_MBP, mbp & ~MBP_RXPROMISC);
+ if (dev->flags & IFF_ALLMULTI) {
+ /* enable all multicast mode */
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff);
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff);
+ } else {
+ /*
+ * cpmac uses some strange mac address hashing
+ * (not crc32)
+ */
+ for (i = 0, iter = dev->mc_list; i < dev->mc_count;
+ i++, iter = iter->next) {
+ bit = 0;
+ tmp = iter->dmi_addr[0];
+ bit ^= (tmp >> 2) ^ (tmp << 4);
+ tmp = iter->dmi_addr[1];
+ bit ^= (tmp >> 4) ^ (tmp << 2);
+ tmp = iter->dmi_addr[2];
+ bit ^= (tmp >> 6) ^ tmp;
+ tmp = iter->dmi_addr[3];
+ bit ^= (tmp >> 2) ^ (tmp << 4);
+ tmp = iter->dmi_addr[4];
+ bit ^= (tmp >> 4) ^ (tmp << 2);
+ tmp = iter->dmi_addr[5];
+ bit ^= (tmp >> 6) ^ tmp;
+ bit &= 0x3f;
+ hash[bit / 32] |= 1 << (bit % 32);
+ }
+
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, hash[0]);
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, hash[1]);
+ }
+ }
+}
+
+static struct sk_buff *cpmac_rx_one(struct net_device *dev,
+ struct cpmac_priv *priv,
+ struct cpmac_desc *desc)
+{
+ struct sk_buff *skb, *result = NULL;
+
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(dev, desc);
+ cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping);
+ if (unlikely(!desc->datalen)) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: rx: spurious interrupt\n",
+ dev->name);
+ return NULL;
+ }
+
+ skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+ if (likely(skb)) {
+ skb_reserve(skb, 2);
+ skb_put(desc->skb, desc->datalen);
+ desc->skb->protocol = eth_type_trans(desc->skb, dev);
+ desc->skb->ip_summed = CHECKSUM_NONE;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += desc->datalen;
+ result = desc->skb;
+ dma_unmap_single(&dev->dev, desc->data_mapping, CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&dev->dev, skb->data,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ if (unlikely(netif_msg_pktdata(priv))) {
+ printk(KERN_DEBUG "%s: received packet:\n", dev->name);
+ cpmac_dump_skb(dev, result);
+ }
+ } else {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING
+ "%s: low on skbs, dropping packet\n", dev->name);
+ dev->stats.rx_dropped++;
+ }
+
+ desc->buflen = CPMAC_SKB_SIZE;
+ desc->dataflags = CPMAC_OWN;
+
+ return result;
+}
+
+static int cpmac_poll(struct net_device *dev, int *budget)
+{
+ struct sk_buff *skb;
+ struct cpmac_desc *desc;
+ int received = 0, quota = min(dev->quota, *budget);
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ spin_lock(&priv->rx_lock);
+ if (unlikely(!priv->rx_head)) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: rx: polling, but no queue\n",
+ dev->name);
+ netif_rx_complete(dev);
+ return 0;
+ }
+
+ desc = priv->rx_head;
+ while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) {
+ skb = cpmac_rx_one(dev, priv, desc);
+ if (likely(skb)) {
+ netif_receive_skb(skb);
+ received++;
+ }
+ desc = desc->next;
+ }
+
+ priv->rx_head = desc;
+ spin_unlock(&priv->rx_lock);
+ *budget -= received;
+ dev->quota -= received;
+ if (unlikely(netif_msg_rx_status(priv)))
+ printk(KERN_DEBUG "%s: poll processed %d packets\n", dev->name,
+ received);
+ if (desc->dataflags & CPMAC_OWN) {
+ netif_rx_complete(dev);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping);
+ cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int queue, len;
+ struct cpmac_desc *desc;
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (unlikely(skb_padto(skb, ETH_ZLEN))) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING
+ "%s: tx: padding failed, dropping\n", dev->name);
+ spin_lock(&priv->lock);
+ dev->stats.tx_dropped++;
+ spin_unlock(&priv->lock);
+ return -ENOMEM;
+ }
+
+ len = max(skb->len, ETH_ZLEN);
+ queue = skb->queue_mapping;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ netif_stop_subqueue(dev, queue);
+#else
+ netif_stop_queue(dev);
+#endif
+
+ desc = &priv->desc_ring[queue];
+ if (unlikely(desc->dataflags & CPMAC_OWN)) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: tx dma ring full, dropping\n",
+ dev->name);
+ spin_lock(&priv->lock);
+ dev->stats.tx_dropped++;
+ spin_unlock(&priv->lock);
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+
+ spin_lock(&priv->lock);
+ dev->trans_start = jiffies;
+ spin_unlock(&priv->lock);
+ desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&dev->dev, skb->data, len,
+ DMA_TO_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ desc->datalen = len;
+ desc->buflen = len;
+ if (unlikely(netif_msg_tx_queued(priv)))
+ printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb,
+ skb->len);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(dev, desc);
+ if (unlikely(netif_msg_pktdata(priv)))
+ cpmac_dump_skb(dev, skb);
+ cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping);
+
+ return 0;
+}
+
+static void cpmac_end_xmit(struct net_device *dev, int queue)
+{
+ struct cpmac_desc *desc;
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ desc = &priv->desc_ring[queue];
+ cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping);
+ if (likely(desc->skb)) {
+ spin_lock(&priv->lock);
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += desc->skb->len;
+ spin_unlock(&priv->lock);
+ dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len,
+ DMA_TO_DEVICE);
+
+ if (unlikely(netif_msg_tx_done(priv)))
+ printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name,
+ desc->skb, desc->skb->len);
+
+ dev_kfree_skb_irq(desc->skb);
+ desc->skb = NULL;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (netif_subqueue_stopped(dev, queue))
+ netif_wake_subqueue(dev, queue);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+ } else {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING
+ "%s: end_xmit: spurious interrupt\n", dev->name);
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (netif_subqueue_stopped(dev, queue))
+ netif_wake_subqueue(dev, queue);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+ }
+}
+
+static void cpmac_hw_stop(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+ ar7_device_reset(pdata->reset_bit);
+ cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1);
+ cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1);
+ for (i = 0; i < 8; i++) {
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+ }
+ cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+ cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII);
+}
+
+static void cpmac_hw_start(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+ ar7_device_reset(pdata->reset_bit);
+ for (i = 0; i < 8; i++) {
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+ }
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping);
+
+ cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST |
+ MBP_RXMCAST);
+ cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0);
+ for (i = 0; i < 8; i++)
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]);
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]);
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] |
+ (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) |
+ (dev->dev_addr[3] << 24));
+ cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE);
+ cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1);
+ cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+ cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3);
+
+ cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1);
+ cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1);
+ cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+ cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII |
+ MAC_FDX);
+}
+
+static void cpmac_clear_rx(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct cpmac_desc *desc;
+ int i;
+ if (unlikely(!priv->rx_head))
+ return;
+ desc = priv->rx_head;
+ for (i = 0; i < priv->ring_size; i++) {
+ if ((desc->dataflags & CPMAC_OWN) == 0) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: packet dropped\n",
+ dev->name);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(dev, desc);
+ desc->dataflags = CPMAC_OWN;
+ dev->stats.rx_dropped++;
+ }
+ desc = desc->next;
+ }
+}
+
+static void cpmac_clear_tx(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int i;
+ if (unlikely(!priv->desc_ring))
+ return;
+ for (i = 0; i < CPMAC_QUEUES; i++)
+ if (priv->desc_ring[i].skb) {
+ dev_kfree_skb_any(priv->desc_ring[i].skb);
+ if (netif_subqueue_stopped(dev, i))
+ netif_wake_subqueue(dev, i);
+ }
+}
+
+static void cpmac_hw_error(struct work_struct *work)
+{
+ struct cpmac_priv *priv =
+ container_of(work, struct cpmac_priv, reset_work);
+
+ spin_lock(&priv->rx_lock);
+ cpmac_clear_rx(priv->dev);
+ spin_unlock(&priv->rx_lock);
+ cpmac_clear_tx(priv->dev);
+ cpmac_hw_start(priv->dev);
+ netif_start_queue(priv->dev);
+}
+
+static irqreturn_t cpmac_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct cpmac_priv *priv;
+ int queue;
+ u32 status;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ priv = netdev_priv(dev);
+
+ status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR);
+
+ if (unlikely(netif_msg_intr(priv)))
+ printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name,
+ status);
+
+ if (status & MAC_INT_TX)
+ cpmac_end_xmit(dev, (status & 7));
+
+ if (status & MAC_INT_RX) {
+ queue = (status >> 8) & 7;
+ netif_rx_schedule(dev);
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue);
+ }
+
+ cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0);
+
+ if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) {
+ if (netif_msg_drv(priv) && net_ratelimit())
+ printk(KERN_ERR "%s: hw error, resetting...\n",
+ dev->name);
+ netif_stop_queue(dev);
+ cpmac_hw_stop(dev);
+ schedule_work(&priv->reset_work);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_regs(dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void cpmac_tx_timeout(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int i;
+
+ spin_lock(&priv->lock);
+ dev->stats.tx_errors++;
+ spin_unlock(&priv->lock);
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: transmit timeout\n", dev->name);
+ /*
+ * FIXME: waking up random queue is not the best thing to
+ * do... on the other hand why we got here at all?
+ */
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ for (i = 0; i < CPMAC_QUEUES; i++)
+ if (priv->desc_ring[i].skb) {
+ dev_kfree_skb_any(priv->desc_ring[i].skb);
+ netif_wake_subqueue(dev, i);
+ break;
+ }
+#else
+ if (priv->desc_ring[0].skb)
+ dev_kfree_skb_any(priv->desc_ring[0].skb);
+ netif_wake_queue(dev);
+#endif
+}
+
+static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ if (!(netif_running(dev)))
+ return -EINVAL;
+ if (!priv->phy)
+ return -EINVAL;
+ if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
+ (cmd == SIOCSMIIREG))
+ return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
+
+ return -EOPNOTSUPP;
+}
+
+static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (priv->phy)
+ return phy_ethtool_gset(priv->phy, cmd);
+
+ return -EINVAL;
+}
+
+static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (priv->phy)
+ return phy_ethtool_sset(priv->phy, cmd);
+
+ return -EINVAL;
+}
+
+static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ ring->rx_max_pending = 1024;
+ ring->rx_mini_max_pending = 1;
+ ring->rx_jumbo_max_pending = 1;
+ ring->tx_max_pending = 1;
+
+ ring->rx_pending = priv->ring_size;
+ ring->rx_mini_pending = 1;
+ ring->rx_jumbo_pending = 1;
+ ring->tx_pending = 1;
+}
+
+static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (dev->flags && IFF_UP)
+ return -EBUSY;
+ priv->ring_size = ring->rx_pending;
+ return 0;
+}
+
+static void cpmac_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, "cpmac");
+ strcpy(info->version, CPMAC_VERSION);
+ info->fw_version[0] = '\0';
+ sprintf(info->bus_info, "%s", "cpmac");
+ info->regdump_len = 0;
+}
+
+static const struct ethtool_ops cpmac_ethtool_ops = {
+ .get_settings = cpmac_get_settings,
+ .set_settings = cpmac_set_settings,
+ .get_drvinfo = cpmac_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = cpmac_get_ringparam,
+ .set_ringparam = cpmac_set_ringparam,
+};
+
+static void cpmac_adjust_link(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int new_state = 0;
+
+ spin_lock(&priv->lock);
+ if (priv->phy->link) {
+ netif_start_queue(dev);
+ if (priv->phy->duplex != priv->oldduplex) {
+ new_state = 1;
+ priv->oldduplex = priv->phy->duplex;
+ }
+
+ if (priv->phy->speed != priv->oldspeed) {
+ new_state = 1;
+ priv->oldspeed = priv->phy->speed;
+ }
+
+ if (!priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 1;
+ netif_schedule(dev);
+ }
+ } else if (priv->oldlink) {
+ netif_stop_queue(dev);
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+ }
+
+ if (new_state && netif_msg_link(priv) && net_ratelimit())
+ phy_print_status(priv->phy);
+
+ spin_unlock(&priv->lock);
+}
+
+static int cpmac_open(struct net_device *dev)
+{
+ int i, size, res;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+ struct cpmac_desc *desc;
+ struct sk_buff *skb;
+
+ priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link,
+ 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(priv->phy)) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Could not attach to PHY\n",
+ dev->name);
+ return PTR_ERR(priv->phy);
+ }
+
+ mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+ if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to request registers\n",
+ dev->name);
+ res = -ENXIO;
+ goto fail_reserve;
+ }
+
+ priv->regs = ioremap(mem->start, mem->end - mem->start);
+ if (!priv->regs) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to remap registers\n",
+ dev->name);
+ res = -ENXIO;
+ goto fail_remap;
+ }
+
+ size = priv->ring_size + CPMAC_QUEUES;
+ priv->desc_ring = dma_alloc_coherent(&dev->dev,
+ sizeof(struct cpmac_desc) * size,
+ &priv->dma_ring,
+ GFP_KERNEL);
+ if (!priv->desc_ring) {
+ res = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ for (i = 0; i < size; i++)
+ priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i;
+
+ priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+ for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) {
+ skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+ if (unlikely(!skb)) {
+ res = -ENOMEM;
+ goto fail_desc;
+ }
+ skb_reserve(skb, 2);
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&dev->dev, skb->data,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ desc->buflen = CPMAC_SKB_SIZE;
+ desc->dataflags = CPMAC_OWN;
+ desc->next = &priv->rx_head[(i + 1) % priv->ring_size];
+ desc->hw_next = (u32)desc->next->mapping;
+ }
+
+ if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
+ dev->name, dev))) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to obtain irq\n",
+ dev->name);
+ goto fail_irq;
+ }
+
+ INIT_WORK(&priv->reset_work, cpmac_hw_error);
+ cpmac_hw_start(dev);
+
+ priv->phy->state = PHY_CHANGELINK;
+ phy_start(priv->phy);
+
+ return 0;
+
+fail_irq:
+fail_desc:
+ for (i = 0; i < priv->ring_size; i++) {
+ if (priv->rx_head[i].skb) {
+ dma_unmap_single(&dev->dev,
+ priv->rx_head[i].data_mapping,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_head[i].skb);
+ }
+ }
+fail_alloc:
+ kfree(priv->desc_ring);
+ iounmap(priv->regs);
+
+fail_remap:
+ release_mem_region(mem->start, mem->end - mem->start);
+
+fail_reserve:
+ phy_disconnect(priv->phy);
+
+ return res;
+}
+
+static int cpmac_stop(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ netif_stop_queue(dev);
+
+ cancel_work_sync(&priv->reset_work);
+ phy_stop(priv->phy);
+ phy_disconnect(priv->phy);
+ priv->phy = NULL;
+
+ cpmac_hw_stop(dev);
+
+ for (i = 0; i < 8; i++)
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0);
+ cpmac_write(priv->regs, CPMAC_MBP, 0);
+
+ free_irq(dev->irq, dev);
+ iounmap(priv->regs);
+ mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+ release_mem_region(mem->start, mem->end - mem->start);
+ priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+ for (i = 0; i < priv->ring_size; i++) {
+ if (priv->rx_head[i].skb) {
+ dma_unmap_single(&dev->dev,
+ priv->rx_head[i].data_mapping,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_head[i].skb);
+ }
+ }
+
+ dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) *
+ (CPMAC_QUEUES + priv->ring_size),
+ priv->desc_ring, priv->dma_ring);
+ return 0;
+}
+
+static int external_switch;
+
+static int __devinit cpmac_probe(struct platform_device *pdev)
+{
+ int rc, phy_id;
+ struct resource *mem;
+ struct cpmac_priv *priv;
+ struct net_device *dev;
+ struct plat_cpmac_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+
+ for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+ if (!(pdata->phy_mask & (1 << phy_id)))
+ continue;
+ if (!cpmac_mii.phy_map[phy_id])
+ continue;
+ break;
+ }
+
+ if (phy_id == PHY_MAX_ADDR) {
+ if (external_switch || dumb_switch)
+ phy_id = 0;
+ else {
+ printk(KERN_ERR "cpmac: no PHY present\n");
+ return -ENODEV;
+ }
+ }
+
+ dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES);
+
+ if (!dev) {
+ printk(KERN_ERR "cpmac: Unable to allocate net_device\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ priv = netdev_priv(dev);
+
+ priv->pdev = pdev;
+ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ if (!mem) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ dev->irq = platform_get_irq_byname(pdev, "irq");
+
+ dev->open = cpmac_open;
+ dev->stop = cpmac_stop;
+ dev->set_config = cpmac_config;
+ dev->hard_start_xmit = cpmac_start_xmit;
+ dev->do_ioctl = cpmac_ioctl;
+ dev->set_multicast_list = cpmac_set_multicast_list;
+ dev->tx_timeout = cpmac_tx_timeout;
+ dev->ethtool_ops = &cpmac_ethtool_ops;
+ dev->poll = cpmac_poll;
+ dev->weight = 64;
+ dev->features |= NETIF_F_MULTI_QUEUE;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->rx_lock);
+ priv->dev = dev;
+ priv->ring_size = 64;
+ priv->msg_enable = netif_msg_init(debug_level, 0xff);
+ memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
+ if (phy_id == 31) {
+ snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT,
+ cpmac_mii.id, phy_id);
+ } else
+ snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1);
+
+ if ((rc = register_netdev(dev))) {
+ printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,
+ dev->name);
+ goto fail;
+ }
+
+ if (netif_msg_probe(priv)) {
+ printk(KERN_INFO
+ "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: "
+ MAC_FMT ")\n", dev->name, (void *)mem->start, dev->irq,
+ priv->phy_name, MAC_ARG(dev->dev_addr));
+ }
+ return 0;
+
+fail:
+ free_netdev(dev);
+ return rc;
+}
+
+static int __devexit cpmac_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ unregister_netdev(dev);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver cpmac_driver = {
+ .driver.name = "cpmac",
+ .probe = cpmac_probe,
+ .remove = __devexit_p(cpmac_remove),
+};
+
+int __devinit cpmac_init(void)
+{
+ u32 mask;
+ int i, res;
+
+ cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);
+
+ if (!cpmac_mii.priv) {
+ printk(KERN_ERR "Can't ioremap mdio registers\n");
+ return -ENXIO;
+ }
+
+#warning FIXME: unhardcode gpio&reset bits
+ ar7_gpio_disable(26);
+ ar7_gpio_disable(27);
+ ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
+ ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
+ ar7_device_reset(AR7_RESET_BIT_EPHY);
+
+ cpmac_mii.reset(&cpmac_mii);
+
+ for (i = 0; i < 300000; i++)
+ if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))
+ break;
+ else
+ cpu_relax();
+
+ mask &= 0x7fffffff;
+ if (mask & (mask - 1)) {
+ external_switch = 1;
+ mask = 0;
+ }
+
+ cpmac_mii.phy_mask = ~(mask | 0x80000000);
+
+ res = mdiobus_register(&cpmac_mii);
+ if (res)
+ goto fail_mii;
+
+ res = platform_driver_register(&cpmac_driver);
+ if (res)
+ goto fail_cpmac;
+
+ return 0;
+
+fail_cpmac:
+ mdiobus_unregister(&cpmac_mii);
+
+fail_mii:
+ iounmap(cpmac_mii.priv);
+
+ return res;
+}
+
+void __devexit cpmac_exit(void)
+{
+ platform_driver_unregister(&cpmac_driver);
+ mdiobus_unregister(&cpmac_mii);
+ iounmap(cpmac_mii.priv);
+}
+
+module_init(cpmac_init);
+module_exit(cpmac_exit);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 0db5e6fabe7..558440c15b6 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -168,7 +168,6 @@ static int gfar_probe(struct platform_device *pdev)
struct gfar_private *priv = NULL;
struct gianfar_platform_data *einfo;
struct resource *r;
- int idx;
int err = 0;
DECLARE_MAC_BUF(mac);
@@ -261,7 +260,9 @@ static int gfar_probe(struct platform_device *pdev)
dev->hard_start_xmit = gfar_start_xmit;
dev->tx_timeout = gfar_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_GFAR_NAPI
netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = gfar_netpoll;
#endif
@@ -931,9 +932,14 @@ tx_skb_fail:
/* Returns 0 for success. */
static int gfar_enet_open(struct net_device *dev)
{
+#ifdef CONFIG_GFAR_NAPI
+ struct gfar_private *priv = netdev_priv(dev);
+#endif
int err;
+#ifdef CONFIG_GFAR_NAPI
napi_enable(&priv->napi);
+#endif
/* Initialize a bunch of registers */
init_registers(dev);
@@ -943,13 +949,17 @@ static int gfar_enet_open(struct net_device *dev)
err = init_phy(dev);
if(err) {
+#ifdef CONFIG_GFAR_NAPI
napi_disable(&priv->napi);
+#endif
return err;
}
err = startup_gfar(dev);
if (err)
+#ifdef CONFIG_GFAR_NAPI
napi_disable(&priv->napi);
+#endif
netif_start_queue(dev);
@@ -1103,7 +1113,9 @@ static int gfar_close(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+#ifdef CONFIG_GFAR_NAPI
napi_disable(&priv->napi);
+#endif
stop_gfar(dev);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index ecd156def03..ad9e327c3b0 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -292,7 +292,7 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev,
const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
- if (type != htons(ETH_P_AX25))
+ if (type != ETH_P_AX25)
return ax25_hard_header(skb, dev, type, daddr, saddr, len);
#endif
return 0;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 9e43c47691c..803a3bdea0a 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -583,7 +583,7 @@ static int ax_header(struct sk_buff *skb, struct net_device *dev,
const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
- if (type != htons(ETH_P_AX25))
+ if (type != ETH_P_AX25)
return ax25_hard_header(skb, dev, type, daddr, saddr, len);
#endif
return 0;
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index 4e49e8c4f87..dcd8826fc74 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -413,7 +413,10 @@ static int __init mal_probe(struct ocp_device *ocpdev)
ocpdev->def->index);
return -ENOMEM;
}
- mal->dcrbase = maldata->dcr_base;
+
+ /* XXX This only works for native dcr for now */
+ mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0);
+
mal->def = ocpdev->def;
INIT_LIST_HEAD(&mal->poll_list);
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 8f54d621994..b8adbe6d4b0 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -191,7 +191,6 @@ struct mal_commac {
};
struct ibm_ocp_mal {
- int dcrbase;
dcr_host_t dcrhost;
struct list_head poll_list;
@@ -209,12 +208,12 @@ struct ibm_ocp_mal {
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
{
- return dcr_read(mal->dcrhost, mal->dcrbase + reg);
+ return dcr_read(mal->dcrhost, reg);
}
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
{
- dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
+ dcr_write(mal->dcrhost, reg, val);
}
/* Register MAL devices */
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 8ea50096187..0de3aa2a2e4 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1534,7 +1534,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
dev_kfree_skb(dev->rx_sg_skb);
dev->rx_sg_skb = NULL;
} else {
- cacheable_memcpy(dev->rx_sg_skb->tail,
+ cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
dev->rx_skb[slot]->data, len);
skb_put(dev->rx_sg_skb, len);
emac_recycle_rx_skb(dev, slot, len);
@@ -1950,7 +1950,7 @@ static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
{
struct emac_instance *dev = netdev_priv(ndev);
- return dev->tah_dev != 0;
+ return dev->tah_dev != NULL;
}
static int emac_get_regs_len(struct emac_instance *dev)
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 58854117b1a..39f4cb6b0cf 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -461,6 +461,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
struct mal_instance *mal;
int err = 0, i, bd_size;
int index = mal_count++;
+ unsigned int dcr_base;
const u32 *prop;
u32 cfg;
@@ -497,14 +498,14 @@ static int __devinit mal_probe(struct of_device *ofdev,
}
mal->num_rx_chans = prop[0];
- mal->dcr_base = dcr_resource_start(ofdev->node, 0);
- if (mal->dcr_base == 0) {
+ dcr_base = dcr_resource_start(ofdev->node, 0);
+ if (dcr_base == 0) {
printk(KERN_ERR
"mal%d: can't find DCR resource!\n", index);
err = -ENODEV;
goto fail;
}
- mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100);
+ mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);
if (!DCR_MAP_OK(mal->dcr_host)) {
printk(KERN_ERR
"mal%d: failed to map DCRs !\n", index);
@@ -626,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
fail2:
dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
fail_unmap:
- dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100);
+ dcr_unmap(mal->dcr_host, 0x100);
fail:
kfree(mal);
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index cb1a16d589f..784edb8ea82 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -185,7 +185,6 @@ struct mal_commac {
struct mal_instance {
int version;
- int dcr_base;
dcr_host_t dcr_host;
int num_tx_chans; /* Number of TX channels */
@@ -213,12 +212,12 @@ struct mal_instance {
static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
{
- return dcr_read(mal->dcr_host, mal->dcr_base + reg);
+ return dcr_read(mal->dcr_host, reg);
}
static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
{
- dcr_write(mal->dcr_host, mal->dcr_base + reg, val);
+ dcr_write(mal->dcr_host, reg, val);
}
/* Register MAL devices */
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
index bcd7fc639c4..de416951a43 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -84,7 +84,7 @@ static inline u32 rgmii_mode_mask(int mode, int input)
int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct rgmii_regs *p = dev->base;
+ struct rgmii_regs __iomem *p = dev->base;
RGMII_DBG(dev, "attach(%d)" NL, input);
@@ -113,7 +113,7 @@ int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct rgmii_regs *p = dev->base;
+ struct rgmii_regs __iomem *p = dev->base;
u32 ssr;
mutex_lock(&dev->lock);
@@ -135,7 +135,7 @@ void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
void rgmii_get_mdio(struct of_device *ofdev, int input)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct rgmii_regs *p = dev->base;
+ struct rgmii_regs __iomem *p = dev->base;
u32 fer;
RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
@@ -156,7 +156,7 @@ void rgmii_get_mdio(struct of_device *ofdev, int input)
void rgmii_put_mdio(struct of_device *ofdev, int input)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct rgmii_regs *p = dev->base;
+ struct rgmii_regs __iomem *p = dev->base;
u32 fer;
RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
@@ -177,7 +177,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input)
void __devexit rgmii_detach(struct of_device *ofdev, int input)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct rgmii_regs *p = dev->base;
+ struct rgmii_regs __iomem *p = dev->base;
mutex_lock(&dev->lock);
@@ -242,7 +242,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
}
rc = -ENOMEM;
- dev->base = (struct rgmii_regs *)ioremap(regs.start,
+ dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start,
sizeof(struct rgmii_regs));
if (dev->base == NULL) {
printk(KERN_ERR "%s: Can't map device registers!\n",
@@ -251,7 +251,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
}
/* Check for RGMII type */
- if (device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+ if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
dev->type = RGMII_AXON;
else
dev->type = RGMII_STANDARD;
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
index e05c7e81efb..f161fb100e8 100644
--- a/drivers/net/ibm_newemac/tah.c
+++ b/drivers/net/ibm_newemac/tah.c
@@ -42,7 +42,7 @@ void __devexit tah_detach(struct of_device *ofdev, int channel)
void tah_reset(struct of_device *ofdev)
{
struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct tah_regs *p = dev->base;
+ struct tah_regs __iomem *p = dev->base;
int n;
/* Reset TAH */
@@ -108,7 +108,7 @@ static int __devinit tah_probe(struct of_device *ofdev,
}
rc = -ENOMEM;
- dev->base = (struct tah_regs *)ioremap(regs.start,
+ dev->base = (struct tah_regs __iomem *)ioremap(regs.start,
sizeof(struct tah_regs));
if (dev->base == NULL) {
printk(KERN_ERR "%s: Can't map device registers!\n",
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
index d0631290184..2219ec2740e 100644
--- a/drivers/net/ibm_newemac/zmii.c
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -79,7 +79,7 @@ static inline u32 zmii_mode_mask(int mode, int input)
int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
{
struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
- struct zmii_regs *p = dev->base;
+ struct zmii_regs __iomem *p = dev->base;
ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
@@ -250,7 +250,7 @@ static int __devinit zmii_probe(struct of_device *ofdev,
}
rc = -ENOMEM;
- dev->base = (struct zmii_regs *)ioremap(regs.start,
+ dev->base = (struct zmii_regs __iomem *)ioremap(regs.start,
sizeof(struct zmii_regs));
if (dev->base == NULL) {
printk(KERN_ERR "%s: Can't map device registers!\n",
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 4ac161e1ca1..7d7758f3ad8 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
pool_count[i], pool_size[i],
pool_active[i]);
kobj->parent = &dev->dev.kobj;
- sprintf(kobj->name, "pool%d", i);
+ kobject_set_name(kobj, "pool%d", i);
kobj->ktype = &ktype_veth_pool;
kobject_register(kobj);
}
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 59898ce54dc..68887235d7e 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -754,7 +754,7 @@ static int init_rfdlist(struct net_device *dev)
if (sp->RxBuff[i]) {
pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
sp->RxBuff[i] = NULL;
@@ -871,7 +871,7 @@ static void ipg_nic_txfree(struct net_device *dev)
/* Free the transmit buffer. */
if (skb) {
pci_unmap_single(sp->pdev,
- le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+ le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
skb->len, PCI_DMA_TODEVICE);
IPG_DEV_KFREE_SKB(skb);
@@ -1413,10 +1413,10 @@ static int ipg_nic_rx(struct net_device *dev)
framelen = IPG_RXFRAG_SIZE;
}
- if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs &
+ if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
(IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
- IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) {
+ IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
(unsigned long int) rxfd->rfs);
@@ -1425,27 +1425,27 @@ static int ipg_nic_rx(struct net_device *dev)
sp->stats.rx_errors++;
/* Increment detailed receive error statistics. */
- if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) {
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
sp->stats.rx_fifo_errors++;
}
- if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) {
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
IPG_DEBUG_MSG("RX runt occured.\n");
sp->stats.rx_length_errors++;
}
- if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ;
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ;
/* Do nothing, error count handled by a IPG
* statistic register.
*/
- if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) {
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
IPG_DEBUG_MSG("RX alignment error occured.\n");
sp->stats.rx_frame_errors++;
}
- if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ;
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ;
/* Do nothing, error count handled by a IPG
* statistic register.
*/
@@ -1455,10 +1455,10 @@ static int ipg_nic_rx(struct net_device *dev)
* not pass it to higher layer processes.
*/
if (skb) {
- u64 info = rxfd->frag_info;
+ __le64 info = rxfd->frag_info;
pci_unmap_single(sp->pdev,
- le64_to_cpu(info & ~IPG_RFI_FRAGLEN),
+ le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
IPG_DEV_KFREE_SKB(skb);
@@ -1532,9 +1532,9 @@ static int ipg_nic_rx(struct net_device *dev)
if (!i)
sp->EmptyRFDListCount++;
#endif
- while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) &&
- !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) &&
- (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) {
+ while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) &&
+ !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) &&
+ (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) {
unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
rxfd = sp->rxd + entry;
@@ -1552,7 +1552,7 @@ static int ipg_nic_rx(struct net_device *dev)
*/
if (sp->RxBuff[entry]) {
pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
}
@@ -1730,7 +1730,7 @@ static void ipg_rx_clear(struct ipg_nic_private *sp)
IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
sp->RxBuff[i] = NULL;
pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
}
}
@@ -1745,7 +1745,7 @@ static void ipg_tx_clear(struct ipg_nic_private *sp)
struct ipg_tx *txfd = sp->txd + i;
pci_unmap_single(sp->pdev,
- le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+ le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
index 1952d0dfd31..e418b9035ca 100644
--- a/drivers/net/ipg.h
+++ b/drivers/net/ipg.h
@@ -776,17 +776,17 @@ enum ipg_regs {
* TFD field is 64 bits wide.
*/
struct ipg_tx {
- u64 next_desc;
- u64 tfc;
- u64 frag_info;
+ __le64 next_desc;
+ __le64 tfc;
+ __le64 frag_info;
};
/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
*/
struct ipg_rx {
- u64 next_desc;
- u64 rfs;
- u64 frag_info;
+ __le64 next_desc;
+ __le64 rfs;
+ __le64 frag_info;
};
struct SJumbo {
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 3e5eca1aa98..a82d8f98383 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -840,7 +840,7 @@ toshoboe_probe (struct toshoboe_cb *self)
/* test 1: SIR filter and back to back */
- for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j)
+ for (j = 0; j < ARRAY_SIZE(bauds); ++j)
{
int fir = (j > 1);
toshoboe_stopchip (self);
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index d3825c8ee99..5c154fe1385 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
struct sonic_local *lp;
struct resource *res;
int err = 0;
- int i;
DECLARE_MAC_BUF(mac);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index be25aa33971..662b8d16803 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -265,17 +265,16 @@ static __net_init int loopback_net_init(struct net *net)
if (err)
goto out_free_netdev;
- err = 0;
net->loopback_dev = dev;
+ return 0;
-out:
- if (err)
- panic("loopback: Failed to register netdevice: %d\n", err);
- return err;
out_free_netdev:
free_netdev(dev);
- goto out;
+out:
+ if (net == &init_net)
+ panic("loopback: Failed to register netdevice: %d\n", err);
+ return err;
}
static __net_exit void loopback_net_exit(struct net *net)
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 6589239b79e..18770527df9 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -538,8 +538,9 @@ static void mace_set_multicast(struct net_device *dev)
local_irq_restore(flags);
}
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct net_device *dev, int intr)
{
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
static int mace_babbles, mace_jabbers;
@@ -571,7 +572,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
local_irq_save(flags);
intr = mb->ir; /* read interrupt register */
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(dev, intr);
if (intr & XMTINT) {
fs = mb->xmtfs;
@@ -645,7 +646,6 @@ static void mace_tx_timeout(struct net_device *dev)
static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
{
- struct mace_data *mp = netdev_priv(dev);
struct sk_buff *skb;
unsigned int frame_status = mf->rcvsts;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index b7c81c874f7..2e4bcd5654c 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -178,7 +178,6 @@ static const struct header_ops macvlan_hard_header_ops = {
.create = macvlan_hard_header,
.rebuild = eth_rebuild_header,
.parse = eth_header_parse,
- .rebuild = eth_rebuild_header,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
};
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index d593175ab6f..37707a0c049 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -7,12 +7,12 @@
#define DEBUG
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
-#include <asm/io.h>
#include <asm/mips-boards/simint.h>
#include "mipsnet.h" /* actual device IO mapping */
@@ -33,9 +33,8 @@ static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
if (available_len < len)
return -EFAULT;
- for (; len > 0; len--, kdata++) {
+ for (; len > 0; len--, kdata++)
*kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
- }
return inl(mipsnet_reg_address(dev, rxDataCount));
}
@@ -47,16 +46,15 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
char *buf_ptr = skb->data;
pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
- dev->name, __FUNCTION__, skb->len);
+ dev->name, __FUNCTION__, skb->len);
outl(skb->len, mipsnet_reg_address(dev, txDataCount));
pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n",
- dev->name, __FUNCTION__, skb->len);
+ dev->name, __FUNCTION__, skb->len);
- for (; count_to_go; buf_ptr++, count_to_go--) {
+ for (; count_to_go; buf_ptr++, count_to_go--)
outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
- }
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -67,7 +65,7 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
pr_debug("%s:%s(): transmitting %d bytes\n",
- dev->name, __FUNCTION__, skb->len);
+ dev->name, __FUNCTION__, skb->len);
/* Only one packet at a time. Once TXDONE interrupt is serviced, the
* queue will be restarted.
@@ -83,7 +81,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
struct sk_buff *skb;
size_t len = count;
- if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
+ skb = alloc_skb(len + 2, GFP_KERNEL);
+ if (!skb) {
dev->stats.rx_dropped++;
return -ENOMEM;
}
@@ -96,7 +95,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
skb->ip_summed = CHECKSUM_UNNECESSARY;
pr_debug("%s:%s(): pushing RXed data to kernel\n",
- dev->name, __FUNCTION__);
+ dev->name, __FUNCTION__);
netif_rx(skb);
dev->stats.rx_packets++;
@@ -114,42 +113,44 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
if (irq == dev->irq) {
pr_debug("%s:%s(): irq %d for device\n",
- dev->name, __FUNCTION__, irq);
+ dev->name, __FUNCTION__, irq);
retval = IRQ_HANDLED;
interruptFlags =
inl(mipsnet_reg_address(dev, interruptControl));
pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name,
- __FUNCTION__, interruptFlags);
+ __FUNCTION__, interruptFlags);
if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
pr_debug("%s:%s(): got TXDone\n",
- dev->name, __FUNCTION__);
+ dev->name, __FUNCTION__);
outl(MIPSNET_INTCTL_TXDONE,
mipsnet_reg_address(dev, interruptControl));
- // only one packet at a time, we are done.
+ /* only one packet at a time, we are done. */
netif_wake_queue(dev);
} else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
pr_debug("%s:%s(): got RX data\n",
- dev->name, __FUNCTION__);
+ dev->name, __FUNCTION__);
mipsnet_get_fromdev(dev,
- inl(mipsnet_reg_address(dev, rxDataCount)));
+ inl(mipsnet_reg_address(dev, rxDataCount)));
pr_debug("%s:%s(): clearing RX int\n",
- dev->name, __FUNCTION__);
+ dev->name, __FUNCTION__);
outl(MIPSNET_INTCTL_RXDONE,
mipsnet_reg_address(dev, interruptControl));
} else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
pr_debug("%s:%s(): got test interrupt\n",
- dev->name, __FUNCTION__);
- // TESTBIT is cleared on read.
- // And takes effect after a write with 0
+ dev->name, __FUNCTION__);
+ /*
+ * TESTBIT is cleared on read.
+ * And takes effect after a write with 0
+ */
outl(0, mipsnet_reg_address(dev, interruptControl));
} else {
pr_debug("%s:%s(): no valid fags 0x%016llx\n",
- dev->name, __FUNCTION__, interruptFlags);
- // Maybe shared IRQ, just ignore, no clearing.
+ dev->name, __FUNCTION__, interruptFlags);
+ /* Maybe shared IRQ, just ignore, no clearing. */
retval = IRQ_NONE;
}
@@ -159,7 +160,7 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
retval = IRQ_NONE;
}
return retval;
-} //mipsnet_interrupt()
+}
static int mipsnet_open(struct net_device *dev)
{
@@ -171,18 +172,18 @@ static int mipsnet_open(struct net_device *dev)
if (err) {
pr_debug("%s: %s(): can't get irq %d\n",
- dev->name, __FUNCTION__, dev->irq);
+ dev->name, __FUNCTION__, dev->irq);
release_region(dev->base_addr, MIPSNET_IO_EXTENT);
return err;
}
pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n",
- dev->name, __FUNCTION__, dev->base_addr, dev->irq);
+ dev->name, __FUNCTION__, dev->base_addr, dev->irq);
netif_start_queue(dev);
- // test interrupt handler
+ /* test interrupt handler */
outl(MIPSNET_INTCTL_TESTBIT,
mipsnet_reg_address(dev, interruptControl));
@@ -199,8 +200,6 @@ static int mipsnet_close(struct net_device *dev)
static void mipsnet_set_mclist(struct net_device *dev)
{
- // we don't do anything
- return;
}
static int __init mipsnet_probe(struct device *dev)
@@ -226,13 +225,13 @@ static int __init mipsnet_probe(struct device *dev)
*/
netdev->base_addr = 0x4200;
netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
- inl(mipsnet_reg_address(netdev, interruptInfo));
+ inl(mipsnet_reg_address(netdev, interruptInfo));
- // Get the io region now, get irq on open()
+ /* Get the io region now, get irq on open() */
if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} "
- "for dev is not availble.\n", netdev->name,
- __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
+ "for dev is not availble.\n", netdev->name,
+ __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
err = -EBUSY;
goto out_free_netdev;
}
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
index 026c732024c..0132c6714a4 100644
--- a/drivers/net/mipsnet.h
+++ b/drivers/net/mipsnet.h
@@ -9,32 +9,34 @@
/*
* Id of this Net device, as seen by the core.
*/
-#define MIPS_NET_DEV_ID ((uint64_t) \
- ((uint64_t)'M'<< 0)| \
- ((uint64_t)'I'<< 8)| \
- ((uint64_t)'P'<<16)| \
- ((uint64_t)'S'<<24)| \
- ((uint64_t)'N'<<32)| \
- ((uint64_t)'E'<<40)| \
- ((uint64_t)'T'<<48)| \
- ((uint64_t)'0'<<56))
+#define MIPS_NET_DEV_ID ((uint64_t) \
+ ((uint64_t) 'M' << 0)| \
+ ((uint64_t) 'I' << 8)| \
+ ((uint64_t) 'P' << 16)| \
+ ((uint64_t) 'S' << 24)| \
+ ((uint64_t) 'N' << 32)| \
+ ((uint64_t) 'E' << 40)| \
+ ((uint64_t) 'T' << 48)| \
+ ((uint64_t) '0' << 56))
/*
* Net status/control block as seen by sw in the core.
* (Why not use bit fields? can't be bothered with cross-platform struct
* packing.)
*/
-typedef struct _net_control_block {
- /// dev info for probing
- /// reads as MIPSNET%d where %d is some form of version
- uint64_t devId; /*0x00 */
+struct net_control_block {
+ /*
+ * dev info for probing
+ * reads as MIPSNET%d where %d is some form of version
+ */
+ uint64_t devId; /* 0x00 */
/*
* read only busy flag.
* Set and cleared by the Net Device to indicate that an rx or a tx
* is in progress.
*/
- uint32_t busy; /*0x08 */
+ uint32_t busy; /* 0x08 */
/*
* Set by the Net Device.
@@ -43,16 +45,16 @@ typedef struct _net_control_block {
* rxDataBuffer. The value will decrease till 0 until all the data
* from rxDataBuffer has been read.
*/
- uint32_t rxDataCount; /*0x0c */
+ uint32_t rxDataCount; /* 0x0c */
#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
/*
- * Settable from the MIPS core, cleared by the Net Device.
- * The core should set the number of bytes it wants to send,
- * then it should write those bytes of data to txDataBuffer.
- * The device will clear txDataCount has been processed (not necessarily sent).
+ * Settable from the MIPS core, cleared by the Net Device. The core
+ * should set the number of bytes it wants to send, then it should
+ * write those bytes of data to txDataBuffer. The device will clear
+ * txDataCount has been processed (not necessarily sent).
*/
- uint32_t txDataCount; /*0x10 */
+ uint32_t txDataCount; /* 0x10 */
/*
* Interrupt control
@@ -69,39 +71,42 @@ typedef struct _net_control_block {
* To clear the test interrupt, write 0 to this register.
*/
uint32_t interruptControl; /*0x14 */
-#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0))
-#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1))
-#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31))
-#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT)
+#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0))
+#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1))
+#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31))
+#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \
+ MIPSNET_INTCTL_RXDONE | \
+ MIPSNET_INTCTL_TESTBIT)
/*
- * Readonly core-specific interrupt info for the device to signal the core.
- * The meaning of the contents of this field might change.
- */
- /*###\todo: the whole memIntf interrupt scheme is messy: the device should have
- * no control what so ever of what VPE/register set is being used.
- * The MemIntf should only expose interrupt lines, and something in the
- * config should be responsible for the line<->core/vpe bindings.
+ * Readonly core-specific interrupt info for the device to signal the
+ * core. The meaning of the contents of this field might change.
+ *
+ * TODO: the whole memIntf interrupt scheme is messy: the device should
+ * have no control what so ever of what VPE/register set is being
+ * used. The MemIntf should only expose interrupt lines, and
+ * something in the config should be responsible for the
+ * line<->core/vpe bindings.
*/
- uint32_t interruptInfo; /*0x18 */
+ uint32_t interruptInfo; /* 0x18 */
/*
* This is where the received data is read out.
* There is more data to read until rxDataReady is 0.
* Only 1 byte at this regs offset is used.
*/
- uint32_t rxDataBuffer; /*0x1c */
+ uint32_t rxDataBuffer; /* 0x1c */
/*
- * This is where the data to transmit is written.
- * Data should be written for the amount specified in the txDataCount register.
- * Only 1 byte at this regs offset is used.
+ * This is where the data to transmit is written. Data should be
+ * written for the amount specified in the txDataCount register. Only
+ * 1 byte at this regs offset is used.
*/
- uint32_t txDataBuffer; /*0x20 */
-} MIPS_T_NetControl;
+ uint32_t txDataBuffer; /* 0x20 */
+};
#define MIPSNET_IO_EXTENT 0x40 /* being generous */
-#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field)
+#define field_offset(field) (offsetof(struct net_control_block, field))
#endif /* __MIPSNET_H */
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index e029b8afbd3..89b3f0b7cdc 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -884,7 +884,7 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
++mlx4_version_printed;
}
- return mlx4_init_one(pdev, id);
+ return __mlx4_init_one(pdev, id);
}
static void mlx4_remove_one(struct pci_dev *pdev)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index b33d21f4eff..84f2d6382f1 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -784,7 +784,6 @@ static int mv643xx_eth_open(struct net_device *dev)
unsigned int port_num = mp->port_num;
unsigned int size;
int err;
- DECLARE_MAC_BUF(mac);
/* Clear any pending ethernet port interrupts */
mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
@@ -1296,6 +1295,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
struct ethtool_cmd cmd;
int duplex = DUPLEX_HALF;
int speed = 0; /* default to auto-negotiation */
+ DECLARE_MAC_BUF(mac);
pd = pdev->dev.platform_data;
if (pd == NULL) {
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c
index 86c9c06433c..06ca4252155 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/mvme147.c
@@ -85,7 +85,6 @@ struct net_device * __init mvme147lance_probe(int unit)
dev->open = &m147lance_open;
dev->stop = &m147lance_close;
dev->hard_start_xmit = &lance_start_xmit;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->tx_timeout = &lance_tx_timeout;
dev->dma = 0;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e8afa101433..64c8151f200 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.3.2-1.269"
+#define MYRI10GE_VERSION_STR "1.3.2-1.287"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -214,6 +214,8 @@ struct myri10ge_priv {
unsigned long serial_number;
int vendor_specific_offset;
int fw_multicast_support;
+ unsigned long features;
+ u32 max_tso6;
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
@@ -311,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
static void myri10ge_set_multicast_list(struct net_device *dev);
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);
static inline void put_be32(__be32 val, __be32 __iomem * p)
{
@@ -612,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
__be32 buf[16];
u32 dma_low, dma_high, size;
int status, i;
+ struct myri10ge_cmd cmd;
size = 0;
status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -688,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
dev_info(&mgp->pdev->dev, "handoff confirmed\n");
myri10ge_dummy_rdma(mgp, 1);
+ /* probe for IPv6 TSO support */
+ mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ &cmd, 0);
+ if (status == 0) {
+ mgp->max_tso6 = cmd.data0;
+ mgp->features |= NETIF_F_TSO6;
+ }
return 0;
}
@@ -1047,7 +1059,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
- /* allocate an skb to attach the page(s) to. */
+ /* allocate an skb to attach the page(s) to. This is done
+ * after trying LRO, so as to avoid skb allocation overheads */
skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
if (unlikely(skb == NULL)) {
@@ -1217,7 +1230,8 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
static int myri10ge_poll(struct napi_struct *napi, int budget)
{
- struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi);
+ struct myri10ge_priv *mgp =
+ container_of(napi, struct myri10ge_priv, napi);
struct net_device *netdev = mgp->dev;
struct myri10ge_rx_done *rx_done = &mgp->rx_done;
int work_done;
@@ -1382,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
return 0;
}
+static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
+
+ if (tso_enabled)
+ netdev->features |= flags;
+ else
+ netdev->features &= ~flags;
+ return 0;
+}
+
static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1506,7 +1532,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_rx_csum = myri10ge_set_rx_csum,
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = myri10ge_set_tso,
.get_link = ethtool_op_get_link,
.get_strings = myri10ge_get_strings,
.get_sset_count = myri10ge_get_sset_count,
@@ -2164,7 +2190,8 @@ again:
pseudo_hdr_offset = cksum_offset + skb->csum_offset;
/* If the headers are excessively large, then we must
* fall back to a software checksum */
- if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
+ if (unlikely(!mss && (cksum_offset > 255 ||
+ pseudo_hdr_offset > 127))) {
if (skb_checksum_help(skb))
goto drop;
cksum_offset = 0;
@@ -2184,9 +2211,18 @@ again:
/* negative cum_len signifies to the
* send loop that we are still in the
* header portion of the TSO packet.
- * TSO header must be at most 134 bytes long */
+ * TSO header can be at most 1KB long */
cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
+ /* for IPv6 TSO, the checksum offset stores the
+ * TCP header length, to save the firmware from
+ * the need to parse the headers */
+ if (skb_is_gso_v6(skb)) {
+ cksum_offset = tcp_hdrlen(skb);
+ /* Can only handle headers <= max_tso6 long */
+ if (unlikely(-cum_len > mgp->max_tso6))
+ return myri10ge_sw_tso(skb, dev);
+ }
/* for TSO, pseudo_hdr_offset holds mss.
* The firmware figures out where to put
* the checksum by parsing the header. */
@@ -2301,10 +2337,12 @@ again:
req++;
count++;
rdma_count++;
- if (unlikely(cksum_offset > seglen))
- cksum_offset -= seglen;
- else
- cksum_offset = 0;
+ if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) {
+ if (unlikely(cksum_offset > seglen))
+ cksum_offset -= seglen;
+ else
+ cksum_offset = 0;
+ }
}
if (frag_idx == frag_cnt)
break;
@@ -2387,6 +2425,41 @@ drop:
}
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sk_buff *segs, *curr;
+ struct myri10ge_priv *mgp = dev->priv;
+ int status;
+
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
+ if (unlikely(IS_ERR(segs)))
+ goto drop;
+
+ while (segs) {
+ curr = segs;
+ segs = segs->next;
+ curr->next = NULL;
+ status = myri10ge_xmit(curr, dev);
+ if (status != 0) {
+ dev_kfree_skb_any(curr);
+ if (segs != NULL) {
+ curr = segs;
+ segs = segs->next;
+ curr->next = NULL;
+ dev_kfree_skb_any(segs);
+ }
+ goto drop;
+ }
+ }
+ dev_kfree_skb_any(skb);
+ return 0;
+
+drop:
+ dev_kfree_skb_any(skb);
+ mgp->stats.tx_dropped += 1;
+ return 0;
+}
+
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
@@ -2706,7 +2779,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
}
#ifdef CONFIG_PM
-
static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct myri10ge_priv *mgp;
@@ -2787,7 +2859,6 @@ abort_with_enabled:
return -EIO;
}
-
#endif /* CONFIG_PM */
static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
@@ -2954,8 +3025,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp = netdev_priv(netdev);
mgp->dev = netdev;
- netif_napi_add(netdev, &mgp->napi,
- myri10ge_poll, myri10ge_napi_weight);
+ netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight);
mgp->pdev = pdev;
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
@@ -3077,7 +3147,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->change_mtu = myri10ge_change_mtu;
netdev->set_multicast_list = myri10ge_set_multicast_list;
netdev->set_mac_address = myri10ge_set_mac_address;
- netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ netdev->features = mgp->features;
if (dac_enabled)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index a1d2a22296a..58e57178c56 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -10,7 +10,7 @@ struct mcp_dma_addr {
__be32 low;
};
-/* 4 Bytes */
+/* 4 Bytes. 8 Bytes for NDIS drivers. */
struct mcp_slot {
__sum16 checksum;
__be16 length;
@@ -205,8 +205,87 @@ enum myri10ge_mcp_cmd_type {
/* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
* chipset */
- MXGEFW_CMD_UNALIGNED_STATUS
- /* return data = boolean, true if the chipset is known to be unaligned */
+ MXGEFW_CMD_UNALIGNED_STATUS,
+ /* return data = boolean, true if the chipset is known to be unaligned */
+
+ MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
+ /* data0 = number of big buffers to use. It must be 0 or a power of 2.
+ * 0 indicates that the NIC consumes as many buffers as they are required
+ * for packet. This is the default behavior.
+ * A power of 2 number indicates that the NIC always uses the specified
+ * number of buffers for each big receive packet.
+ * It is up to the driver to ensure that this value is big enough for
+ * the NIC to be able to receive maximum-sized packets.
+ */
+
+ MXGEFW_CMD_GET_MAX_RSS_QUEUES,
+ MXGEFW_CMD_ENABLE_RSS_QUEUES,
+ /* data0 = number of slices n (0, 1, ..., n-1) to enable
+ * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue.
+ * If all queues share one interrupt, the driver must have set
+ * RSS_SHARED_INTERRUPT_DMA before enabling queues.
+ */
+ MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
+ MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
+ /* data0, data1 = bus address lsw, msw */
+ MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+ /* get the offset of the indirection table */
+ MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+ /* set the size of the indirection table */
+ MXGEFW_CMD_GET_RSS_KEY_OFFSET,
+ /* get the offset of the secret key */
+ MXGEFW_CMD_RSS_KEY_UPDATED,
+ /* tell nic that the secret key's been updated */
+ MXGEFW_CMD_SET_RSS_ENABLE,
+ /* data0 = enable/disable rss
+ * 0: disable rss. nic does not distribute receive packets.
+ * 1: enable rss. nic distributes receive packets among queues.
+ * data1 = hash type
+ * 1: IPV4
+ * 2: TCP_IPV4
+ * 3: IPV4 | TCP_IPV4
+ */
+
+ MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ /* Return data = the max. size of the entire headers of a IPv6 TSO packet.
+ * If the header size of a IPv6 TSO packet is larger than the specified
+ * value, then the driver must not use TSO.
+ * This size restriction only applies to IPv6 TSO.
+ * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC
+ * always has enough header buffer to store maximum-sized headers.
+ */
+
+ MXGEFW_CMD_SET_TSO_MODE,
+ /* data0 = TSO mode.
+ * 0: Linux/FreeBSD style (NIC default)
+ * 1: NDIS/NetBSD style
+ */
+
+ MXGEFW_CMD_MDIO_READ,
+ /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
+ MXGEFW_CMD_MDIO_WRITE,
+ /* data0 = dev_addr, data1 = register/addr, data2 = value */
+
+ MXGEFW_CMD_XFP_I2C_READ,
+ /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the
+ * obtained data is cached inside the xaui-xfi chip :
+ * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes,
+ * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ]
+ * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes
+ * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts
+ * will return MXGEFW_CMD_ERROR_BUSY
+ */
+ MXGEFW_CMD_XFP_BYTE,
+ /* Return the last obtained copy of a given byte in the xfp i2c table
+ * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ)
+ * data0 : index of the desired table entry
+ * Return data = the byte stored at the requested index in the table
+ */
+
+ MXGEFW_CMD_GET_VPUMP_OFFSET,
+ /* Return data = NIC memory offset of mcp_vpump_public_global */
+ MXGEFW_CMD_RESET_VPUMP,
+ /* Resets the VPUMP state */
};
enum myri10ge_mcp_cmd_status {
@@ -220,7 +299,10 @@ enum myri10ge_mcp_cmd_status {
MXGEFW_CMD_ERROR_BAD_PORT,
MXGEFW_CMD_ERROR_RESOURCES,
MXGEFW_CMD_ERROR_MULTICAST,
- MXGEFW_CMD_ERROR_UNALIGNED
+ MXGEFW_CMD_ERROR_UNALIGNED,
+ MXGEFW_CMD_ERROR_NO_MDIO,
+ MXGEFW_CMD_ERROR_XFP_FAILURE,
+ MXGEFW_CMD_ERROR_XFP_ABSENT
};
#define MXGEFW_OLD_IRQ_DATA_LEN 40
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 527f9dcc7f6..50e1ec67ef9 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -1576,7 +1576,7 @@ static int netdev_open(struct net_device *dev)
/* Set the timer to check for link beat. */
init_timer(&np->timer);
- np->timer.expires = jiffies + NATSEMI_TIMER_FREQ;
+ np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
np->timer.data = (unsigned long)dev;
np->timer.function = &netdev_timer; /* timer handler */
add_timer(&np->timer);
@@ -1856,7 +1856,11 @@ static void netdev_timer(unsigned long data)
next_tick = 1;
}
}
- mod_timer(&np->timer, jiffies + next_tick);
+
+ if (next_tick > 1)
+ mod_timer(&np->timer, round_jiffies(jiffies + next_tick));
+ else
+ mod_timer(&np->timer, jiffies + next_tick);
}
static void dump_ring(struct net_device *dev)
@@ -3310,13 +3314,19 @@ static int natsemi_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct netdev_private *np = netdev_priv(dev);
+ int ret = 0;
rtnl_lock();
if (netif_device_present(dev))
goto out;
if (netif_running(dev)) {
BUG_ON(!np->hands_off);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "pci_enable_device() failed: %d\n", ret);
+ goto out;
+ }
/* pci_power_on(pdev); */
napi_enable(&np->napi);
@@ -3331,12 +3341,12 @@ static int natsemi_resume (struct pci_dev *pdev)
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
- mod_timer(&np->timer, jiffies + 1*HZ);
+ mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ));
}
netif_device_attach(dev);
out:
rtnl_unlock();
- return 0;
+ return ret;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 368f2560856..fbc7531d3c7 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -93,7 +93,7 @@ static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr
bus_width = *(volatile unsigned char *)ABWCR;
bus_width &= 1 << ((base_addr >> 21) & 7);
- for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_offset); i++)
if (bus_width == 0)
reg_offset[i] = i * 2 + 1;
else
@@ -115,7 +115,7 @@ static int h8300_ne_irq[] = {EXT_IRQ5};
static inline int init_dev(struct net_device *dev)
{
- if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) {
+ if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) {
dev->base_addr = h8300_ne_base[h8300_ne_count];
dev->irq = h8300_ne_irq[h8300_ne_count];
h8300_ne_count++;
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 09768524511..3edc971d0ec 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -183,7 +183,7 @@ static struct card {
short addr_offset;
unsigned char *vendor_id;
char *cardname;
- long config;
+ unsigned long config;
} cards[] = {
{
.id0 = NI65_ID0,
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 43bfe7e6b6f..ed1f9bbb2a3 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -6123,19 +6123,19 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
val = nr64(ESPC_PHY_TYPE);
switch (np->port) {
case 0:
- val = (val & ESPC_PHY_TYPE_PORT0) >>
+ val8 = (val & ESPC_PHY_TYPE_PORT0) >>
ESPC_PHY_TYPE_PORT0_SHIFT;
break;
case 1:
- val = (val & ESPC_PHY_TYPE_PORT1) >>
+ val8 = (val & ESPC_PHY_TYPE_PORT1) >>
ESPC_PHY_TYPE_PORT1_SHIFT;
break;
case 2:
- val = (val & ESPC_PHY_TYPE_PORT2) >>
+ val8 = (val & ESPC_PHY_TYPE_PORT2) >>
ESPC_PHY_TYPE_PORT2_SHIFT;
break;
case 3:
- val = (val & ESPC_PHY_TYPE_PORT3) >>
+ val8 = (val & ESPC_PHY_TYPE_PORT3) >>
ESPC_PHY_TYPE_PORT3_SHIFT;
break;
default:
@@ -6143,9 +6143,9 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
np->port);
return -EINVAL;
}
- niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val);
+ niudbg(PROBE, "SPROM: PHY type %x\n", val8);
- switch (val) {
+ switch (val8) {
case ESPC_PHY_TYPE_1G_COPPER:
/* 1G copper, MII */
np->flags &= ~(NIU_FLAGS_FIBER |
@@ -6175,8 +6175,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
break;
default:
- dev_err(np->device, PFX "Bogus SPROM phy type %llu\n",
- (unsigned long long) val);
+ dev_err(np->device, PFX "Bogus SPROM phy type %u\n", val8);
return -EINVAL;
}
@@ -6213,7 +6212,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
val = nr64(ESPC_MOD_STR_LEN);
niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n",
(unsigned long long) val);
- if (val > 8 * 4)
+ if (val >= 8 * 4)
return -EINVAL;
for (i = 0; i < val; i += 4) {
@@ -6229,7 +6228,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
val = nr64(ESPC_BD_MOD_STR_LEN);
niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n",
(unsigned long long) val);
- if (val > 4 * 4)
+ if (val >= 4 * 4)
return -EINVAL;
for (i = 0; i < val; i += 4) {
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 14361e88541..c65199df8a7 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -97,13 +97,16 @@ static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
&lp->evm_saa9730_regs->InterruptBlock1);
}
-static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
+static void __used show_saa9730_regs(struct net_device *dev)
{
+ struct lan_saa9730_private *lp = netdev_priv(dev);
int i, j;
+
printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]);
printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]);
printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]);
printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]);
+
for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
printk("TxmBuffer[%d][%d] = %x\n", i, j,
@@ -146,11 +149,13 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
readl(&lp->lan_saa9730_regs->RxCtl));
printk("lp->lan_saa9730_regs->RxStatus = %x\n",
readl(&lp->lan_saa9730_regs->RxStatus));
+
for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
writel(i, &lp->lan_saa9730_regs->CamAddress);
printk("lp->lan_saa9730_regs->CamData = %x\n",
readl(&lp->lan_saa9730_regs->CamData));
}
+
printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets);
printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors);
printk("dev->stats.tx_aborted_errors = %lx\n",
@@ -855,7 +860,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev)
/* Transmitter timeout, serious problems */
dev->stats.tx_errors++;
printk("%s: transmit timed out, reset\n", dev->name);
- /*show_saa9730_regs(lp); */
+ /*show_saa9730_regs(dev); */
lan_saa9730_restart(lp);
dev->trans_start = jiffies;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 0a320346541..7967240534d 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -52,7 +52,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.18"
+#define DRV_VERSION "1.19"
#define PFX DRV_NAME " "
/*
@@ -296,10 +296,10 @@ static const u16 copper_fc_adv[] = {
/* flow control to advertise bits when using 1000BaseX */
static const u16 fiber_fc_adv[] = {
- [FC_BOTH] = PHY_M_P_BOTH_MD_X,
+ [FC_NONE] = PHY_M_P_NO_PAUSE_X,
[FC_TX] = PHY_M_P_ASYM_MD_X,
[FC_RX] = PHY_M_P_SYM_MD_X,
- [FC_NONE] = PHY_M_P_NO_PAUSE_X,
+ [FC_BOTH] = PHY_M_P_BOTH_MD_X,
};
/* flow control to GMA disable bits */
@@ -606,20 +606,19 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
{
struct pci_dev *pdev = hw->pdev;
u32 reg1;
- static const u32 phy_power[]
- = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
-
- /* looks like this XL is back asswards .. */
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- onoff = !onoff;
+ static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+ static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+ /* Turn on/off phy power saving */
if (onoff)
- /* Turn off phy power saving */
reg1 &= ~phy_power[port];
else
reg1 |= phy_power[port];
+ if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ reg1 |= coma_mode[port];
+
pci_write_config_dword(pdev, PCI_DEV_REG1, reg1);
pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
@@ -1636,8 +1635,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
- sky2->net_stats.tx_packets++;
- sky2->net_stats.tx_bytes += re->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += re->skb->len;
dev_kfree_skb_any(re->skb);
sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
@@ -2205,16 +2204,16 @@ resubmit:
len_error:
/* Truncation of overlength packets
causes PHY length to not match MAC length */
- ++sky2->net_stats.rx_length_errors;
+ ++dev->stats.rx_length_errors;
if (netif_msg_rx_err(sky2) && net_ratelimit())
pr_info(PFX "%s: rx length error: status %#x length %d\n",
dev->name, status, length);
goto resubmit;
error:
- ++sky2->net_stats.rx_errors;
+ ++dev->stats.rx_errors;
if (status & GMR_FS_RX_FF_OV) {
- sky2->net_stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
goto resubmit;
}
@@ -2223,11 +2222,11 @@ error:
dev->name, status, length);
if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
- sky2->net_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & GMR_FS_FRAGMENT)
- sky2->net_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & GMR_FS_CRC_ERR)
- sky2->net_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
goto resubmit;
}
@@ -2272,7 +2271,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
++rx[port];
skb = sky2_receive(dev, length, status);
if (unlikely(!skb)) {
- sky2->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -2287,8 +2286,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
}
skb->protocol = eth_type_trans(skb, dev);
- sky2->net_stats.rx_packets++;
- sky2->net_stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2479,12 +2478,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
gma_read16(hw, port, GM_TX_IRQ_SRC);
if (status & GM_IS_RX_FF_OR) {
- ++sky2->net_stats.rx_fifo_errors;
+ ++dev->stats.rx_fifo_errors;
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
- ++sky2->net_stats.tx_fifo_errors;
+ ++dev->stats.tx_fifo_errors;
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
}
}
@@ -3223,12 +3222,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-static struct net_device_stats *sky2_get_stats(struct net_device *dev)
-{
- struct sky2_port *sky2 = netdev_priv(dev);
- return &sky2->net_stats;
-}
-
static int sky2_set_mac_address(struct net_device *dev, void *p)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -3569,20 +3562,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
{
const struct sky2_port *sky2 = netdev_priv(dev);
const void __iomem *io = sky2->hw->regs;
+ unsigned int b;
regs->version = 1;
- memset(p, 0, regs->len);
-
- memcpy_fromio(p, io, B3_RAM_ADDR);
- /* skip diagnostic ram region */
- memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+ for (b = 0; b < 128; b++) {
+ /* This complicated switch statement is to make sure and
+ * only access regions that are unreserved.
+ * Some blocks are only valid on dual port cards.
+ * and block 3 has some special diagnostic registers that
+ * are poison.
+ */
+ switch (b) {
+ case 3:
+ /* skip diagnostic ram region */
+ memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
+ break;
- /* copy GMAC registers */
- memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
- if (sky2->hw->ports > 1)
- memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
+ /* dual port cards only */
+ case 5: /* Tx Arbiter 2 */
+ case 9: /* RX2 */
+ case 14 ... 15: /* TX2 */
+ case 17: case 19: /* Ram Buffer 2 */
+ case 22 ... 23: /* Tx Ram Buffer 2 */
+ case 25: /* Rx MAC Fifo 1 */
+ case 27: /* Tx MAC Fifo 2 */
+ case 31: /* GPHY 2 */
+ case 40 ... 47: /* Pattern Ram 2 */
+ case 52: case 54: /* TCP Segmentation 2 */
+ case 112 ... 116: /* GMAC 2 */
+ if (sky2->hw->ports == 1)
+ goto reserved;
+ /* fall through */
+ case 0: /* Control */
+ case 2: /* Mac address */
+ case 4: /* Tx Arbiter 1 */
+ case 7: /* PCI express reg */
+ case 8: /* RX1 */
+ case 12 ... 13: /* TX1 */
+ case 16: case 18:/* Rx Ram Buffer 1 */
+ case 20 ... 21: /* Tx Ram Buffer 1 */
+ case 24: /* Rx MAC Fifo 1 */
+ case 26: /* Tx MAC Fifo 1 */
+ case 28 ... 29: /* Descriptor and status unit */
+ case 30: /* GPHY 1*/
+ case 32 ... 39: /* Pattern Ram 1 */
+ case 48: case 50: /* TCP Segmentation 1 */
+ case 56 ... 60: /* PCI space */
+ case 80 ... 84: /* GMAC 1 */
+ memcpy_fromio(p, io, 128);
+ break;
+ default:
+reserved:
+ memset(p, 0, 128);
+ }
+ p += 128;
+ io += 128;
+ }
}
/* In order to do Jumbo packets on these chips, need to turn off the
@@ -3934,7 +3971,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
dev->stop = sky2_down;
dev->do_ioctl = sky2_ioctl;
dev->hard_start_xmit = sky2_xmit_frame;
- dev->get_stats = sky2_get_stats;
dev->set_multicast_list = sky2_set_multicast;
dev->set_mac_address = sky2_set_mac_address;
dev->change_mtu = sky2_change_mtu;
@@ -4360,7 +4396,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
if (!hw)
return;
- napi_disable(&hw->napi);
+ del_timer_sync(&hw->watchdog_timer);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index f4a3c2f403e..49ee264064a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2031,8 +2031,6 @@ struct sky2_port {
#ifdef CONFIG_SKY2_DEBUG
struct dentry *debugfs;
#endif
- struct net_device_stats net_stats;
-
};
struct sky2_hw {
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index a679f4310ce..8038f2882c9 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1461,7 +1461,6 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
}
return IRQ_NONE;
#else
- struct tc35815_local *lp = dev->priv;
int handled;
u32 status;
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 8d04654f0c5..4e1b84e6d66 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -1906,7 +1906,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/************** pci *****************/
if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */
- RET(err); /* it's not a problem though */
+ goto err_pci; /* it's not a problem though */
if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
!(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
@@ -2076,6 +2076,7 @@ err_out_res:
pci_release_regions(pdev);
err_dma:
pci_disable_device(pdev);
+err_pci:
vfree(nic);
RET(err);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index a402b5c0189..014dc2cfe4d 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.83"
-#define DRV_MODULE_RELDATE "October 10, 2007"
+#define DRV_MODULE_VERSION "3.84"
+#define DRV_MODULE_RELDATE "October 12, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
tg3_tx(tp);
if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
- return 0;
+ return work_done;
}
/* run RX thread, within the bounds set by NAPI.
@@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
{
struct tg3 *tp = container_of(napi, struct tg3, napi);
int work_done = 0;
+ struct tg3_hw_status *sblk = tp->hw_status;
while (1) {
work_done = tg3_poll_work(tp, work_done, budget);
@@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget)
if (unlikely(work_done >= budget))
break;
- if (likely(!tg3_has_work(tp))) {
- struct tg3_hw_status *sblk = tp->hw_status;
-
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
- tp->last_tag = sblk->status_tag;
- rmb();
- } else
- sblk->status &= ~SD_STATUS_UPDATED;
+ if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ /* tp->last_tag is used in tg3_restart_ints() below
+ * to tell the hw how much work has been processed,
+ * so we must read it before checking for more work.
+ */
+ tp->last_tag = sblk->status_tag;
+ rmb();
+ } else
+ sblk->status &= ~SD_STATUS_UPDATED;
+ if (likely(!tg3_has_work(tp))) {
netif_rx_complete(tp->dev, napi);
tg3_restart_ints(tp);
break;
@@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget)
return work_done;
tx_recovery:
+ /* work_done is guaranteed to be less than budget. */
netif_rx_complete(tp->dev, napi);
schedule_work(&tp->reset_task);
- return 0;
+ return work_done;
}
static void tg3_irq_quiesce(struct tg3 *tp)
@@ -5052,6 +5056,12 @@ static void tg3_restore_pci_state(struct tg3 *tp)
pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+ if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
+ pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+ tp->pci_cacheline_sz);
+ pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+ tp->pci_lat_timer);
+ }
/* Make sure PCI-X relaxed ordering bit is clear. */
if (tp->pcix_cap) {
u16 pcix_cmd;
@@ -6985,9 +6995,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
break;
};
- /* Write our heartbeat update interval to APE. */
- tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
- APE_HOST_HEARTBEAT_INT_DISABLE);
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ /* Write our heartbeat update interval to APE. */
+ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
+ APE_HOST_HEARTBEAT_INT_DISABLE);
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
@@ -9029,7 +9040,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
int i;
u32 j;
- for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+ for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
for (j = 0; j < len; j += 4) {
u32 val;
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 9b9cd83fb8b..41f34bb91ca 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1041,7 +1041,7 @@ static struct InfoLeaf infoleaf_array[] = {
{DC21142, dc21142_infoleaf},
{DC21143, dc21143_infoleaf}
};
-#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+#define INFOLEAF_SIZE ARRAY_SIZE(infoleaf_array)
/*
** List the SROM info block functions
@@ -1056,7 +1056,7 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
compact_infoblock
};
-#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
+#define COMPACT (ARRAY_SIZE(dc_infoblock) - 1)
/*
** Miscellaneous defines...
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index 12af0cc037f..9fb8d7f0799 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -1017,4 +1017,4 @@ struct de4x5_ioctl {
#define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
-#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index ee08292bcf8..e5e2c9c4ebf 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -292,6 +292,7 @@ static void tulip_up(struct net_device *dev)
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int next_tick = 3*HZ;
+ u32 reg;
int i;
#ifdef CONFIG_TULIP_NAPI
@@ -307,14 +308,14 @@ static void tulip_up(struct net_device *dev)
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
iowrite32(0x00000001, ioaddr + CSR0);
- pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg); /* flush write */
udelay(100);
/* Deassert reset.
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
iowrite32(tp->csr0, ioaddr + CSR0);
- pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg); /* flush write */
udelay(100);
if (tulip_debug > 1)
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index d00e7d41f6a..bec413ba9bc 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -63,7 +63,7 @@
#define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1
void uec_set_ethtool_ops(struct net_device *netdev);
-
+
static DEFINE_SPINLOCK(ugeth_lock);
static struct {
@@ -3454,9 +3454,12 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
u16 length, howmany = 0;
u32 bd_status;
u8 *bdBuffer;
+ struct net_device * dev;
ugeth_vdbg("%s: IN", __FUNCTION__);
+ dev = ugeth->dev;
+
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 26058b4f8f3..ff37bf437a9 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -154,8 +154,8 @@ struct cosa_data {
int nchannels; /* # of channels on this card */
int driver_status; /* For communicating with firmware */
int firmware_status; /* Downloaded, reseted, etc. */
- long int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */
- long int rxtx; /* RX or TX in progress? */
+ unsigned long rxbitmap, txbitmap;/* Bitmap of channels who are willing to send/receive data */
+ unsigned long rxtx; /* RX or TX in progress? */
int enabled;
int usage; /* usage count */
int txchan, txsize, rxsize;
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index b39a541b250..05df0a345b6 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -1342,11 +1342,11 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map)
if (flp->initialized)
return(-EINVAL);
- for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+ for(i=0; i < ARRAY_SIZE(valid_port); i++)
if (valid_port[i] == map->base_addr)
break;
- if (i == sizeof(valid_port) / sizeof(int))
+ if (i == ARRAY_SIZE(valid_port))
return(-EINVAL);
if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
@@ -1487,12 +1487,12 @@ got_type:
}
}
- for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+ for(i=0; i < ARRAY_SIZE(valid_mem); i++)
if (valid_mem[i] == map->mem_start)
break;
err = -EINVAL;
- if (i == sizeof(valid_mem) / sizeof(int))
+ if (i == ARRAY_SIZE(valid_mem))
goto fail2;
if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index 5f7ffa0a76c..3d4ed647c31 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -26,6 +26,7 @@
*/
#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/types.h>
#include "b43.h"
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
index 34a44c1b631..3488f2447bb 100644
--- a/drivers/net/wireless/b43/pio.h
+++ b/drivers/net/wireless/b43/pio.h
@@ -4,6 +4,7 @@
#include "b43.h"
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/list.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
index fcb777383e7..f4faff6a7d6 100644
--- a/drivers/net/wireless/b43/sysfs.c
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -23,13 +23,14 @@
*/
+#include <linux/capability.h>
+#include <linux/io.h>
+
#include "b43.h"
#include "sysfs.h"
#include "main.h"
#include "phy.h"
-#include <linux/capability.h>
-
#define GENERIC_FILESIZE 64
static int get_integer(const char *buf, size_t count)
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index c27b2c1c06a..e6516a186d0 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -661,7 +661,7 @@ struct local_info {
#define HOSTAP_BITS_TRANSMIT 0
#define HOSTAP_BITS_BAP_TASKLET 1
#define HOSTAP_BITS_BAP_TASKLET2 2
- long bits;
+ unsigned long bits;
struct ap_data *ap;
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h
index bd73ebf0334..1e23b7f4cca 100644
--- a/drivers/net/wireless/ray_cs.h
+++ b/drivers/net/wireless/ray_cs.h
@@ -33,8 +33,8 @@ typedef struct ray_dev_t {
void __iomem *rmem; /* pointer to receive buffer window */
struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */
struct timer_list timer;
- long tx_ccs_lock;
- long ccs_lock;
+ unsigned long tx_ccs_lock;
+ unsigned long ccs_lock;
int dl_param_ccs;
union {
struct b4_startup_params b4;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index f464b82c7d5..7fd505cc4f7 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -74,22 +74,12 @@ struct netfront_info {
struct napi_struct napi;
- struct xen_netif_tx_front_ring tx;
- struct xen_netif_rx_front_ring rx;
-
- spinlock_t tx_lock;
- spinlock_t rx_lock;
-
unsigned int evtchn;
+ struct xenbus_device *xbdev;
- /* Receive-ring batched refills. */
-#define RX_MIN_TARGET 8
-#define RX_DFL_MIN_TARGET 64
-#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
- unsigned rx_min_target, rx_max_target, rx_target;
- struct sk_buff_head rx_batch;
-
- struct timer_list rx_refill_timer;
+ spinlock_t tx_lock;
+ struct xen_netif_tx_front_ring tx;
+ int tx_ring_ref;
/*
* {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
@@ -108,14 +98,23 @@ struct netfront_info {
grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
unsigned tx_skb_freelist;
+ spinlock_t rx_lock ____cacheline_aligned_in_smp;
+ struct xen_netif_rx_front_ring rx;
+ int rx_ring_ref;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+ unsigned rx_min_target, rx_max_target, rx_target;
+ struct sk_buff_head rx_batch;
+
+ struct timer_list rx_refill_timer;
+
struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
grant_ref_t gref_rx_head;
grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
- struct xenbus_device *xbdev;
- int tx_ring_ref;
- int rx_ring_ref;
-
unsigned long rx_pfn_array[NET_RX_RING_SIZE];
struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
struct mmu_update rx_mmu[NET_RX_RING_SIZE];
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 1c97e7dd130..2b5352a7dff 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -3,12 +3,9 @@
#include <linux/module.h>
#include "pci.h"
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pci_dev *pdev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp,
if (!pdev)
return -ENODEV;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_CLASS=%04X", pdev->class))
+ if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+ if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+ if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SLOT_NAME=%s", pci_name(pdev)))
+ if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+ if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
(u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
(u8)(pdev->class)))
return -ENOMEM;
-
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 2305cc450a4..a96b739b2d3 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
* slot. */
bus->number = tbus;
pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
- PCI_REVISION_ID, &work);
+ PCI_CLASS_REVISION, &work);
if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
pci_bus_read_config_dword(bus,
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 37d72f123a8..3ef0a4875a6 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -37,6 +37,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func
u8 behind_bridge, struct resource_lists *resources);
static void interrupt_event_handler(struct controller *ctrl);
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending; /* = 0 */
-/* things needed for the long_delay function */
-static struct semaphore delay_sem;
-static wait_queue_head_t delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending; /* = 0 */
/* delay is in jiffies to wait for */
static void long_delay(int delay)
{
- DECLARE_WAITQUEUE(wait, current);
-
- /* only allow 1 customer into the delay queue at once
- * yes this makes some people wait even longer, but who really cares?
- * this is for _huge_ delays to make the hardware happy as the
- * signals bounce around
+ /*
+ * XXX(hch): if someone is bored please convert all callers
+ * to call msleep_interruptible directly. They really want
+ * to specify timeouts in natural units and spend a lot of
+ * effort converting them to jiffies..
*/
- down (&delay_sem);
-
- init_waitqueue_head(&delay_wait);
-
- add_wait_queue(&delay_wait, &wait);
msleep_interruptible(jiffies_to_msecs(delay));
- remove_wait_queue(&delay_wait, &wait);
-
- up(&delay_sem);
}
@@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
}
if (schedule_flag) {
- up(&event_semaphore);
- dbg("Signal event_semaphore\n");
+ wake_up_process(cpqhp_event_thread);
+ dbg("Waking even thread");
}
return IRQ_HANDLED;
}
@@ -973,16 +960,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
struct pci_func *new_slot;
struct pci_func *next;
- new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+ new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
if (new_slot == NULL) {
/* I'm not dead yet!
* You will be. */
return new_slot;
}
- memset(new_slot, 0, sizeof(struct pci_func));
-
new_slot->next = NULL;
new_slot->configured = 1;
@@ -1738,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control
static void pushbutton_helper_thread(unsigned long data)
{
pushbutton_pending = data;
- up(&event_semaphore);
+ wake_up_process(cpqhp_event_thread);
}
@@ -1747,13 +1731,13 @@ static int event_thread(void* data)
{
struct controller *ctrl;
- daemonize("phpd_event");
-
while (1) {
dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished) break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ if (kthread_should_stop())
+ break;
/* Do stuff here */
if (pushbutton_pending)
cpqhp_pushbutton_thread(pushbutton_pending);
@@ -1762,38 +1746,24 @@ static int event_thread(void* data)
interrupt_event_handler(ctrl);
}
dbg("event_thread signals exit\n");
- up(&event_exit);
return 0;
}
-
int cpqhp_event_start_thread(void)
{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX(&delay_sem);
- init_MUTEX_LOCKED(&event_semaphore);
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- pid = kernel_thread(event_thread, NULL, 0);
- if (pid < 0) {
+ cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+ if (IS_ERR(cpqhp_event_thread)) {
err ("Can't start up our event thread\n");
- return -1;
+ return PTR_ERR(cpqhp_event_thread);
}
- dbg("Our event thread pid = %d\n", pid);
+
return 0;
}
void cpqhp_event_stop_thread(void)
{
- event_finished = 1;
- dbg("event_thread finish command given\n");
- up(&event_semaphore);
- dbg("wait for event_thread to exit\n");
- down(&event_exit);
+ kthread_stop(cpqhp_event_thread);
}
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index d06ccb69e41..c31e7bf3450 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -35,7 +35,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-
+#include <linux/kthread.h>
#include "ibmphp.h"
static int to_debug = 0;
@@ -101,12 +101,11 @@ static int to_debug = 0;
//----------------------------------------------------------------------------
// global variables
//----------------------------------------------------------------------------
-static int ibmphp_shutdown;
-static int tid_poll;
static struct mutex sem_hpcaccess; // lock access to HPC
static struct semaphore semOperations; // lock all operations and
// access to data structures
static struct semaphore sem_exit; // make sure polling thread goes away
+static struct task_struct *ibmphp_poll_thread;
//----------------------------------------------------------------------------
// local function prototypes
//----------------------------------------------------------------------------
@@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8);
static u8 hpc_readcmdtoindex (u8, u8);
static void get_hpc_access (void);
static void free_hpc_access (void);
-static void poll_hpc (void);
+static int poll_hpc(void *data);
static int process_changeinstatus (struct slot *, struct slot *);
static int process_changeinlatch (u8, u8, struct controller *);
-static int hpc_poll_thread (void *);
static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
//----------------------------------------------------------------------------
@@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void)
init_MUTEX (&semOperations);
init_MUTEX_LOCKED (&sem_exit);
to_debug = 0;
- ibmphp_shutdown = 0;
- tid_poll = 0;
debug ("%s - Exit\n", __FUNCTION__);
}
@@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void)
#define POLL_LATCH_REGISTER 0
#define POLL_SLOTS 1
#define POLL_SLEEP 2
-static void poll_hpc (void)
+static int poll_hpc(void *data)
{
struct slot myslot;
struct slot *pslot = NULL;
@@ -833,10 +829,7 @@ static void poll_hpc (void)
debug ("%s - Entry\n", __FUNCTION__);
- while (!ibmphp_shutdown) {
- if (ibmphp_shutdown)
- break;
-
+ while (!kthread_should_stop()) {
/* try to get the lock to do some kind of hardware access */
down (&semOperations);
@@ -896,7 +889,7 @@ static void poll_hpc (void)
up (&semOperations);
msleep(POLL_INTERVAL_SEC * 1000);
- if (ibmphp_shutdown)
+ if (kthread_should_stop())
break;
down (&semOperations);
@@ -915,6 +908,7 @@ static void poll_hpc (void)
}
up (&sem_exit);
debug ("%s - Exit\n", __FUNCTION__);
+ return 0;
}
@@ -1050,47 +1044,20 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
}
/*----------------------------------------------------------------------
-* Name: hpc_poll_thread
-*
-* Action: polling
-*
-* Return 0
-* Value:
-*---------------------------------------------------------------------*/
-static int hpc_poll_thread (void *data)
-{
- debug ("%s - Entry\n", __FUNCTION__);
-
- daemonize("hpc_poll");
- allow_signal(SIGKILL);
-
- poll_hpc ();
-
- tid_poll = 0;
- debug ("%s - Exit\n", __FUNCTION__);
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
* Name: ibmphp_hpc_start_poll_thread
*
* Action: start polling thread
*---------------------------------------------------------------------*/
int __init ibmphp_hpc_start_poll_thread (void)
{
- int rc = 0;
-
debug ("%s - Entry\n", __FUNCTION__);
- tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
- if (tid_poll < 0) {
+ ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
+ if (IS_ERR(ibmphp_poll_thread)) {
err ("%s - Error, thread not started\n", __FUNCTION__);
- rc = -1;
+ return PTR_ERR(ibmphp_poll_thread);
}
-
- debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
- return rc;
+ return 0;
}
/*----------------------------------------------------------------------
@@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void)
{
debug ("%s - Entry\n", __FUNCTION__);
- ibmphp_shutdown = 1;
+ kthread_stop(ibmphp_poll_thread);
debug ("before locking operations \n");
ibmphp_lock_operations ();
debug ("after locking operations \n");
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index bd433ef6bfc..01c351c176a 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -689,71 +689,9 @@ int pci_hp_deregister (struct hotplug_slot *slot)
int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
struct hotplug_slot_info *info)
{
- int retval;
-
if ((slot == NULL) || (info == NULL))
return -ENODEV;
- /*
- * check all fields in the info structure, and update timestamps
- * for the files referring to the fields that have now changed.
- */
- if ((has_power_file(slot) == 0) &&
- (slot->info->power_status != info->power_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_power.attr);
- if (retval)
- return retval;
- }
-
- if ((has_attention_file(slot) == 0) &&
- (slot->info->attention_status != info->attention_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_attention.attr);
- if (retval)
- return retval;
- }
-
- if ((has_latch_file(slot) == 0) &&
- (slot->info->latch_status != info->latch_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_latch.attr);
- if (retval)
- return retval;
- }
-
- if ((has_adapter_file(slot) == 0) &&
- (slot->info->adapter_status != info->adapter_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_presence.attr);
- if (retval)
- return retval;
- }
-
- if ((has_address_file(slot) == 0) &&
- (slot->info->address != info->address)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_address.attr);
- if (retval)
- return retval;
- }
-
- if ((has_max_bus_speed_file(slot) == 0) &&
- (slot->info->max_bus_speed != info->max_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
- if (retval)
- return retval;
- }
-
- if ((has_cur_bus_speed_file(slot) == 0) &&
- (slot->info->cur_bus_speed != info->cur_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
- if (retval)
- return retval;
- }
-
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
return 0;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index e5d3f0b4f45..6462ac3b405 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
hotplug_slot->info->attention_status = status;
-
- if (ATTN_LED(slot->ctrl->ctrlcap))
+
+ if (ATTN_LED(slot->ctrl->ctrlcap))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_max_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
struct slot *t_slot;
u8 value;
struct pci_dev *pdev;
-
+
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
err("%s : out of memory\n", __FUNCTION__);
@@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev)
#ifdef CONFIG_PM
static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
static int pciehp_resume (struct pcie_device *dev)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
#endif
-static struct pcie_port_service_id port_pci_ids[] = { {
- .vendor = PCI_ANY_ID,
+static struct pcie_port_service_id port_pci_ids[] = { {
+ .vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.port_type = PCIE_ANY_PORT,
.service_type = PCIE_PORT_SERVICE_HP,
- .driver_data = 0,
+ .driver_data = 0,
}, { /* end: all zeroes */ }
};
static const char device_name[] = "hpdriver";
@@ -540,10 +540,6 @@ static int __init pcied_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- pciehp_poll_mode = 1;
-#endif
-
retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 98e541ffef3..c8cb49c5a75 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
@@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
- if (pslot->hpc_ops->power_off_slot(pslot)) {
+ if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n",
__FUNCTION__);
return;
@@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
}
if (PWR_LED(ctrl->ctrlcap))
- pslot->hpc_ops->green_led_off(pslot);
+ pslot->hpc_ops->green_led_off(pslot);
if (ATTN_LED(ctrl->ctrlcap)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
@@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot)
if (retval)
return retval;
}
-
+
if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot)
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot)
return -ENODEV;
}
}
-
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __FUNCTION__,
@@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot)
/* Check to see if (latch closed, card present, power on) */
mutex_lock(&p_slot->ctrl->crit_sect);
- if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
+ if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
@@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __FUNCTION__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 016eea94a8a..06d025b8b13 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -39,37 +39,6 @@
#include "../pci.h"
#include "pciehp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
@@ -160,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
/* Link Width Encoding */
#define LNK_X1 0x01
#define LNK_X2 0x02
-#define LNK_X4 0x04
+#define LNK_X4 0x04
#define LNK_X8 0x08
#define LNK_X12 0x0C
-#define LNK_X16 0x10
+#define LNK_X16 0x10
#define LNK_X32 0x20
/*Field definitions of Link Status Register */
@@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define EMI_STATE 0x0080
#define EMI_STATUS_BIT 7
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-
static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -231,14 +198,12 @@ static void int_poll_timeout(unsigned long data)
{
struct controller *ctrl = (struct controller *)data;
- DBG_ENTER_ROUTINE
-
/* Poll for interrupt events. regs == NULL => polling */
pcie_isr(0, ctrl);
init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
- pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+ pciehp_poll_time = 2; /* default polling interval is 2 sec */
start_int_poll_timer(ctrl, pciehp_poll_time);
}
@@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
u16 slot_ctrl;
unsigned long flags;
- DBG_ENTER_ROUTINE
-
mutex_lock(&ctrl->ctrl_lock);
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
@@ -299,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
goto out;
}
- if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
+ if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
/* After 1 sec and CMD_COMPLETED still not set, just
proceed forward to issue the next command according
to spec. Just print out the error message */
@@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
retval = pcie_wait_cmd(ctrl);
out:
mutex_unlock(&ctrl->ctrl_lock);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl)
u16 lnk_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -350,26 +310,22 @@ static int hpc_check_lnk_status(struct controller *ctrl)
}
dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
- if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
+ if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
!(lnk_status & NEG_LINK_WD)) {
err("%s : Link Training Error occurs \n", __FUNCTION__);
retval = -1;
return retval;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -400,7 +356,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -410,8 +365,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -428,35 +381,30 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
*status = 1;
break;
case 1:
- *status = 0;
+ *status = 0;
break;
default:
*status = 0xFF;
break;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
- *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
+ *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -467,8 +415,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
u8 card_state;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
@@ -477,7 +423,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
*status = (card_state == 1) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -488,16 +433,13 @@ static int hpc_query_power_fault(struct slot *slot)
u8 pwr_fault;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-
- DBG_LEAVE_ROUTINE
+
return pwr_fault;
}
@@ -507,8 +449,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s : Cannot check EMI status\n", __FUNCTION__);
@@ -516,7 +456,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
}
*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -526,8 +465,6 @@ static int hpc_toggle_emi(struct slot *slot)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
slot_cmd = EMI_CTRL;
cmd_mask = EMI_CTRL;
if (!pciehp_poll_mode) {
@@ -537,7 +474,7 @@ static int hpc_toggle_emi(struct slot *slot)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
- DBG_LEAVE_ROUTINE
+
return rc;
}
@@ -548,8 +485,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
cmd_mask = ATTN_LED_CTRL;
switch (value) {
case 0 : /* turn off */
@@ -572,19 +507,15 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
+
return rc;
}
-
static void hpc_set_green_led_on(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
@@ -597,8 +528,6 @@ static void hpc_set_green_led_on(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_off(struct slot *slot)
@@ -607,8 +536,6 @@ static void hpc_set_green_led_off(struct slot *slot)
u16 slot_cmd;
u16 cmd_mask;
- DBG_ENTER_ROUTINE
-
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
if (!pciehp_poll_mode) {
@@ -619,9 +546,6 @@ static void hpc_set_green_led_off(struct slot *slot)
pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_blink(struct slot *slot)
@@ -629,8 +553,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
@@ -643,14 +565,10 @@ static void hpc_set_green_led_blink(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_release_ctlr(struct controller *ctrl)
{
- DBG_ENTER_ROUTINE
-
if (pciehp_poll_mode)
del_timer(&ctrl->poll_timer);
else
@@ -662,8 +580,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
-
- DBG_LEAVE_ROUTINE
}
static int hpc_power_on_slot(struct slot * slot)
@@ -674,8 +590,6 @@ static int hpc_power_on_slot(struct slot * slot)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
/* Clear sticky power-fault bit from previous power failures */
@@ -719,8 +633,6 @@ static int hpc_power_on_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -731,8 +643,6 @@ static int hpc_power_off_slot(struct slot * slot)
u16 cmd_mask;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
slot_cmd = POWER_OFF;
@@ -764,8 +674,6 @@ static int hpc_power_off_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -784,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
- intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
- PRSN_DETECT_CHANGED | CMD_COMPLETED );
+ intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+ MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
intr_loc = slot_status & intr_detect;
@@ -807,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
__FUNCTION__, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE &
+ ~CMD_CMPL_INTR_ENABLE) | 0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n",
@@ -825,7 +734,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
}
dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
__FUNCTION__, slot_status);
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -835,10 +744,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
}
-
+
if (intr_loc & CMD_COMPLETED) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
*/
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
@@ -892,7 +801,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
__FUNCTION__);
return IRQ_NONE;
}
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -904,19 +813,17 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
__FUNCTION__, temp_word);
}
-
+
return IRQ_HANDLED;
}
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -934,19 +841,18 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Max link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_max_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -985,19 +891,17 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Max link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -1015,25 +919,24 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Current link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_cur_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
-
+
switch ((lnk_status & 0x03F0) >> 4){
case 0:
lnk_wdth = PCIE_LNK_WIDTH_RESRV;
@@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Current link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -1085,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
.get_max_lnk_width = hpc_get_max_lnk_width,
.get_cur_lnk_width = hpc_get_cur_lnk_width,
-
+
.query_power_fault = hpc_query_power_fault,
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
.check_lnk_status = hpc_check_lnk_status,
};
@@ -1138,6 +1041,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
dbg("Trying to get hotplug control for %s \n",
(char *)string.pointer);
status = pci_osc_control_set(handle,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
if (status == AE_NOT_FOUND)
status = acpi_run_oshp(handle);
@@ -1163,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
}
#endif
-
-
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
int rc;
@@ -1176,8 +1078,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
- DBG_ENTER_ROUTINE
-
pdev = dev->port;
ctrl->pci_dev = pdev; /* save pci_dev in context */
@@ -1201,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: CAPREG offset %x cap_reg %x\n",
__FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
- if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+ if (((cap_reg & SLOT_IMPL) == 0) ||
+ (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
- dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+ dbg("%s : This is not a root port or the port is not "
+ "connected to a slot\n", __FUNCTION__);
goto abort_free_ctlr;
}
@@ -1236,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
- for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+ for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
if (pci_resource_len(pdev, rc) > 0)
dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
(unsigned long long)pci_resource_start(pdev, rc),
(unsigned long long)pci_resource_len(pdev, rc));
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device,
- pdev->subsystem_vendor, pdev->subsystem_device);
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
+ pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
@@ -1267,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL %x value read %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+ 0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
@@ -1330,14 +1234,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
if (ATTN_BUTTN(slot_cap))
intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
+
if (POWER_CTRL(slot_cap))
intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
+
if (MRL_SENS(slot_cap))
intr_enable = intr_enable | MRL_DETECT_ENABLE;
- temp_word = (temp_word & ~intr_enable) | intr_enable;
+ temp_word = (temp_word & ~intr_enable) | intr_enable;
if (pciehp_poll_mode) {
temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
}
- /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+ /*
+ * Unmask Hot-plug Interrupt Enable for the interrupt
+ * notification mechanism case.
+ */
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -1356,14 +1263,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
temp_word = 0x1F; /* Clear all events */
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
if (pciehp_force) {
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
@@ -1375,10 +1282,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->hpc_ops = &pciehp_hpc_ops;
- DBG_LEAVE_ROUTINE
return 0;
- /* We end up here for the many possible ways to fail this API. */
+ /* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
@@ -1395,6 +1301,5 @@ abort_free_irq:
free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 854aaea09e4..c424aded13f 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot)
int pciehp_unconfigure_device(struct slot *p_slot)
{
- int rc = 0;
+ int ret, rc = 0;
int j;
u8 bctl = 0;
+ u8 presence = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
@@ -263,23 +264,28 @@ int pciehp_unconfigure_device(struct slot *p_slot)
continue;
}
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
- if (bctl & PCI_BRIDGE_CTL_VGA) {
- err("Cannot remove display device %s\n",
+ ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+ &presence);
+ if (!ret && presence) {
+ pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+ &bctl);
+ if (bctl & PCI_BRIDGE_CTL_VGA) {
+ err("Cannot remove display device %s\n",
pci_name(temp));
- pci_dev_put(temp);
- continue;
+ pci_dev_put(temp);
+ continue;
+ }
}
}
pci_remove_bus_device(temp);
pci_dev_put(temp);
}
- /*
+ /*
* Some PCI Express root ports require fixup after hot-plug operation.
*/
- if (pcie_mch_quirk)
+ if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
-
+
return rc;
}
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index df076064a3e..a080fedf033 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = {
};
struct kset dlpar_io_kset = {
- .kobj = {.name = DLPAR_KOBJ_NAME,
- .ktype = &ktype_dlpar_io,
+ .kobj = {.ktype = &ktype_dlpar_io,
.parent = &pci_hotplug_slots_subsys.kobj},
.ktype = &ktype_dlpar_io,
};
int dlpar_sysfs_init(void)
{
+ kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
if (kset_register(&dlpar_io_kset)) {
printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
- dlpar_io_kset.kobj.name);
+ kobject_name(&dlpar_io_kset.kobj));
return -EINVAL;
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index be1df85e5e2..87e01615053 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
} else {
msg->address_hi = 0;
- pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
}
msg->data = data;
break;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 004bc248727..6e2760b6c20 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
if (!dynid)
return -ENOMEM;
- INIT_LIST_HEAD(&dynid->node);
dynid->id.vendor = vendor;
dynid->id.device = device;
dynid->id.subvendor = subvendor;
@@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
driver_data : 0UL;
spin_lock(&pdrv->dynids.lock);
- list_add_tail(&pdrv->dynids.list, &dynid->node);
+ list_add_tail(&dynid->node, &pdrv->dynids.list);
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
@@ -532,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev)
}
#ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 37c00f6fd80..71d561fda0a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -17,11 +17,16 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/log2.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
unsigned int pci_pm_d3_delay = 10;
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domains_supported = 1;
+#endif
+
#define DEFAULT_CARDBUS_IO_SIZE (256)
#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -653,7 +658,7 @@ int
pci_restore_state(struct pci_dev *dev)
{
int i;
- int val;
+ u32 val;
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
@@ -1454,7 +1459,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
int cap, err = -EINVAL;
u32 stat, cmd, v, o;
- if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+ if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
goto out;
v = ffs(mmrbc) - 10;
@@ -1526,7 +1531,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
int cap, err = -EINVAL;
u16 ctl, v;
- if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+ if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
goto out;
v = (ffs(rq) - 8) << 12;
@@ -1566,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
return bars;
}
+static void __devinit pci_no_domains(void)
+{
+#ifdef CONFIG_PCI_DOMAINS
+ pci_domains_supported = 0;
+#endif
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1585,6 +1597,10 @@ static int __devinit pci_setup(char *str)
if (*str && (str = pcibios_setup(str)) && *str) {
if (!strcmp(str, "nomsi")) {
pci_no_msi();
+ } else if (!strcmp(str, "noaer")) {
+ pci_no_aer();
+ } else if (!strcmp(str, "nodomains")) {
+ pci_no_domains();
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4c36e80f6d2..6fda33de84e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,7 +1,6 @@
/* Functions internal to the PCI core code */
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
@@ -52,6 +51,12 @@ void pci_restore_msi_state(struct pci_dev *dev);
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
#endif
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+#else
+static inline void pci_no_aer(void) { }
+#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 0ad92a8ad8b..287a9311716 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE
When in doubt, say N.
-config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_PCIE
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index ad90a01b0df..7a62f7dd900 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = {
.reset_link = aer_root_reset,
};
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+ pcie_aer_disable = 1; /* has priority over 'forceload' */
+}
+
/**
* aer_irq - Root Port's ISR
* @irq: IRQ assigned to Root Port
@@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev)
**/
static int __init aer_service_init(void)
{
+ if (pcie_aer_disable)
+ return -ENXIO;
return pcie_port_service_register(&aerdriver);
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 171ca712e52..5db6b6690b5 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
if (sz) {
res->flags = (l & IORESOURCE_ROM_ENABLE) |
- IORESOURCE_MEM | IORESOURCE_PREFETCH |
- IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ IORESOURCE_MEM | IORESOURCE_READONLY;
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz;
}
@@ -597,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
if (!is_cardbus) {
- child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
+ child->bridge_ctl = bctl;
/*
* Adjust subordinate busnr in parent buses.
* We do this before scanning for children because
@@ -744,22 +743,46 @@ static int pci_setup_device(struct pci_dev * dev)
*/
if (class == PCI_CLASS_STORAGE_IDE) {
u8 progif;
+ struct pci_bus_region region;
+
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x1F0,
+ .end = 0x1F7,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[0].start = region.start;
+ dev->resource[0].end = region.end;
+ dev->resource[0].flags = resource.flags;
+ resource.start = 0x3F6;
+ resource.end = 0x3F6;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[1].start = region.start;
+ dev->resource[1].end = region.end;
+ dev->resource[1].flags = resource.flags;
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x170,
+ .end = 0x177,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[2].start = region.start;
+ dev->resource[2].end = region.end;
+ dev->resource[2].flags = resource.flags;
+ resource.start = 0x376;
+ resource.end = 0x376;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[3].start = region.start;
+ dev->resource[3].end = region.end;
+ dev->resource[3].flags = resource.flags;
}
}
break;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 90adc62d07f..716439e25dd 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
*/
if (capable(CAP_SYS_ADMIN))
- size = dev->cfg_size;
+ size = dp->size;
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
else
@@ -129,11 +129,11 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_path.dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
- int size = dev->cfg_size;
+ int size = dp->size;
int cnt;
if (pos >= size)
@@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
}
*ppos = pos;
+ i_size_write(ino, dp->size);
return nbytes;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 50f2dd9e1bb..59d4da2734c 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_
*/
static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
{
- u8 rev;
u32 region;
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
- if (rev & 0x10) {
+ if (dev->revision & 0x10) {
pci_read_config_dword(dev, 0x48, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
@@ -629,12 +627,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
*/
static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
{
- unsigned char revid;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
- if (dev->subordinate && revid <= 0x12) {
+ if (dev->subordinate && dev->revision <= 0x12) {
printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
- "MMRBC\n", revid);
+ "MMRBC\n", dev->revision);
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
}
}
@@ -930,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge );
-/*
- * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled
- * when a PCI-Soundcard is added. The BIOS only gives Options
- * "Disabled" and "AUTO". This Quirk Sets the corresponding
- * Register-Value to enable the Soundcard.
- *
- * FIXME: Presently this quirk will run on anything that has an 8237
- * which isn't correct, we need to check DMI tables or something in
- * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it
- * runs everywhere at present we suppress the printk output in most
- * irrelevant cases.
- */
-static void k8t_sound_hostbridge(struct pci_dev *dev)
-{
- unsigned char val;
-
- pci_read_config_byte(dev, 0x50, &val);
- if (val == 0xc8) {
- /* Assume it's probably a MSI-K8T-Neo2Fir */
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
- pci_write_config_byte(dev, 0x50, val & (~0x40));
-
- /* Verify the Change for Status output */
- pci_read_config_byte(dev, 0x50, &val);
- if (val & 0x40)
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
- else
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5e5191ec8de..401e03c920b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus)
break;
case PCI_CLASS_BRIDGE_PCI:
+ /* don't size subtractive decoding (transparent)
+ * PCI-to-PCI bridges */
+ if (bus->self->transparent)
+ break;
pci_bridge_check_ranges(bus);
+ /* fall through */
default:
pbus_size_io(bus);
/* If the bridge supports prefetchable range, size it
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 568f1877315..05ca2ed9eb5 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev,
dev->irq = irq;
pr_debug("PCI: fixup irq: (%s) got %d\n",
- dev->dev.kobj.name, dev->irq);
+ kobject_name(&dev->dev.kobj), dev->irq);
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index f8b13f0270d..a0aca46ce87 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+ struct kobj_uevent_env *env)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
- int i = 0, length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "SOCKET_NO=%u", s->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index a99607142fc..55baa1f0fcb 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
#ifdef CONFIG_HOTPLUG
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pcmcia_device *p_dev;
- int i, length = 0;
+ int i;
u32 hash[4] = { 0, 0, 0, 0};
if (!dev)
@@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
}
- i = 0;
-
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "SOCKET_NO=%u",
- p_dev->socket->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE_NO=%02X",
- p_dev->device_no))
+ if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
"pa%08Xpb%08Xpc%08Xpd%08X",
p_dev->has_manf_id ? p_dev->manf_id : 0,
p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[3]))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
#else
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 71b33707117..839bb1c0db5 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -101,7 +101,7 @@ static int ignore = -1;
/* Bit map or list of interrupts to choose from */
static u_int irq_mask = 0xffff;
static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq = 0;
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index dd0ddf19ee5..abc10fe49bd 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -58,7 +58,7 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
static int irq_list[16];
-static int irq_list_count = 0;
+static unsigned int irq_list_count = 0;
module_param(irq_mode, int, 0444);
module_param_array(irq_list, int, &irq_list_count, 0444);
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 36c671c5fb6..6fa5eaaab8a 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -157,7 +157,6 @@ static int __init mst_pcmcia_init(void)
if (!mst_pcmcia_device)
return -ENOMEM;
- mst_pcmcia_device->dev.uevent_suppress = 0;
mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
ret = platform_device_add(mst_pcmcia_device);
@@ -177,3 +176,4 @@ fs_initcall(mst_pcmcia_init);
module_exit(mst_pcmcia_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f531b..d5c33bd78d6 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void)
if (!sharpsl_pcmcia_device)
return -ENOMEM;
- sharpsl_pcmcia_device->dev.uevent_suppress = 0;
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
@@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit);
MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index c158cf38b9d..749ac371091 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -90,7 +90,7 @@ static int do_scan = 1;
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xffff;
static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq;
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index a9880d468ee..f38ba482be7 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -14,8 +14,7 @@
extern int power_supply_create_attrs(struct power_supply *psy);
extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
#else
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index de3155b2128..249f61bae63 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp)
return ret;
}
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct power_supply *psy = dev_get_drvdata(dev);
- int i = 0, length = 0, ret = 0, j;
+ int ret = 0, j;
char *prop_buf;
char *attrname;
@@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_NAME=%s", psy->name);
+ ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
if (ret)
return ret;
@@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
@@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
}
- envp[i] = NULL;
out:
free_page((unsigned long)prop_buf);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 93ee05eeaeb..78277a118b6 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -1,7 +1,7 @@
/*
* SuperH On-Chip RTC Support
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006, 2007 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
*
* Based on the old arch/sh/kernel/cpu/rtc.c by:
@@ -23,16 +23,19 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <asm/rtc.h>
#define DRV_NAME "sh-rtc"
-#define DRV_VERSION "0.1.2"
+#define DRV_VERSION "0.1.3"
#ifdef CONFIG_CPU_SH3
#define rtc_reg_size sizeof(u16)
#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+#define RTC_DEF_CAPABILITIES 0UL
#elif defined(CONFIG_CPU_SH4)
#define rtc_reg_size sizeof(u32)
#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR
#endif
#define RTC_REG(r) ((r) * rtc_reg_size)
@@ -80,6 +83,7 @@ struct sh_rtc {
struct rtc_device *rtc_dev;
spinlock_t lock;
int rearm_aie;
+ unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */
};
static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
@@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
-#if defined(CONFIG_CPU_SH4)
- yr = readw(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN(yr >> 8);
- yr &= 0xff;
-#else
- yr = readb(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
-#endif
+ if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+ yr = readw(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN(yr >> 8);
+ yr &= 0xff;
+ } else {
+ yr = readb(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+ }
tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
@@ -375,14 +379,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
-#ifdef CONFIG_CPU_SH3
- year = tm->tm_year % 100;
- writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
-#else
- year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
- BIN2BCD(tm->tm_year % 100);
- writew(year, rtc->regbase + RYRCNT);
-#endif
+ if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+ year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+ BIN2BCD(tm->tm_year % 100);
+ writew(year, rtc->regbase + RYRCNT);
+ } else {
+ year = tm->tm_year % 100;
+ writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+ }
/* Start RTC */
tmp = readb(rtc->regbase + RCR2);
@@ -589,6 +593,17 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
goto err_badmap;
}
+ rtc->capabilities = RTC_DEF_CAPABILITIES;
+ if (pdev->dev.platform_data) {
+ struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data;
+
+ /*
+ * Some CPUs have special capabilities in addition to the
+ * default set. Add those in here.
+ */
+ rtc->capabilities |= pinfo->capabilities;
+ }
+
platform_set_drvdata(pdev, rtc);
return 0;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index aeda5268244..d427daeef51 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -53,6 +53,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
+#include <linux/log2.h>
#include <asm/ccwdev.h>
#include <linux/workqueue.h>
#include <asm/debug.h>
@@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem)
static inline int
dasd_check_blocksize(int bsize)
{
- if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+ if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
return -EMEDIUMTYPE;
return 0;
}
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 0fbacc8b106..f231bc21b1c 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio)
}
}
set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_end_io(bio, 0);
+ bio_endio(bio, 0);
return 0;
fail:
bio_io_error(bio);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6000bdee408..0e1f35c9ed9 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev)
struct raw3215_info *raw;
int line;
+ /* Console is special. */
+ if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+ return 0;
raw = kmalloc(sizeof(struct raw3215_info) +
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
if (raw == NULL)
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fd3479119eb..0b040557db0 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -22,6 +22,7 @@
#include <asm/ebcdic.h>
#include "raw3270.h"
+#include "tty3270.h"
#include "ctrlchar.h"
#define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
spin_unlock_irqrestore(&cp->view.lock,flags);
}
-extern struct tty_driver *tty3270_driver;
-
static struct tty_driver *
con3270_device(struct console *c, int *index)
{
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index fa62e694405..25629b92dec 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t {
#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
@@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-static inline void __sclp_make_read_req(void);
static void
__sclp_queue_read_req(void)
@@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data)
}
/* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
{
struct sccb_header *sccb;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 9f244c591ee..da25f8e2415 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device,
c_info = &TAPE_3590_CRYPT_INFO(device);
- if (sense->masst == MSENSE_UNASSOCIATED) {
+ DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+ switch (sense->macst) {
+ case 0x04:
+ case 0x05:
+ case 0x06:
tape_med_state_set(device, MS_UNLOADED);
TAPE_3590_CRYPT_INFO(device).medium_status = 0;
return;
- }
- if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
- PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ case 0x08:
+ case 0x09:
+ tape_med_state_set(device, MS_LOADED);
+ break;
+ default:
+ tape_med_state_set(device, MS_UNKNOWN);
return;
}
- tape_med_state_set(device, MS_LOADED);
c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
if (sense->flags & MSENSE_CRYPT_MASK) {
PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
/* Probably result of halt ssch */
return TAPE_IO_PENDING;
else if (irb->scsw.dstat == 0x85)
- /* Device Ready -> check medium state */
- tape_3590_schedule_work(device, TO_MSEN);
- else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+ /* Device Ready */
+ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+ else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
tape_3590_schedule_work(device, TO_READ_ATTMSG);
- else {
+ } else {
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
tape_dump_sense(device, NULL, irb);
}
+ /* check medium state */
+ tape_3590_schedule_work(device, TO_MSEN);
return TAPE_IO_SUCCESS;
}
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index bc33068b9ce..70b1980a08b 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
-
#include "raw3270.h"
+#include "tty3270.h"
#include "keyboard.h"
#define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix)
static void
tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
{
- tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
- cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+ int max_cx = max(0, cx);
+ int max_cy = max(0, cy);
+
+ tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+ cy = min_t(int, tp->view.rows - 3, max_cy);
if (cy != tp->cy) {
tty3270_convert_line(tp, tp->cy);
tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644
index 00000000000..799da57f039
--- /dev/null
+++ b/drivers/s390/char/tty3270.h
@@ -0,0 +1,16 @@
+/*
+ * drivers/s390/char/tty3270.h
+ *
+ * Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 680b9b58b80..6f40facb1c4 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout,
"0: la %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
- : "=d" (err) : "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+ : "+d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl) : "1", "cc");
return err;
}
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3712ede1672..7073daf7798 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count)
if (count == 0)
return 0;
- flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+ flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
asm volatile (
"0: mvcle %1,%2,0x0\n"
"1: jo 0b\n"
" lhi %0,0x0\n"
"2:\n"
EX_TABLE(1b,2b)
- : "+d" (rc)
- : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+ : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+ "+d" (_len2), "=m" (*((long*)dest))
+ : "m" (*((long*)src))
: "cc", "memory");
__raw_local_irq_ssm(flags);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index b0a18f5176a..5baa517c3b6 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
return 0;
}
static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
- int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
{
/* TODO */
return 0;
@@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - create and register a ccw group device
+ * @root: parent device for the new device
+ * @creator_id: identifier of creating driver
+ * @cdrv: ccw driver of slave devices
+ * @argc: number of slave devices
+ * @argv: bus ids of slave devices
+ *
+ * Create and register a new ccw group device as a child of @root. Slave
+ * devices are obtained from the list of bus ids given in @argv[] and must all
+ * belong to @cdrv.
+ * Returns:
+ * %0 on success and an error code on failure.
+ * Context:
+ * non-atomic
*/
-int
-ccwgroup_create(struct device *root,
- unsigned int creator_id,
- struct ccw_driver *cdrv,
- int argc, char *argv[])
+int ccwgroup_create(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int argc, char *argv[])
{
struct ccwgroup_device *gdev;
int i;
@@ -390,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = {
.remove = ccwgroup_remove,
};
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
@@ -406,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data)
return 1;
}
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
{
struct device *dev;
@@ -427,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
driver_unregister(&cdriver->driver);
}
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ * always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
{
return 0;
}
@@ -452,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
return NULL;
}
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 920dd71e643..42c1f4659ad 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
#include <linux/jiffies.h>
#include <linux/wait.h>
#include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
#include <asm/chpid.h>
#include <asm/sclp.h>
@@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue;
/* Return channel_path struct for given chpid. */
static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
{
- return css[chpid.cssid]->chps[chpid.id];
+ return channel_subsystems[chpid.cssid]->chps[chpid.id];
}
/* Set vary state for given chpid. */
@@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
opm = 0;
chp_id_init(&chpid);
- for (i=0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
opm <<= 1;
chpid.id = sch->schib.pmcw.chpid[i];
if (chp_get_status(chpid) != 0)
@@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
chpid.id);
- CIO_TRACE_EVENT( 2, dbf_text);
+ CIO_TRACE_EVENT(2, dbf_text);
status = chp_get_status(chpid);
if (!on && !status) {
@@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
if (!chp->cmg_chars)
return 0;
@@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj,
{
struct channel_path *chp;
struct channel_subsystem *css;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
css = to_css(chp->dev.parent);
size = sizeof(struct cmg_entry);
@@ -353,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev,
static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
&dev_attr_status.attr,
&dev_attr_configure.attr,
&dev_attr_type.attr,
@@ -395,7 +399,7 @@ int chp_new(struct chp_id chpid)
/* fill in status, etc. */
chp->chpid = chpid;
chp->state = 1;
- chp->dev.parent = &css[chpid.cssid]->device;
+ chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
chpid.id);
@@ -430,18 +434,18 @@ int chp_new(struct chp_id chpid)
device_unregister(&chp->dev);
goto out_free;
}
- mutex_lock(&css[chpid.cssid]->mutex);
- if (css[chpid.cssid]->cm_enabled) {
+ mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+ if (channel_subsystems[chpid.cssid]->cm_enabled) {
ret = chp_add_cmg_attr(chp);
if (ret) {
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev);
- mutex_unlock(&css[chpid.cssid]->mutex);
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
goto out_free;
}
}
- css[chpid.cssid]->chps[chpid.id] = chp;
- mutex_unlock(&css[chpid.cssid]->mutex);
+ channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
return ret;
out_free:
kfree(chp);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index f2708d65be5..46905345159 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
+ /* clean up possible residual cmf stuff */
+ sch->schib.pmcw.mme = 0;
+ sch->schib.pmcw.mbfc = 0;
+ sch->schib.pmcw.mbi = 0;
+ sch->schib.mba = 0;
return 0;
out:
if (!cio_is_console(schid))
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 34a796913b0..b960f66843e 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -45,7 +45,8 @@
#include "ioasm.h"
#include "chsc.h"
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
* used on any subchannel
* "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@ enum cmb_index {
* enum cmb_format - types of supported measurement block formats
*
* @CMF_BASIC: traditional channel measurement blocks supported
- * by all machines that we run on
+ * by all machines that we run on
* @CMF_EXTENDED: improved format that was introduced with the z990
- * machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- * or later machine, otherwise fall back to basic format
- **/
+ * machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ * supporting extended format, otherwise fall back to
+ * basic format
+ */
enum cmb_format {
CMF_BASIC,
CMF_EXTENDED,
CMF_AUTODETECT = -1,
};
-/**
+
+/*
* format - actual format for all measurement blocks
*
* The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@ module_param(format, bool, 0444);
* either with the help of a special pool or with kmalloc
* @free: free memory allocated with @alloc
* @set: enable or disable measurement
+ * @read: read a measurement entry at an index
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
* @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
- int (*alloc) (struct ccw_device*);
- void(*free) (struct ccw_device*);
- int (*set) (struct ccw_device*, u32);
- u64 (*read) (struct ccw_device*, int);
- int (*readall)(struct ccw_device*, struct cmbdata *);
- void (*reset) (struct ccw_device*);
- void * (*align) (void *);
-
+ int (*alloc) (struct ccw_device *);
+ void (*free) (struct ccw_device *);
+ int (*set) (struct ccw_device *, u32);
+ u64 (*read) (struct ccw_device *, int);
+ int (*readall)(struct ccw_device *, struct cmbdata *);
+ void (*reset) (struct ccw_device *);
+ void *(*align) (void *);
+/* private: */
struct attribute_group *attr_group;
};
static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@ struct cmb_data {
unsigned long long last_update; /* when last_block was updated */
};
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
* while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
static inline u64 time_to_nsec(u32 value)
{
return ((u64)value) * 128000ull;
@@ -159,12 +165,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
return ret;
}
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
* the monitor is deactivated. The channel monitor needs to
* be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
{
register void * __gpr2 asm("2");
register long __gpr1 asm("1");
@@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff)
asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
}
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+ unsigned long address)
{
int ret;
int retry;
@@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev)
*
* @mem: pointer to CMBs (only in basic measurement mode)
* @list: contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
* @lock: protect concurrent access to @mem and @list
*/
struct cmb_area {
@@ -481,28 +489,36 @@ static struct cmb_area cmb_area = {
.num_channels = 1024,
};
-
/* ****** old style CMB handling ********/
-/** int maxchannels
- *
+/*
* Basic channel measurement blocks are allocated in one contiguous
* block of memory, which can not be moved as long as any channel
* is active. Therefore, a maximum number of subchannels needs to
* be defined somewhere. This is a module parameter, defaulting to
* a resonable value of 1024, or 32 kb of memory.
* Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
*/
module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
/**
* struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
+ *
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
*
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
* Only one cmb area can be present in the system.
*/
struct cmb {
@@ -516,8 +532,9 @@ struct cmb {
u32 reserved[2];
};
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
*/
static int alloc_cmb_single(struct ccw_device *cdev,
struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev,
goto out;
}
- /* find first unused cmb in cmb_area.mem.
- * this is a little tricky: cmb_area.list
- * remains sorted by ->cmb->hw_data pointers */
+ /*
+ * Find first unused cmb in cmb_area.mem.
+ * This is a little tricky: cmb_area.list
+ * remains sorted by ->cmb->hw_data pointers.
+ */
cmb = cmb_area.mem;
list_for_each_entry(node, &cmb_area.list, cmb_list) {
struct cmb_data *data;
@@ -558,8 +577,7 @@ out:
return ret;
}
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
{
int ret;
struct cmb *mem;
@@ -670,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
return set_schib_wait(cdev, mme, 0, offset);
}
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
{
struct cmb *cmb;
u32 val;
@@ -720,7 +738,7 @@ out:
return ret;
}
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmb *cmb;
struct cmb_data *cmb_data;
@@ -793,14 +811,25 @@ static struct cmb_operations cmbops_basic = {
.align = align_cmb,
.attr_group = &cmf_attr_group,
};
-
+
/* ******** extended cmb handling ********/
/**
* struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
*
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
* third edition, chapter 17.
*/
struct cmbe {
@@ -816,10 +845,12 @@ struct cmbe {
u32 reserved[7];
};
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
* pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
{
unsigned long addr;
addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -827,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
return (struct cmbe*)addr;
}
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
{
struct cmbe *cmbe;
struct cmb_data *cmb_data;
@@ -873,7 +904,7 @@ out_free:
return ret;
}
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
{
struct cmb_data *cmb_data;
@@ -912,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
}
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -970,7 +1001,7 @@ out:
return ret;
}
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -1047,17 +1078,16 @@ static struct cmb_operations cmbops_extended = {
.align = align_cmbe,
.attr_group = &cmf_attr_group_ext,
};
-
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
{
return sprintf(buf, "%lld\n",
(unsigned long long) cmf_read(to_ccwdev(dev), idx));
}
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct ccw_device *cdev;
long interval;
@@ -1079,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%ld\n", interval);
}
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct cmbdata data;
u64 utilization;
@@ -1112,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
}
#define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
#define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
cmf_attr(ssch_rsch_count);
cmf_attr(sample_count);
@@ -1131,7 +1164,8 @@ cmf_attr_avg(device_active_only_time);
cmf_attr_avg(device_busy_time);
cmf_attr_avg(initial_command_response_time);
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+ NULL);
static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
static struct attribute *cmf_attributes[] = {
@@ -1172,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = {
.attrs = cmf_attributes_ext,
};
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
}
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t c)
{
struct ccw_device *cdev;
int ret;
@@ -1202,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ * @cdev: The ccw device to be enabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1225,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev)
return ret;
}
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ * @cdev: The ccw device to be disabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1238,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev)
return ret;
}
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev: the channel to be read
+ * @index: the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ * Context:
+ * any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
{
return cmbops->read(cdev, index);
}
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev: the channel to be read
+ * @data: a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ * Context:
+ * any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
{
return cmbops->readall(cdev, data);
}
@@ -1257,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev)
return cmbops->set(cdev, 2);
}
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
{
char *format_string;
char *detect_string = "parameter";
- /* We cannot really autoprobe this. If the user did not give a parameter,
- see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+ /*
+ * If the user did not give a parameter, see if we are running on a
+ * machine supporting extended measurement blocks, otherwise fall back
+ * to basic mode.
+ */
if (format == CMF_AUTODETECT) {
if (!css_characteristics_avail ||
!css_general_characteristics.ext_mb) {
@@ -1284,7 +1356,7 @@ init_cmf(void)
cmbops = &cmbops_basic;
break;
case CMF_EXTENDED:
- format_string = "extended";
+ format_string = "extended";
cmbops = &cmbops_extended;
break;
default:
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 5635e656c1a..5d83dd47146 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/list.h>
+#include <linux/reboot.h>
#include "css.h"
#include "cio.h"
@@ -27,7 +28,7 @@ int css_init_done = 0;
static int need_reprobe = 0;
static int max_ssid = 0;
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
@@ -177,7 +178,7 @@ static int css_register_subchannel(struct subchannel *sch)
int ret;
/* Initialize the subchannel structure */
- sch->dev.parent = &css[0]->device;
+ sch->dev.parent = &channel_subsystems[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
sch->dev.groups = subch_attr_groups;
@@ -606,30 +607,55 @@ static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
+ struct channel_subsystem *css;
- memset(css[nr], 0, sizeof(struct channel_subsystem));
- css[nr]->pseudo_subchannel =
- kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
- if (!css[nr]->pseudo_subchannel)
+ css = channel_subsystems[nr];
+ memset(css, 0, sizeof(struct channel_subsystem));
+ css->pseudo_subchannel =
+ kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+ if (!css->pseudo_subchannel)
return -ENOMEM;
- css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
- css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
- sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
- ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ css->pseudo_subchannel->dev.parent = &css->device;
+ css->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css->pseudo_subchannel);
if (ret) {
- kfree(css[nr]->pseudo_subchannel);
+ kfree(css->pseudo_subchannel);
return ret;
}
- mutex_init(&css[nr]->mutex);
- css[nr]->valid = 1;
- css[nr]->cssid = nr;
- sprintf(css[nr]->device.bus_id, "css%x", nr);
- css[nr]->device.release = channel_subsystem_release;
+ mutex_init(&css->mutex);
+ css->valid = 1;
+ css->cssid = nr;
+ sprintf(css->device.bus_id, "css%x", nr);
+ css->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
- css_generate_pgid(css[nr], tod_high);
+ css_generate_pgid(css, tod_high);
return 0;
}
+static int css_reboot_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ int ret, i;
+
+ ret = NOTIFY_DONE;
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ struct channel_subsystem *css;
+
+ css = channel_subsystems[i];
+ if (css->cm_enabled)
+ if (chsc_secm(css, 0))
+ ret = NOTIFY_BAD;
+ }
+
+ return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+ .notifier_call = css_reboot_event,
+};
+
/*
* Now that the driver core is running, we can setup our channel subsystem.
* The struct subchannel's are created during probing (except for the
@@ -670,51 +696,63 @@ init_channel_subsystem (void)
}
/* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) {
- css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
- if (!css[i]) {
+ struct channel_subsystem *css;
+
+ css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+ if (!css) {
ret = -ENOMEM;
goto out_unregister;
}
+ channel_subsystems[i] = css;
ret = setup_css(i);
if (ret)
goto out_free;
- ret = device_register(&css[i]->device);
+ ret = device_register(&css->device);
if (ret)
goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
- ret = device_create_file(&css[i]->device,
+ ret = device_create_file(&css->device,
&dev_attr_cm_enable);
if (ret)
goto out_device;
}
- ret = device_register(&css[i]->pseudo_subchannel->dev);
+ ret = device_register(&css->pseudo_subchannel->dev);
if (ret)
goto out_file;
}
+ ret = register_reboot_notifier(&css_reboot_notifier);
+ if (ret)
+ goto out_pseudo;
css_init_done = 1;
ctl_set_bit(6, 28);
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_pseudo:
+ device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file:
- device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+ device_remove_file(&channel_subsystems[i]->device,
+ &dev_attr_cm_enable);
out_device:
- device_unregister(&css[i]->device);
+ device_unregister(&channel_subsystems[i]->device);
out_free_all:
- kfree(css[i]->pseudo_subchannel->lock);
- kfree(css[i]->pseudo_subchannel);
+ kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+ kfree(channel_subsystems[i]->pseudo_subchannel);
out_free:
- kfree(css[i]);
+ kfree(channel_subsystems[i]);
out_unregister:
while (i > 0) {
+ struct channel_subsystem *css;
+
i--;
- device_unregister(&css[i]->pseudo_subchannel->dev);
+ css = channel_subsystems[i];
+ device_unregister(&css->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_remove_file(&css[i]->device,
+ device_remove_file(&css->device,
&dev_attr_cm_enable);
- device_unregister(&css[i]->device);
+ device_unregister(&css->device);
}
out_bus:
bus_unregister(&css_bus_type);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 5d65e83ca66..81215ef3243 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -167,7 +167,7 @@ struct channel_subsystem {
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
/* Some helper functions for disconnected state. */
int device_is_disconnected(struct subchannel *);
@@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *);
extern struct workqueue_struct *slow_path_wq;
-int subchannel_add_files (struct device *);
extern struct attribute_group *subch_attr_groups[];
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e44d92eac8e..7ee57f084a8 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -21,6 +21,7 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/param.h> /* HZ */
+#include <asm/cmb.h>
#include "cio.h"
#include "cio_debug.h"
@@ -78,49 +79,38 @@ static int snprint_alias(char *buf, size_t size,
/* Set up environment variables for ccw device uevent. Return 0 on success,
* non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ccw_device *cdev = to_ccwdev(dev);
struct ccw_device_id *id = &(cdev->id);
- int i = 0;
- int len = 0;
int ret;
char modalias_buf[30];
/* CU_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_TYPE=%04X", id->cu_type);
+ ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
if (ret)
return ret;
/* CU_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_MODEL=%02X", id->cu_model);
+ ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
if (ret)
return ret;
/* The next two can be zero, that's ok for us */
/* DEV_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_TYPE=%04X", id->dev_type);
+ ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
if (ret)
return ret;
/* DEV_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_MODEL=%02X", id->dev_model);
+ ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
if (ret)
return ret;
/* MODALIAS= */
snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "MODALIAS=%s", modalias_buf);
- if (ret)
- return ret;
- envp[i] = NULL;
- return 0;
+ ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
+ return ret;
}
struct bus_type ccw_bus_type;
@@ -357,8 +347,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
cdev->private->dev_id.devno);
}
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
{
int ret;
@@ -396,8 +396,19 @@ ccw_device_set_offline(struct ccw_device *cdev)
return ret;
}
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
{
int ret;
@@ -947,8 +958,7 @@ out:
wake_up(&ccw_device_init_wq);
}
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
@@ -1101,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch)
* device, e.g. the console.
*/
cdev = sch->dev.driver_data;
+ cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
/*
@@ -1326,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id)
}
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ * If a match is found, its reference count of the found device is increased
+ * and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+ const char *bus_id)
{
struct device *dev;
struct device_driver *drv;
@@ -1401,16 +1423,34 @@ ccw_device_remove (struct device *dev)
return 0;
}
+static void ccw_device_shutdown(struct device *dev)
+{
+ struct ccw_device *cdev;
+
+ cdev = to_ccwdev(dev);
+ if (cdev->drv && cdev->drv->shutdown)
+ cdev->drv->shutdown(cdev);
+ disable_cmf(cdev);
+}
+
struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
.uevent = ccw_uevent,
.probe = ccw_device_probe,
.remove = ccw_device_remove,
+ .shutdown = ccw_device_shutdown,
};
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
{
struct device_driver *drv = &cdriver->driver;
@@ -1420,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver)
return driver_register(drv);
}
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
{
driver_unregister(&cdriver->driver);
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index b66338b7657..0d408960043 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
void ccw_device_move_to_orphanage(struct work_struct *);
int ccw_device_is_orphan(struct ccw_device *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 8633dc53769..8867443b806 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
if (cdev->private->pgid[last].inf.ps.state1 ==
SNID_STATE1_RESET)
/* No previous pgid found */
- memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+ memcpy(&cdev->private->pgid[0],
+ &channel_subsystems[0]->global_pgid,
sizeof(struct pgid));
else
/* Use existing pgid */
@@ -543,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
- struct subchannel *sch;
- int ret;
- unsigned long flags;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- spin_lock_irqsave(cdev->ccwlock, flags);
- sch = to_subchannel(cdev->dev.parent);
- /* Extra sanity. */
- if (sch->lpm)
- goto out_unlock;
- if (sch->driver && sch->driver->notify) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
- spin_lock_irqsave(cdev->ccwlock, flags);
- } else
- ret = 0;
- if (!ret) {
- if (get_device(&sch->dev)) {
- /* Driver doesn't want to keep device. */
- cio_disable_subchannel(sch);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work,
- &cdev->private->kick_work);
- } else
- put_device(&sch->dev);
- }
- } else {
- cio_disable_subchannel(sch);
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- }
-out_unlock:
- spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -631,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- if (cdev->online) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
+ if (cdev->online)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -690,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
break;
default:
cdev->private->flags.donotify = 0;
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -765,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
}
/*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
*/
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+ enum dev_event dev_event)
{
struct subchannel *sch;
cdev->private->state = DEV_STATE_NOT_OPER;
sch = to_subchannel(cdev->dev.parent);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct subchannel *sch;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- if (sch->driver->notify) {
- spin_unlock_irq(cdev->ccwlock);
- ret = sch->driver->notify(&sch->dev,
- sch->lpm ? CIO_GONE : CIO_NO_PATH);
- spin_lock_irq(cdev->ccwlock);
- } else
- ret = 0;
- if (ret) {
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- return;
- }
- cdev->private->state = DEV_STATE_NOT_OPER;
- cio_disable_subchannel(sch);
- if (sch->schib.scsw.actl != 0) {
- // FIXME: not-oper indication to device driver ?
- ccw_device_call_handler(cdev);
- }
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
+ css_schedule_eval(sch->schid);
}
/*
@@ -915,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV) {
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- } else if (cdev->handler)
+ if (ret == -ENODEV)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-ETIMEDOUT));
}
@@ -1233,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
@@ -1245,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_OFFLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_W4SENSE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_DISBAND_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_BOXED] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_stlck_done,
[DEV_EVENT_TIMEOUT] = ccw_device_stlck_done,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* states to wait for i/o completion before doing something */
[DEV_STATE_CLEAR_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_TIMEOUT_KILL] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 14eba854b15..7fd2dadc329 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -25,6 +25,16 @@
#include "device.h"
#include "chp.h"
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ * %0 on success, -%EINVAL on an invalid flag combination.
+ */
int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ * %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
{
cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
}
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags)
{
struct subchannel *sch;
int ret;
@@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags, int expires)
{
int ret;
@@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, unsigned long flags)
{
return ccw_device_start_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags);
}
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags,
- int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm,
+ unsigned long flags, int expires)
{
return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
}
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev)
return 1;
}
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ * %NULL if no extended sense data has been stored or if no CIW of the
+ * specified command type could be found,
+ * else a pointer to the CIW of the specified command type.
*/
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
{
int ciw_cnt;
@@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
return NULL;
}
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ * %0 if no subchannel for the device is available,
+ * else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -357,8 +539,7 @@ out_unlock:
return ret;
}
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
{
struct subchannel *sch;
struct chp_id chpid;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index d8d479876ec..40a3208c7cf 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q)
}
static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
{
- __qdio_outbound_processing(q);
+ __qdio_outbound_processing((struct qdio_q *) q);
}
/************************* INBOUND ROUTINES *******************************/
@@ -1449,9 +1449,10 @@ out:
}
static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
{
- __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+ __tiqdio_inbound_processing((struct qdio_q *) q,
+ atomic_read(&spare_indicator_usecount));
}
static void
@@ -1494,9 +1495,9 @@ again:
}
static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
{
- __qdio_inbound_processing(q);
+ __qdio_inbound_processing((struct qdio_q *) q);
}
/************************* MAIN ROUTINES *******************************/
@@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->handler=input_handler;
q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
- q->tasklet.data=(unsigned long)q;
/* q->is_thinint_q isn't valid at this time, but
- * irq_ptr->is_thinint_irq is */
- q->tasklet.func=(void(*)(unsigned long))
- ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
- &qdio_inbound_processing);
+ * irq_ptr->is_thinint_irq is
+ */
+ if (irq_ptr->is_thinint_irq)
+ tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+ (unsigned long) q);
+ else
+ tasklet_init(&q->tasklet, qdio_inbound_processing,
+ (unsigned long) q);
/* actually this is not used for inbound queues. yet. */
atomic_set(&q->busy_siga_counter,0);
@@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->last_move_ftc=0;
q->handler=output_handler;
- q->tasklet.data=(unsigned long)q;
- q->tasklet.func=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.function=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.data = (long)q;
- init_timer(&q->timer);
+ tasklet_init(&q->tasklet, qdio_outbound_processing,
+ (unsigned long) q);
+ setup_timer(&q->timer, qdio_outbound_processing,
+ (unsigned long) q);
atomic_set(&q->busy_siga_counter,0);
q->timing.busy_start=0;
@@ -3726,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
#endif /* CONFIG_64BIT */
}
} else {
- QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 90bd2201451..67aaff3e668 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
* uevent function for AP devices. It sets up a single environment
* variable DEV_TYPE which contains the hardware device type.
*/
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
{
struct ap_device *ap_dev = to_ap_dev(dev);
- int retval = 0, length = 0, i = 0;
+ int retval = 0;
if (!ap_dev)
return -ENODEV;
/* Set up DEV_TYPE environment variable. */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEV_TYPE=%04X", ap_dev->device_type);
+ retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
if (retval)
return retval;
/* Add MODALIAS= */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=ap:t%02X", ap_dev->device_type);
+ retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
- envp[i] = NULL;
return retval;
}
@@ -1231,8 +1225,9 @@ static void ap_reset_domain(void)
{
int i;
- for (i = 0; i < AP_DEVICES; i++)
- ap_reset_queue(AP_MKQID(i, ap_domain_index));
+ if (ap_domain_index != -1)
+ for (i = 0; i < AP_DEVICES; i++)
+ ap_reset_queue(AP_MKQID(i, ap_domain_index));
}
static void ap_reset_all(void)
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
index 2a9349ad68b..44253fdd413 100644
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
/**
* The module initialization code.
*/
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
{
int rc;
@@ -86,7 +86,7 @@ out:
/**
* The module termination code.
*/
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
{
zcrypt_cex2a_exit();
zcrypt_pcixcc_exit();
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 64948788d30..70b9ddc8cf9 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
};
struct {
struct type6_hdr hdr;
- struct ica_CPRBX cprbx;
+ struct CPRBX cprbx;
} __attribute__((packed)) *msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
}
if (service_rc == 8 && service_rs == 770) {
PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
- zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
- return -EAGAIN;
+ return -EINVAL;
}
if (service_rc == 8 && service_rs == 783) {
PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
return -EAGAIN;
}
+ if (service_rc == 12 && service_rs == 769) {
+ PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+ return -EINVAL;
+ }
PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
service_rc, service_rs);
zdev->online = 0;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index a78ff307fd1..8cb7d7a6973 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,51 +28,6 @@
#ifndef _ZCRYPT_PCIXCC_H_
#define _ZCRYPT_PCIXCC_H_
-/**
- * CPRBX
- * Note that all shorts and ints are big-endian.
- * All pointer fields are 16 bytes long, and mean nothing.
- *
- * A request CPRB is followed by a request_parameter_block.
- *
- * The request (or reply) parameter block is organized thus:
- * function code
- * VUD block
- * key block
- */
-struct CPRBX {
- unsigned short cprb_len; /* CPRB length 220 */
- unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
- unsigned char pad_000[3]; /* Alignment pad bytes */
- unsigned char func_id[2]; /* function id 0x5432 */
- unsigned char cprb_flags[4]; /* Flags */
- unsigned int req_parml; /* request parameter buffer len */
- unsigned int req_datal; /* request data buffer */
- unsigned int rpl_msgbl; /* reply message block length */
- unsigned int rpld_parml; /* replied parameter block len */
- unsigned int rpl_datal; /* reply data block len */
- unsigned int rpld_datal; /* replied data block len */
- unsigned int req_extbl; /* request extension block len */
- unsigned char pad_001[4]; /* reserved */
- unsigned int rpld_extbl; /* replied extension block len */
- unsigned char req_parmb[16]; /* request parm block 'address' */
- unsigned char req_datab[16]; /* request data block 'address' */
- unsigned char rpl_parmb[16]; /* reply parm block 'address' */
- unsigned char rpl_datab[16]; /* reply data block 'address' */
- unsigned char req_extb[16]; /* request extension block 'addr'*/
- unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
- unsigned short ccp_rtcode; /* server return code */
- unsigned short ccp_rscode; /* server reason code */
- unsigned int mac_data_len; /* Mac Data Length */
- unsigned char logon_id[8]; /* Logon Identifier */
- unsigned char mac_value[8]; /* Mac Value */
- unsigned char mac_content_flgs;/* Mac content flag byte */
- unsigned char pad_002; /* Alignment */
- unsigned short domain; /* Domain */
- unsigned char pad_003[12]; /* Domain masks */
- unsigned char pad_004[36]; /* reserved */
-} __attribute__((packed));
-
int zcrypt_pcixcc_init(void);
void zcrypt_pcixcc_exit(void);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 90aa53fc4f3..7507067351b 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -891,7 +891,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit)
/*
* Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI
* commands.
- * It also genrates fcp-nameserver request/response buffer and unsolicited
+ * It also genrates fcp-nameserver request/response buffer and unsolicited
* status read fsf_req buffers.
*
* locks: must only be called with zfcp_data.config_sema taken
@@ -982,7 +982,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
struct zfcp_adapter *adapter;
/*
- * Note: It is safe to release the list_lock, as any list changes
+ * Note: It is safe to release the list_lock, as any list changes
* are protected by the config_sema, which must be held to get here
*/
@@ -1038,6 +1038,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
spin_lock_init(&adapter->san_dbf_lock);
spin_lock_init(&adapter->scsi_dbf_lock);
+ retval = zfcp_adapter_debug_register(adapter);
+ if (retval)
+ goto debug_register_failed;
+
/* initialize error recovery stuff */
rwlock_init(&adapter->erp_lock);
@@ -1058,7 +1062,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* mark adapter unusable as long as sysfs registration is not complete */
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
- adapter->ccw_device = ccw_device;
dev_set_drvdata(&ccw_device->dev, adapter);
if (zfcp_sysfs_adapter_create_files(&ccw_device->dev))
@@ -1085,6 +1088,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
generic_services_failed:
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
sysfs_failed:
+ zfcp_adapter_debug_unregister(adapter);
+ debug_register_failed:
dev_set_drvdata(&ccw_device->dev, NULL);
zfcp_reqlist_free(adapter);
failed_low_mem_buffers:
@@ -1130,6 +1135,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
goto out;
}
+ zfcp_adapter_debug_unregister(adapter);
+
/* remove specified adapter data structure from list */
write_lock_irq(&zfcp_data.config_lock);
list_del(&adapter->list);
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 1c8f71a5985..e01cbf152a8 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = {
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
- .driver = {
- .shutdown = zfcp_ccw_shutdown,
- },
+ .shutdown = zfcp_ccw_shutdown,
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -150,15 +148,12 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
- retval = zfcp_adapter_debug_register(adapter);
- if (retval)
- goto out;
retval = zfcp_erp_thread_setup(adapter);
if (retval) {
ZFCP_LOG_INFO("error: start of error recovery thread for "
"adapter %s failed\n",
zfcp_get_busid_by_adapter(adapter));
- goto out_erp_thread;
+ goto out;
}
retval = zfcp_adapter_scsi_register(adapter);
@@ -177,8 +172,6 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
out_scsi_register:
zfcp_erp_thread_kill(adapter);
- out_erp_thread:
- zfcp_adapter_debug_unregister(adapter);
out:
up(&zfcp_data.config_sema);
return retval;
@@ -201,7 +194,6 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
- zfcp_adapter_debug_unregister(adapter);
up(&zfcp_data.config_sema);
return 0;
}
@@ -277,12 +269,12 @@ zfcp_ccw_register(void)
* Makes sure that QDIO queues are down when the system gets stopped.
*/
static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
{
struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema);
- adapter = dev_get_drvdata(dev);
+ adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5f3212440f6..ffa3bf75694 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <asm/debug.h>
#include <linux/ctype.h>
+#include <asm/debug.h>
#include "zfcp_ext.h"
static u32 dbfsize = 4;
@@ -35,17 +35,17 @@ static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
- struct timespec xtime;
+ struct timespec dbftime;
int len = 0;
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
sec = stck >> 12;
do_div(sec, 1000000);
- xtime.tv_sec = sec;
+ dbftime.tv_sec = sec;
stck -= (sec * 1000000) << 12;
- xtime.tv_nsec = ((stck * 1000) >> 12);
+ dbftime.tv_nsec = ((stck * 1000) >> 12);
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
- label, xtime.tv_sec, xtime.tv_nsec);
+ label, dbftime.tv_sec, dbftime.tv_nsec);
return len;
}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index b36dfc40d9f..16e5563e0c6 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -1,23 +1,23 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
- */
+ *
+ * This program is free software; you can redistribute 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.
+ */
#ifndef ZFCP_DEF_H
#define ZFCP_DEF_H
@@ -90,7 +90,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define ZFCP_DEVICE_TYPE 0x1732
#define ZFCP_DEVICE_MODEL 0x03
#define ZFCP_DEVICE_MODEL_PRIV 0x04
-
+
/* allow as many chained SBALs as are supported by hardware */
#define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ
#define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ
@@ -508,7 +508,7 @@ struct zfcp_rc_entry {
/*
* this allows removal of logging code by the preprocessor
- * (the most detailed log level still to be compiled in is specified,
+ * (the most detailed log level still to be compiled in is specified,
* higher log levels are removed)
*/
#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE
@@ -546,7 +546,7 @@ do { \
if (ZFCP_LOG_CHECK(level)) \
_ZFCP_LOG(fmt, ##args); \
} while (0)
-
+
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
# define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0)
#else
@@ -583,8 +583,8 @@ do { \
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
-/*
- * Note, the leftmost status byte is common among adapter, port
+/*
+ * Note, the leftmost status byte is common among adapter, port
* and unit
*/
#define ZFCP_COMMON_FLAGS 0xfff00000
@@ -1007,8 +1007,8 @@ struct zfcp_fsf_req {
u32 fsf_command; /* FSF Command copy */
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
- unsigned long data; /* private data of request */
- struct timer_list timer; /* used for erp or scsi er */
+ unsigned long data; /* private data of request */
+ struct timer_list timer; /* used for erp or scsi er */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
mempool_t *pool; /* used if request was alloacted
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index d8cd75ce2d9..a6475a2bb8a 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
@@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
@@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
static void zfcp_erp_action_ready(struct zfcp_erp_action *);
static int zfcp_erp_action_exists(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
@@ -191,7 +191,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
}
/*
- * function:
+ * function:
*
* purpose: called if an adapter failed,
* initiates adapter recovery which is done
@@ -228,7 +228,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_adapter_reopen_internal
* used to ensure the correct locking
@@ -476,7 +476,7 @@ zfcp_test_link(struct zfcp_port *port)
/*
- * function:
+ * function:
*
* purpose: called if a port failed to be opened normally
* initiates Forced Reopen recovery which is done
@@ -517,7 +517,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_port_forced_reopen_internal
* used to ensure the correct locking
@@ -543,7 +543,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: called if a port is to be opened
* initiates Reopen recovery which is done
@@ -612,7 +612,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: called if a unit is to be opened
* initiates Reopen recovery which is done
@@ -704,7 +704,7 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
}
/*
- * function:
+ * function:
*
* purpose: disable I/O,
* return any open requests and clean them up,
@@ -725,7 +725,7 @@ zfcp_erp_port_block(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: enable I/O
*
@@ -742,7 +742,7 @@ zfcp_erp_port_unblock(struct zfcp_port *port)
}
/*
- * function:
+ * function:
*
* purpose: disable I/O,
* return any open requests and clean them up,
@@ -763,7 +763,7 @@ zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: enable I/O
*
@@ -792,7 +792,7 @@ zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose:
*
@@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data)
* action gets an appropriate flag and will be processed
* accordingly
*/
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -967,7 +967,7 @@ void zfcp_erp_timeout_handler(unsigned long data)
* zfcp_erp_action_dismiss - dismiss an erp_action
*
* adapter->erp_lock must be held
- *
+ *
* Dismissal of an erp_action is usually required if an erp_action of
* higher priority is generated.
*/
@@ -1005,9 +1005,9 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns:
*
@@ -1094,7 +1094,7 @@ zfcp_erp_thread(void *data)
}
/*
- * function:
+ * function:
*
* purpose: drives single error recovery action and schedules higher and
* subordinate actions, if necessary
@@ -1206,7 +1206,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
/*
* put this target through the erp mill again if someone has
- * requested to change the status of a target being online
+ * requested to change the status of a target being online
* to offline or the other way around
* (old retval is preserved if nothing has to be done here)
*/
@@ -1228,7 +1228,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
unlock:
write_unlock(&adapter->erp_lock);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-
+
if (retval != ZFCP_ERP_CONTINUES)
zfcp_erp_action_cleanup(action, adapter, port, unit, retval);
@@ -1250,9 +1250,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_DISMISSED - if action has been dismissed
* retval - otherwise
@@ -1322,7 +1322,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: triggers retry of this action after a certain amount of time
* by means of timer provided by erp_action
@@ -1346,7 +1346,7 @@ zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
return retval;
}
-/*
+/*
* function: zfcp_erp_adapter_failed
*
* purpose: sets the adapter and all underlying devices to ERP_FAILED
@@ -1362,7 +1362,7 @@ zfcp_erp_adapter_failed(struct zfcp_adapter *adapter)
debug_text_event(adapter->erp_dbf, 2, "a_afail");
}
-/*
+/*
* function: zfcp_erp_port_failed
*
* purpose: sets the port and all underlying devices to ERP_FAILED
@@ -1386,7 +1386,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
debug_event(port->adapter->erp_dbf, 2, &port->wwpn, sizeof (wwn_t));
}
-/*
+/*
* function: zfcp_erp_unit_failed
*
* purpose: sets the unit to ERP_FAILED
@@ -1417,7 +1417,7 @@ zfcp_erp_unit_failed(struct zfcp_unit *unit)
* successfully is reset.
*
* returns: ZFCP_ERP_CONTINUES - action continues (not considered)
- * ZFCP_ERP_SUCCEEDED - action finished successfully
+ * ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_EXIT - action failed and will not continue
*/
static int
@@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action,
return retval;
}
-static inline int
+static int
zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
{
return
@@ -1646,7 +1646,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
}
/*
- * function:
+ * function:
*
* purpose: remaining things in good cases,
* escalation in bad cases
@@ -1687,8 +1687,8 @@ zfcp_erp_strategy_followup_actions(int action,
break;
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (status == ZFCP_ERP_SUCCEEDED) ; /* no further action */
- else
+ /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */
+ if (status != ZFCP_ERP_SUCCEEDED)
zfcp_erp_port_reopen_internal(unit->port, 0);
break;
}
@@ -1815,7 +1815,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_port_reopen_all_internal
* used to ensure the correct locking
@@ -1852,9 +1852,9 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: FIXME
*/
@@ -1871,7 +1871,7 @@ zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Adapter' action
* (the entire action is processed synchronously, since
@@ -1908,9 +1908,9 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -1930,9 +1930,9 @@ zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -1957,7 +1957,7 @@ zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action)
* purpose: allocate the irq associated with this devno and register
* the FSF adapter with the SCSI stack
*
- * returns:
+ * returns:
*/
static int
zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
@@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
* returns: 0 - successful setup
* !0 - failed setup
*/
-int
+static int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
int retval;
@@ -2197,7 +2197,7 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
zfcp_erp_action_to_running(erp_action);
write_unlock_irq(&adapter->erp_lock);
- ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
+ ret = zfcp_fsf_exchange_port_data(erp_action);
if (ret == -EOPNOTSUPP) {
debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
return ZFCP_ERP_SUCCEEDED;
@@ -2249,7 +2249,7 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Physical Port' action
*
@@ -2308,7 +2308,7 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Port' action
*
@@ -2530,7 +2530,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: makes the erp thread continue with reopen (physical) port
* actions which have been paused until the name server port
@@ -2570,9 +2570,9 @@ zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2626,9 +2626,9 @@ zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2663,9 +2663,9 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2700,9 +2700,9 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2737,7 +2737,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Unit' action
* currently no retries
@@ -2825,9 +2825,9 @@ zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2865,9 +2865,9 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2913,7 +2913,7 @@ void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
}
/*
- * function:
+ * function:
*
* purpose: enqueue the specified error recovery action, if needed
*
@@ -2992,7 +2992,7 @@ zfcp_erp_action_enqueue(int action,
port->erp_action.action);
debug_text_event(adapter->erp_dbf, 4,
"pf_actenq_drp");
- } else
+ } else
debug_text_event(adapter->erp_dbf, 4,
"pf_actenq_drpcp");
debug_event(adapter->erp_dbf, 4, &port->wwpn,
@@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
zfcp_erp_action_dismiss(&unit->erp_action);
}
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
}
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 991d45667a4..8534cf09546 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#ifndef ZFCP_EXT_H
@@ -82,9 +82,11 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
-extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
- struct zfcp_adapter *,
- struct fsf_qtcb_bottom_port *);
+extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *,
+ struct fsf_qtcb_bottom_config *);
+extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);
+extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *,
+ struct fsf_qtcb_bottom_port *);
extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 99299976e89..ff866ebd44a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -80,10 +80,10 @@ static const char zfcp_act_subtable_type[5][8] = {
/*
* function: zfcp_fsf_req_alloc
*
- * purpose: Obtains an fsf_req and potentially a qtcb (for all but
+ * purpose: Obtains an fsf_req and potentially a qtcb (for all but
* unsolicited requests) via helper functions
* Does some initial fsf request set-up.
- *
+ *
* returns: pointer to allocated fsf_req if successfull
* NULL otherwise
*
@@ -192,7 +192,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
* returns: 0 - success
* !0 - failure
*
- * context:
+ * context:
*/
int
zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
@@ -214,8 +214,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
}
/*
- * fsf_req may be deleted due to waking up functions, so
- * cleanup is saved here and used later
+ * fsf_req may be deleted due to waking up functions, so
+ * cleanup is saved here and used later
*/
if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
cleanup = 1;
@@ -259,9 +259,9 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
* and initiates appropriate actions
* (usually calling FSF command specific handlers)
*
- * returns:
+ * returns:
*
- * context:
+ * context:
*
* locks:
*/
@@ -638,7 +638,7 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
*
* purpose: calls the appropriate command specific handler
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
@@ -854,7 +854,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
*
* purpose: is called for finished Open Port command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
@@ -1088,7 +1088,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
* returns: address of initiated FSF request
* NULL - request could not be initiated
*
- * FIXME(design): should be watched by a timeout !!!
+ * FIXME(design): should be watched by a timeout !!!
* FIXME(design) shouldn't this be modified to return an int
* also...don't know how though
*/
@@ -1157,7 +1157,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
*
* purpose: is called for finished Abort FCP Command request
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
@@ -1941,25 +1941,28 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
+ struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long lock_flags;
- int retval = 0;
+ int retval;
/* setup new FSF request */
- retval = zfcp_fsf_req_create(erp_action->adapter,
+ retval = zfcp_fsf_req_create(adapter,
FSF_QTCB_EXCHANGE_CONFIG_DATA,
ZFCP_REQ_AUTO_CLEANUP,
- erp_action->adapter->pool.fsf_req_erp,
+ adapter->pool.fsf_req_erp,
&lock_flags, &fsf_req);
- if (retval < 0) {
+ if (retval) {
ZFCP_LOG_INFO("error: Could not create exchange configuration "
"data request for adapter %s.\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto out;
+ zfcp_get_busid_by_adapter(adapter));
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return retval;
}
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
- sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
- sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
fsf_req->qtcb->bottom.config.feature_selection =
FSF_FEATURE_CFDC |
@@ -1971,23 +1974,71 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
zfcp_erp_start_timer(fsf_req);
retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
if (retval) {
- ZFCP_LOG_INFO
- ("error: Could not send exchange configuration data "
- "command on the adapter %s\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
+ ZFCP_LOG_INFO("error: Could not send exchange configuration "
+ "data command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
- goto out;
}
+ else
+ ZFCP_LOG_DEBUG("exchange configuration data request initiated "
+ "(adapter %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
- ZFCP_LOG_DEBUG("exchange configuration data request initiated "
- "(adapter %s)\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
+ return retval;
+}
- out:
- write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
+int
+zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
+ struct fsf_qtcb_bottom_config *data)
+{
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval;
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+ 0, NULL, &lock_flags, &fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not create exchange configuration "
+ "data request for adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return retval;
+ }
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ fsf_req->qtcb->bottom.config.feature_selection =
+ FSF_FEATURE_CFDC |
+ FSF_FEATURE_LUN_SHARING |
+ FSF_FEATURE_NOTIFICATION_LOST |
+ FSF_FEATURE_UPDATE_ALERT;
+
+ if (data)
+ fsf_req->data = (unsigned long) data;
+
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
+ if (retval)
+ ZFCP_LOG_INFO("error: Could not send exchange configuration "
+ "data command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ else
+ wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+ zfcp_fsf_req_free(fsf_req);
+
return retval;
}
@@ -2016,11 +2067,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
adapter->peer_d_id = 0;
if (xchg_ok) {
+
+ if (fsf_req->data)
+ memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data,
+ bottom, sizeof (struct fsf_qtcb_bottom_config));
+
fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
fc_host_speed(shost) = bottom->fc_link_speed;
- fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
+ fc_host_supported_classes(shost) =
+ FC_COS_CLASS2 | FC_COS_CLASS3;
adapter->hydra_version = bottom->adapter_type;
if (fc_host_permanent_port_name(shost) == -1)
fc_host_permanent_port_name(shost) =
@@ -2053,7 +2110,8 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
min(FC_SERIAL_NUMBER_SIZE, 17));
}
- ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
+ ZFCP_LOG_NORMAL("The adapter %s reported the following "
+ "characteristics:\n"
"WWNN 0x%016Lx, "
"WWPN 0x%016Lx, "
"S_ID 0x%06x,\n"
@@ -2090,7 +2148,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
return 0;
}
-/*
+/**
* function: zfcp_fsf_exchange_config_data_handler
*
* purpose: is called for finished Exchange Configuration Data command
@@ -2125,7 +2183,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
adapter->peer_wwpn,
adapter->peer_d_id);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
- "top-p-to-p");
+ "top-p-to-p");
break;
case FC_PORTTYPE_NLPORT:
ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
@@ -2138,8 +2196,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
return -EIO;
case FC_PORTTYPE_NPORT:
ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
- "network detected at adapter %s.\n",
- zfcp_get_busid_by_adapter(adapter));
+ "network detected at adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
break;
default:
ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
@@ -2179,7 +2237,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
return -EIO;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
+ &adapter->status);
zfcp_fsf_link_down_info_eval(adapter,
&qtcb->header.fsf_status_qual.link_down_info);
@@ -2187,7 +2246,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
default:
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
debug_event(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status, sizeof (u32));
+ &fsf_req->qtcb->header.fsf_status, sizeof(u32));
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
}
@@ -2197,74 +2256,118 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
/**
* zfcp_fsf_exchange_port_data - request information about local port
* @erp_action: ERP action for the adapter for which port data is requested
- * @adapter: for which port data is requested
- * @data: response to exchange port data request
*/
int
-zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
- struct zfcp_adapter *adapter,
- struct fsf_qtcb_bottom_port *data)
+zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
- struct zfcp_fsf_req *fsf_req;
+ struct zfcp_fsf_req *fsf_req;
+ struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long lock_flags;
- int retval = 0;
+ int retval;
if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
ZFCP_LOG_INFO("error: exchange port data "
- "command not supported by adapter %s\n",
+ "command not supported by adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
- return -EOPNOTSUPP;
- }
+ return -EOPNOTSUPP;
+ }
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
- erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
- NULL, &lock_flags, &fsf_req);
- if (retval < 0) {
+ ZFCP_REQ_AUTO_CLEANUP,
+ adapter->pool.fsf_req_erp,
+ &lock_flags, &fsf_req);
+ if (retval) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
- "exchange port data request for"
- "the adapter %s.\n",
+ "exchange port data request for"
+ "the adapter %s.\n",
zfcp_get_busid_by_adapter(adapter));
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
return retval;
}
- if (data)
- fsf_req->data = (unsigned long) data;
-
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
- sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
- sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- if (erp_action) {
- erp_action->fsf_req = fsf_req;
- fsf_req->erp_action = erp_action;
- zfcp_erp_start_timer(fsf_req);
- } else
- zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+ zfcp_erp_start_timer(fsf_req);
retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+
if (retval) {
ZFCP_LOG_INFO("error: Could not send an exchange port data "
- "command on the adapter %s\n",
+ "command on the adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_fsf_req_free(fsf_req);
- if (erp_action)
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req = NULL;
+ }
+ else
+ ZFCP_LOG_DEBUG("exchange port data request initiated "
+ "(adapter %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ return retval;
+}
+
+
+/**
+ * zfcp_fsf_exchange_port_data_sync - request information about local port
+ * and wait until information is ready
+ */
+int
+zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
+ struct fsf_qtcb_bottom_port *data)
+{
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval;
+
+ if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
+ ZFCP_LOG_INFO("error: exchange port data "
+ "command not supported by adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ return -EOPNOTSUPP;
+ }
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
+ 0, NULL, &lock_flags, &fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+ "exchange port data request for"
+ "the adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
return retval;
}
+ if (data)
+ fsf_req->data = (unsigned long) data;
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- if (!erp_action) {
+ if (retval)
+ ZFCP_LOG_INFO("error: Could not send an exchange port data "
+ "command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ else
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- zfcp_fsf_req_free(fsf_req);
- }
+
+ zfcp_fsf_req_free(fsf_req);
+
return retval;
}
@@ -2277,18 +2380,16 @@ static void
zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
{
struct zfcp_adapter *adapter;
- struct fsf_qtcb *qtcb;
- struct fsf_qtcb_bottom_port *bottom, *data;
+ struct fsf_qtcb_bottom_port *bottom;
struct Scsi_Host *shost;
adapter = fsf_req->adapter;
- qtcb = fsf_req->qtcb;
- bottom = &qtcb->bottom.port;
+ bottom = &fsf_req->qtcb->bottom.port;
shost = adapter->scsi_host;
- data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
- if (data)
- memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
+ if (fsf_req->data)
+ memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom,
+ sizeof(struct fsf_qtcb_bottom_port));
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
fc_host_permanent_port_name(shost) = bottom->wwpn;
@@ -2336,10 +2437,10 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
/*
* function: zfcp_fsf_open_port
*
- * purpose:
+ * purpose:
*
* returns: address of initiated FSF request
- * NULL - request could not be initiated
+ * NULL - request could not be initiated
*/
int
zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
@@ -2400,7 +2501,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
*
* purpose: is called for finished Open Port command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
@@ -3002,7 +3103,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
*
* purpose: is called for finished Open LUN command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
@@ -3265,7 +3366,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
* purpose:
*
* returns: address of fsf_req - request successfully initiated
- * NULL -
+ * NULL -
*
* assumptions: This routine does not check whether the associated
* remote port/lun has already been opened. This should be
@@ -3586,17 +3687,17 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
ZFCP_LOG_DEBUG(
"Data did not fit into available buffer(s), "
"waiting for more...\n");
- retval = -EIO;
- } else {
- ZFCP_LOG_NORMAL("error: No truncation implemented but "
- "required. Shutting down unit "
- "(adapter %s, port 0x%016Lx, "
- "unit 0x%016Lx)\n",
- zfcp_get_busid_by_unit(unit),
- unit->port->wwpn,
- unit->fcp_lun);
- zfcp_erp_unit_shutdown(unit, 0);
- retval = -EINVAL;
+ retval = -EIO;
+ } else {
+ ZFCP_LOG_NORMAL("error: No truncation implemented but "
+ "required. Shutting down unit "
+ "(adapter %s, port 0x%016Lx, "
+ "unit 0x%016Lx)\n",
+ zfcp_get_busid_by_unit(unit),
+ unit->port->wwpn,
+ unit->fcp_lun);
+ zfcp_erp_unit_shutdown(unit, 0);
+ retval = -EINVAL;
}
goto no_fit;
}
@@ -3727,7 +3828,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
*
* purpose: is called for finished Send FCP Command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
@@ -3964,7 +4065,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
*
* purpose: evaluates FCP_RSP IU
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
@@ -4192,7 +4293,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
*
* purpose: evaluates FCP_RSP IU
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
@@ -4635,7 +4736,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
INIT_LIST_HEAD(&fsf_req->list);
init_timer(&fsf_req->timer);
- /* initialize waitqueue which may be used to wait on
+ /* initialize waitqueue which may be used to wait on
this request completion */
init_waitqueue_head(&fsf_req->completion_wq);
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 71186618947..8cce5cc11d5 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#ifndef FSF_H
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index c6899efdc8f..3f105fdcf23 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -174,10 +174,9 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
* That is why we need to clear the link-down flag
* which is set again in case we have missed by a mile.
*/
- zfcp_erp_adapter_reopen(
- adapter,
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_COMMON_ERP_FAILED);
+ zfcp_erp_adapter_reopen(adapter,
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_COMMON_ERP_FAILED);
}
return retval;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index ad7eb4a9261..abae2027f7e 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
@@ -101,7 +101,7 @@ zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
((unsigned char *) fcp_cmd +
sizeof (struct fcp_cmnd_iu) + additional_length);
/*
- * fcp_dl_addr = start address of fcp_cmnd structure +
+ * fcp_dl_addr = start address of fcp_cmnd structure +
* size of fixed part + size of dynamically sized add_dcp_cdb field
* SEE FCP-2 documentation
*/
@@ -189,13 +189,12 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
unit->device = NULL;
zfcp_erp_unit_failed(unit);
zfcp_unit_put(unit);
- } else {
+ } else
ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at "
"address %p\n", sdpnt);
- }
}
-/*
+/*
* called from scsi midlayer to allow finetuning of a device.
*/
static int
@@ -361,12 +360,11 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
list_for_each_entry(port, &adapter->port_list_head, list) {
if (!port->rport || (id != port->rport->scsi_target_id))
continue;
- list_for_each_entry(unit, &port->unit_list_head, list) {
+ list_for_each_entry(unit, &port->unit_list_head, list)
if (lun == unit->scsi_lun) {
retval = unit;
goto out;
}
- }
}
out:
return retval;
@@ -374,7 +372,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
/**
* zfcp_scsi_eh_abort_handler - abort the specified SCSI command
- * @scpnt: pointer to scsi_cmnd to be aborted
+ * @scpnt: pointer to scsi_cmnd to be aborted
* Return: SUCCESS - command has been aborted and cleaned up in internal
* bookkeeping, SCSI stack won't be called for aborted command
* FAILED - otherwise
@@ -733,7 +731,7 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost)
if (!data)
return NULL;
- ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+ ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
if (ret) {
kfree(data);
return NULL; /* XXX return zeroed fc_stats? */
@@ -763,7 +761,7 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
if (!data)
return;
- ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+ ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
if (ret) {
kfree(data);
} else {
@@ -802,6 +800,7 @@ struct fc_function_template zfcp_transport_functions = {
.show_host_port_type = 1,
.show_host_speed = 1,
.show_host_port_id = 1,
+ .disable_target_scan = 1,
};
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c
index 81a48417586..63f75ee95c3 100644
--- a/drivers/s390/scsi/zfcp_sysfs_unit.c
+++ b/drivers/s390/scsi/zfcp_sysfs_unit.c
@@ -139,7 +139,7 @@ static struct attribute_group zfcp_unit_attr_group = {
.attrs = zfcp_unit_attrs,
};
-/**
+/**
* zfcp_sysfs_create_unit_files - create sysfs unit files
* @dev: pointer to belonging device
*
@@ -151,7 +151,7 @@ zfcp_sysfs_unit_create_files(struct device *dev)
return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group);
}
-/**
+/**
* zfcp_sysfs_remove_unit_files - remove sysfs unit files
* @dev: pointer to belonging device
*
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 6f2c71ef47e..30905cebefb 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -272,6 +272,13 @@ config SCSI_FC_ATTRS
each attached FiberChannel device to sysfs, say Y.
Otherwise, say N.
+config SCSI_FC_TGT_ATTRS
+ bool "SCSI target support for FiberChannel Transport Attributes"
+ depends on SCSI_FC_ATTRS
+ depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS
+ help
+ If you want to use SCSI target mode drivers enable this option.
+
config SCSI_ISCSI_ATTRS
tristate "iSCSI Transport Attributes"
depends on SCSI && NET
@@ -289,6 +296,20 @@ config SCSI_SAS_ATTRS
source "drivers/scsi/libsas/Kconfig"
+config SCSI_SRP_ATTRS
+ tristate "SRP Transport Attributes"
+ depends on SCSI
+ help
+ If you wish to export transport-specific information about
+ each attached SRP device to sysfs, say Y.
+
+config SCSI_SRP_TGT_ATTRS
+ bool "SCSI target support for SRP Transport Attributes"
+ depends on SCSI_SRP_ATTRS
+ depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS
+ help
+ If you want to use SCSI target mode drivers enable this option.
+
endmenu
menuconfig SCSI_LOWLEVEL
@@ -502,7 +523,6 @@ config SCSI_ADVANSYS
tristate "AdvanSys SCSI support"
depends on SCSI
depends on ISA || EISA || PCI
- depends on BROKEN || X86_32
help
This is a driver for all SCSI host adapters manufactured by
AdvanSys. It is documented in the kernel source in
@@ -524,19 +544,32 @@ config SCSI_IN2000
module will be called in2000.
config SCSI_ARCMSR
- tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+ tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter"
depends on PCI && SCSI
help
- This driver supports all of ARECA's SATA RAID controller cards.
+ This driver supports all of ARECA's SATA/SAS RAID controller cards.
This is an ARECA-maintained driver by Erich Chen.
- If you have any problems, please mail to: < erich@areca.com.tw >
+ If you have any problems, please mail to: <erich@areca.com.tw>.
Areca supports Linux RAID config tools.
-
- < http://www.areca.com.tw >
+ Please link <http://www.areca.com.tw>
To compile this driver as a module, choose M here: the
module will be called arcmsr (modprobe arcmsr).
+config SCSI_ARCMSR_AER
+ bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)"
+ depends on SCSI_ARCMSR && PCIEAER
+ default n
+ help
+ The advanced error reporting(AER) capability is "NOT" provided by
+ ARC1200/1201/1202 SATA RAID controllers cards.
+ If your card is one of ARC1200/1201/1202, please use the default setting, n.
+ If your card is other models, you could pick it
+ on condition that the kernel version is greater than 2.6.19.
+ This function is maintained driver by Nick Cheng. If you have any
+ problems or suggestion, you are welcome to contact with <nick.cheng@areca.com.tw>.
+ To enable this function, choose Y here.
+
source "drivers/scsi/megaraid/Kconfig.megaraid"
config SCSI_HPTIOP
@@ -836,6 +869,7 @@ config SCSI_IPS
config SCSI_IBMVSCSI
tristate "IBM Virtual SCSI support"
depends on PPC_PSERIES || PPC_ISERIES
+ select SCSI_SRP_ATTRS
help
This is the IBM POWER Virtual SCSI Client
@@ -844,7 +878,7 @@ config SCSI_IBMVSCSI
config SCSI_IBMVSCSIS
tristate "IBM Virtual SCSI Server support"
- depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
+ depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS
help
This is the SRP target driver for IBM pSeries virtual environments.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 86a7ba7bad6..6141389dcdb 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
+obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index f8e449a98d2..988f0bc5eda 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -1542,9 +1542,7 @@ part2:
hostdata->connected = cmd;
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- if (cmd->SCp.ptr != (char *)cmd->sense_buffer) {
- initialize_SCp(cmd);
- }
+ initialize_SCp(cmd);
return 0;
@@ -2133,7 +2131,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
/*
@@ -2196,7 +2194,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else
cmd->SCp.this_residual -= transfersize - len;
@@ -2280,19 +2278,16 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
-
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->sense_buffer;
- cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
LIST(cmd, hostdata->issue_queue);
cmd->host_scribble = (unsigned char *)
@@ -2740,7 +2735,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
- tmp->done(tmp);
+ tmp->scsi_done(tmp);
return SUCCESS;
}
#if (NDEBUG & NDEBUG_ABORT)
@@ -2805,7 +2800,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
*prev = (Scsi_Cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
- tmp->done(tmp);
+ tmp->scsi_done(tmp);
return SUCCESS;
}
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index bccf13f7153..bdc468c9e1d 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -30,6 +30,10 @@
#include <linux/interrupt.h>
+#ifdef AUTOSENSE
+#include <scsi/scsi_eh.h>
+#endif
+
#define NCR5380_PUBLIC_RELEASE 7
#define NCR53C400_PUBLIC_RELEASE 2
@@ -281,6 +285,9 @@ struct NCR5380_hostdata {
unsigned pendingr;
unsigned pendingw;
#endif
+#ifdef AUTOSENSE
+ struct scsi_eh_save ses;
+#endif
};
#ifdef __KERNEL__
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 79b4df15814..96e8e29aa05 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -1385,7 +1385,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
this->host_scribble = NULL;
esp_release_dmabufs(esp, this);
this->result = DID_ABORT << 16;
- this->done(this);
+ this->scsi_done(this);
if(don)
esp->dma_ints_on(esp);
return SUCCESS;
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 3a8089705fe..9e64b21ef63 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -97,7 +97,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mca.h>
-#include <linux/interrupt.h>
#include <asm/io.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
@@ -314,10 +313,10 @@ NCR_D700_probe(struct device *dev)
break;
}
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, '\0', sizeof(*p));
+
p->dev = dev;
snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
index 0c758d1452b..d4bda201774 100644
--- a/drivers/scsi/a4000t.c
+++ b/drivers/scsi/a4000t.c
@@ -37,7 +37,7 @@ static struct platform_device *a4000t_scsi_device;
static int __devinit a4000t_probe(struct device *dev)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
@@ -47,12 +47,11 @@ static int __devinit a4000t_probe(struct device *dev)
"A4000T builtin SCSI"))
goto out;
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
goto out_release;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6800e578e4b..80e448d0f3d 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -177,9 +177,9 @@ int check_interval = 24 * 60 * 60;
module_param(check_interval, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
-int check_reset = 1;
-module_param(check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+int aac_check_reset = 1;
+module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
@@ -1305,7 +1305,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
(int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
dev->supplement_adapter_info.VpdInfo.Tsid);
}
- if (!check_reset ||
+ if (!aac_check_reset ||
(dev->supplement_adapter_info.SupportedOptions2 &
le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 94727b9375e..03b51025a8f 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1871,4 +1871,4 @@ extern int aac_reset_devices;
extern int aac_commit;
extern int update_interval;
extern int check_interval;
-extern int check_reset;
+extern int aac_check_reset;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index bb870906b4c..240a0bb8986 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1372,8 +1372,9 @@ int aac_check_health(struct aac_dev * aac)
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
- if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
- le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+ if (!aac_check_reset ||
+ (aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
goto out;
host = aac->scsi_host_ptr;
if (aac->thread->pid != current->pid)
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 79c0b6e37a3..9dd3952516c 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,765 +1,27 @@
-#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */
+#define DRV_NAME "advansys"
+#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
*
* Copyright (c) 1995-2000 Advanced System Products, Inc.
* Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
+ * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
* All Rights Reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
- * changed its name to ConnectCom Solutions, 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.
*/
/*
-
- Documentation for the AdvanSys Driver
-
- A. Linux Kernels Supported by this Driver
- B. Adapters Supported by this Driver
- C. Linux source files modified by AdvanSys Driver
- D. Source Comments
- E. Driver Compile Time Options and Debugging
- F. Driver LILO Option
- G. Tests to run before releasing new driver
- H. Release History
- I. Known Problems/Fix List
- J. Credits (Chronological Order)
-
- A. Linux Kernels Supported by this Driver
-
- This driver has been tested in the following Linux kernels: v2.2.18
- v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
- alpha, and PowerPC platforms.
-
- B. Adapters Supported by this Driver
-
- AdvanSys (Advanced System Products, Inc.) manufactures the following
- RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
- (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
- buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
- transfer) SCSI Host Adapters for the PCI bus.
-
- The CDB counts below indicate the number of SCSI CDB (Command
- Descriptor Block) requests that can be stored in the RISC chip
- cache and board LRAM. A CDB is a single SCSI command. The driver
- detect routine will display the number of CDBs available for each
- adapter detected. The number of CDBs used by the driver can be
- lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
-
- Laptop Products:
- ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
-
- Connectivity Products:
- ABP510/5150 - Bus-Master ISA (240 CDB)
- ABP5140 - Bus-Master ISA PnP (16 CDB)
- ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
- ABP902/3902 - Bus-Master PCI (16 CDB)
- ABP3905 - Bus-Master PCI (16 CDB)
- ABP915 - Bus-Master PCI (16 CDB)
- ABP920 - Bus-Master PCI (16 CDB)
- ABP3922 - Bus-Master PCI (16 CDB)
- ABP3925 - Bus-Master PCI (16 CDB)
- ABP930 - Bus-Master PCI (16 CDB)
- ABP930U - Bus-Master PCI Ultra (16 CDB)
- ABP930UA - Bus-Master PCI Ultra (16 CDB)
- ABP960 - Bus-Master PCI MAC/PC (16 CDB)
- ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
-
- Single Channel Products:
- ABP542 - Bus-Master ISA with floppy (240 CDB)
- ABP742 - Bus-Master EISA (240 CDB)
- ABP842 - Bus-Master VL (240 CDB)
- ABP940 - Bus-Master PCI (240 CDB)
- ABP940U - Bus-Master PCI Ultra (240 CDB)
- ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
- ABP970 - Bus-Master PCI MAC/PC (240 CDB)
- ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
- ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
- ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
- ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
- ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
-
- Multi-Channel Products:
- ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
- ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
- ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
- ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
- ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
- ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
- ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
- ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
- ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
-
- C. Linux source files modified by AdvanSys Driver
-
- This section for historical purposes documents the changes
- originally made to the Linux kernel source to add the advansys
- driver. As Linux has changed some of these files have also
- been modified.
-
- 1. linux/arch/i386/config.in:
-
- bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
-
- 2. linux/drivers/scsi/hosts.c:
-
- #ifdef CONFIG_SCSI_ADVANSYS
- #include "advansys.h"
- #endif
-
- and after "static struct scsi_host_template builtin_scsi_hosts[] =":
-
- #ifdef CONFIG_SCSI_ADVANSYS
- ADVANSYS,
- #endif
-
- 3. linux/drivers/scsi/Makefile:
-
- ifdef CONFIG_SCSI_ADVANSYS
- SCSI_SRCS := $(SCSI_SRCS) advansys.c
- SCSI_OBJS := $(SCSI_OBJS) advansys.o
- else
- SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
- endif
-
- 4. linux/init/main.c:
-
- extern void advansys_setup(char *str, int *ints);
-
- and add the following lines to the bootsetups[] array.
-
- #ifdef CONFIG_SCSI_ADVANSYS
- { "advansys=", advansys_setup },
- #endif
-
- D. Source Comments
-
- 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
-
- 2. This driver should be maintained in multiple files. But to make
- it easier to include with Linux and to follow Linux conventions,
- the whole driver is maintained in the source files advansys.h and
- advansys.c. In this file logical sections of the driver begin with
- a comment that contains '---'. The following are the logical sections
- of the driver below.
-
- --- Linux Version
- --- Linux Include File
- --- Driver Options
- --- Debugging Header
- --- Asc Library Constants and Macros
- --- Adv Library Constants and Macros
- --- Driver Constants and Macros
- --- Driver Structures
- --- Driver Data
- --- Driver Function Prototypes
- --- Linux 'struct scsi_host_template' and advansys_setup() Functions
- --- Loadable Driver Support
- --- Miscellaneous Driver Functions
- --- Functions Required by the Asc Library
- --- Functions Required by the Adv Library
- --- Tracing and Debugging Functions
- --- Asc Library Functions
- --- Adv Library Functions
-
- 3. The string 'XXX' is used to flag code that needs to be re-written
- or that contains a problem that needs to be addressed.
-
- 4. I have stripped comments from and reformatted the source for the
- Asc Library and Adv Library to reduce the size of this file. This
- source can be found under the following headings. The Asc Library
- is used to support Narrow Boards. The Adv Library is used to
- support Wide Boards.
-
- --- Asc Library Constants and Macros
- --- Adv Library Constants and Macros
- --- Asc Library Functions
- --- Adv Library Functions
-
- E. Driver Compile Time Options and Debugging
-
- In this source file the following constants can be defined. They are
- defined in the source below. Both of these options are enabled by
- default.
-
- 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
-
- Enabling this option adds assertion logic statements to the
- driver. If an assertion fails a message will be displayed to
- the console, but the system will continue to operate. Any
- assertions encountered should be reported to the person
- responsible for the driver. Assertion statements may proactively
- detect problems with the driver and facilitate fixing these
- problems. Enabling assertions will add a small overhead to the
- execution of the driver.
-
- 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
-
- Enabling this option adds tracing functions to the driver and
- the ability to set a driver tracing level at boot time. This
- option will also export symbols not required outside the driver to
- the kernel name space. This option is very useful for debugging
- the driver, but it will add to the size of the driver execution
- image and add overhead to the execution of the driver.
-
- The amount of debugging output can be controlled with the global
- variable 'asc_dbglvl'. The higher the number the more output. By
- default the debug level is 0.
-
- If the driver is loaded at boot time and the LILO Driver Option
- is included in the system, the debug level can be changed by
- specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
- first three hex digits of the pseudo I/O Port must be set to
- 'deb' and the fourth hex digit specifies the debug level: 0 - F.
- The following command line will look for an adapter at 0x330
- and set the debug level to 2.
-
- linux advansys=0x330,0,0,0,0xdeb2
-
- If the driver is built as a loadable module this variable can be
- defined when the driver is loaded. The following insmod command
- will set the debug level to one.
-
- insmod advansys.o asc_dbglvl=1
-
- Debugging Message Levels:
- 0: Errors Only
- 1: High-Level Tracing
- 2-N: Verbose Tracing
-
- To enable debug output to console, please make sure that:
-
- a. System and kernel logging is enabled (syslogd, klogd running).
- b. Kernel messages are routed to console output. Check
- /etc/syslog.conf for an entry similar to this:
-
- kern.* /dev/console
-
- c. klogd is started with the appropriate -c parameter
- (e.g. klogd -c 8)
-
- This will cause printk() messages to be be displayed on the
- current console. Refer to the klogd(8) and syslogd(8) man pages
- for details.
-
- Alternatively you can enable printk() to console with this
- program. However, this is not the 'official' way to do this.
- Debug output is logged in /var/log/messages.
-
- main()
- {
- syscall(103, 7, 0, 0);
- }
-
- Increasing LOG_BUF_LEN in kernel/printk.c to something like
- 40960 allows more debug messages to be buffered in the kernel
- and written to the console or log file.
-
- 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
-
- Enabling this option adds statistics collection and display
- through /proc to the driver. The information is useful for
- monitoring driver and device performance. It will add to the
- size of the driver execution image and add minor overhead to
- the execution of the driver.
-
- Statistics are maintained on a per adapter basis. Driver entry
- point call counts and transfer size counts are maintained.
- Statistics are only available for kernels greater than or equal
- to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
-
- AdvanSys SCSI adapter files have the following path name format:
-
- /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
-
- This information can be displayed with cat. For example:
-
- cat /proc/scsi/advansys/0
-
- When ADVANSYS_STATS is not defined the AdvanSys /proc files only
- contain adapter and device configuration information.
-
- F. Driver LILO Option
-
- If init/main.c is modified as described in the 'Directions for Adding
- the AdvanSys Driver to Linux' section (B.4.) above, the driver will
- recognize the 'advansys' LILO command line and /etc/lilo.conf option.
- This option can be used to either disable I/O port scanning or to limit
- scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
- PCI boards will still be searched for and detected. This option only
- affects searching for ISA and VL boards.
-
- Examples:
- 1. Eliminate I/O port scanning:
- boot: linux advansys=
- or
- boot: linux advansys=0x0
- 2. Limit I/O port scanning to one I/O port:
- boot: linux advansys=0x110
- 3. Limit I/O port scanning to four I/O ports:
- boot: linux advansys=0x110,0x210,0x230,0x330
-
- For a loadable module the same effect can be achieved by setting
- the 'asc_iopflag' variable and 'asc_ioport' array when loading
- the driver, e.g.
-
- insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
-
- If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
- I/O Port may be added to specify the driver debug level. Refer to
- the 'Driver Compile Time Options and Debugging' section above for
- more information.
-
- G. Tests to run before releasing new driver
-
- 1. In the supported kernels verify there are no warning or compile
- errors when the kernel is built as both a driver and as a module
- and with the following options:
-
- ADVANSYS_DEBUG - enabled and disabled
- CONFIG_SMP - enabled and disabled
- CONFIG_PROC_FS - enabled and disabled
-
- 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
- card and one wide card attached to a hard disk and CD-ROM drive:
- fdisk, mkfs, fsck, bonnie, copy/compare test from the
- CD-ROM to the hard drive.
-
- H. Release History
-
- BETA-1.0 (12/23/95):
- First Release
-
- BETA-1.1 (12/28/95):
- 1. Prevent advansys_detect() from being called twice.
- 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
-
- 1.2 (1/12/96):
- 1. Prevent re-entrancy in the interrupt handler which
- resulted in the driver hanging Linux.
- 2. Fix problem that prevented ABP-940 cards from being
- recognized on some PCI motherboards.
- 3. Add support for the ABP-5140 PnP ISA card.
- 4. Fix check condition return status.
- 5. Add conditionally compiled code for Linux v1.3.X.
-
- 1.3 (2/23/96):
- 1. Fix problem in advansys_biosparam() that resulted in the
- wrong drive geometry being returned for drives > 1GB with
- extended translation enabled.
- 2. Add additional tracing during device initialization.
- 3. Change code that only applies to ISA PnP adapter.
- 4. Eliminate 'make dep' warning.
- 5. Try to fix problem with handling resets by increasing their
- timeout value.
-
- 1.4 (5/8/96):
- 1. Change definitions to eliminate conflicts with other subsystems.
- 2. Add versioning code for the shared interrupt changes.
- 3. Eliminate problem in asc_rmqueue() with iterating after removing
- a request.
- 4. Remove reset request loop problem from the "Known Problems or
- Issues" section. This problem was isolated and fixed in the
- mid-level SCSI driver.
-
- 1.5 (8/8/96):
- 1. Add support for ABP-940U (PCI Ultra) adapter.
- 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
- request_irq and supplying a dev_id pointer to both request_irq()
- and free_irq().
- 3. In AscSearchIOPortAddr11() restore a call to check_region() which
- should be used before I/O port probing.
- 4. Fix bug in asc_prt_hex() which resulted in the displaying
- the wrong data.
- 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
- 6. Change driver versioning to be specific to each Linux sub-level.
- 7. Change statistics gathering to be per adapter instead of global
- to the driver.
- 8. Add more information and statistics to the adapter /proc file:
- /proc/scsi/advansys[0...].
- 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
- This problem has been addressed with the SCSI mid-level changes
- made in v1.3.89. The advansys_select_queue_depths() function
- was added for the v1.3.89 changes.
-
- 1.6 (9/10/96):
- 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
-
- 1.7 (9/25/96):
- 1. Enable clustering and optimize the setting of the maximum number
- of scatter gather elements for any particular board. Clustering
- increases CPU utilization, but results in a relatively larger
- increase in I/O throughput.
- 2. Improve the performance of the request queuing functions by
- adding a last pointer to the queue structure.
- 3. Correct problems with reset and abort request handling that
- could have hung or crashed Linux.
- 4. Add more information to the adapter /proc file:
- /proc/scsi/advansys[0...].
- 5. Remove the request timeout issue form the driver issues list.
- 6. Miscellaneous documentation additions and changes.
-
- 1.8 (10/4/96):
- 1. Make changes to handle the new v2.1.0 kernel memory mapping
- in which a kernel virtual address may not be equivalent to its
- bus or DMA memory address.
- 2. Change abort and reset request handling to make it yet even
- more robust.
- 3. Try to mitigate request starvation by sending ordered requests
- to heavily loaded, tag queuing enabled devices.
- 4. Maintain statistics on request response time.
- 5. Add request response time statistics and other information to
- the adapter /proc file: /proc/scsi/advansys[0...].
-
- 1.9 (10/21/96):
- 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
- make use of mid-level SCSI driver device queue depth flow
- control mechanism. This will eliminate aborts caused by a
- device being unable to keep up with requests and eliminate
- repeat busy or QUEUE FULL status returned by a device.
- 2. Incorporate miscellaneous Asc Library bug fixes.
- 3. To allow the driver to work in kernels with broken module
- support set 'cmd_per_lun' if the driver is compiled as a
- module. This change affects kernels v1.3.89 to present.
- 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
- is relocated by the motherboard BIOS and its new address can
- not be determined by the driver.
- 5. Add mid-level SCSI queue depth information to the adapter
- /proc file: /proc/scsi/advansys[0...].
-
- 2.0 (11/14/96):
- 1. Change allocation of global structures used for device
- initialization to guarantee they are in DMA-able memory.
- Previously when the driver was loaded as a module these
- structures might not have been in DMA-able memory, causing
- device initialization to fail.
-
- 2.1 (12/30/96):
- 1. In advansys_reset(), if the request is a synchronous reset
- request, even if the request serial number has changed, then
- complete the request.
- 2. Add Asc Library bug fixes including new microcode.
- 3. Clear inquiry buffer before using it.
- 4. Correct ifdef typo.
-
- 2.2 (1/15/97):
- 1. Add Asc Library bug fixes including new microcode.
- 2. Add synchronous data transfer rate information to the
- adapter /proc file: /proc/scsi/advansys[0...].
- 3. Change ADVANSYS_DEBUG to be disabled by default. This
- will reduce the size of the driver image, eliminate execution
- overhead, and remove unneeded symbols from the kernel symbol
- space that were previously added by the driver.
- 4. Add new compile-time option ADVANSYS_ASSERT for assertion
- code that used to be defined within ADVANSYS_DEBUG. This
- option is enabled by default.
-
- 2.8 (5/26/97):
- 1. Change version number to 2.8 to synchronize the Linux driver
- version numbering with other AdvanSys drivers.
- 2. Reformat source files without tabs to present the same view
- of the file to everyone regardless of the editor tab setting
- being used.
- 3. Add Asc Library bug fixes.
-
- 3.1A (1/8/98):
- 1. Change version number to 3.1 to indicate that support for
- Ultra-Wide adapters (ABP-940UW) is included in this release.
- 2. Add Asc Library (Narrow Board) bug fixes.
- 3. Report an underrun condition with the host status byte set
- to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
- causes the underrun condition to be ignored. When Linux defines
- its own DID_UNDERRUN the constant defined in this file can be
- removed.
- 4. Add patch to AscWaitTixISRDone().
- 5. Add support for up to 16 different AdvanSys host adapter SCSI
- channels in one system. This allows four cards with four channels
- to be used in one system.
-
- 3.1B (1/9/98):
- 1. Handle that PCI register base addresses are not always page
- aligned even though ioremap() requires that the address argument
- be page aligned.
-
- 3.1C (1/10/98):
- 1. Update latest BIOS version checked for from the /proc file.
- 2. Don't set microcode SDTR variable at initialization. Instead
- wait until device capabilities have been detected from an Inquiry
- command.
-
- 3.1D (1/21/98):
- 1. Improve performance when the driver is compiled as module by
- allowing up to 64 scatter-gather elements instead of 8.
-
- 3.1E (5/1/98):
- 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
- 2. Include SMP locking changes.
- 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
- access functions.
- 4. Update board serial number printing.
- 5. Try allocating an IRQ both with and without the IRQF_DISABLED
- flag set to allow IRQ sharing with drivers that do not set
- the IRQF_DISABLED flag. Also display a more descriptive error
- message if request_irq() fails.
- 6. Update to latest Asc and Adv Libraries.
-
- 3.2A (7/22/99):
- 1. Update Adv Library to 4.16 which includes support for
- the ASC38C0800 (Ultra2/LVD) IC.
-
- 3.2B (8/23/99):
- 1. Correct PCI compile time option for v2.1.93 and greater
- kernels, advansys_info() string, and debug compile time
- option.
- 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
- kernels. This caused an LVD detection/BIST problem problem
- among other things.
- 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
- to be consistent with the BIOS.
- 4. Update to Asc Library S121 and Adv Library 5.2.
-
- 3.2C (8/24/99):
- 1. Correct PCI card detection bug introduced in 3.2B that
- prevented PCI cards from being detected in kernels older
- than v2.1.93.
-
- 3.2D (8/26/99):
- 1. Correct /proc device synchronous speed information display.
- Also when re-negotiation is pending for a target device
- note this condition with an * and footnote.
- 2. Correct initialization problem with Ultra-Wide cards that
- have a pre-3.2 BIOS. A microcode variable changed locations
- in 3.2 and greater BIOSes which caused WDTR to be attempted
- erroneously with drives that don't support WDTR.
-
- 3.2E (8/30/99):
- 1. Fix compile error caused by v2.3.13 PCI structure change.
- 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
- checksum error for ISA cards.
- 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
- SCSI changes that it depended on were never included in Linux.
-
- 3.2F (9/3/99):
- 1. Handle new initial function code added in v2.3.16 for all
- driver versions.
-
- 3.2G (9/8/99):
- 1. Fix PCI board detection in v2.3.13 and greater kernels.
- 2. Fix comiple errors in v2.3.X with debugging enabled.
-
- 3.2H (9/13/99):
- 1. Add 64-bit address, long support for Alpha and UltraSPARC.
- The driver has been verified to work on an Alpha system.
- 2. Add partial byte order handling support for Power PC and
- other big-endian platforms. This support has not yet been
- completed or verified.
- 3. For wide boards replace block zeroing of request and
- scatter-gather structures with individual field initialization
- to improve performance.
- 4. Correct and clarify ROM BIOS version detection.
-
- 3.2I (10/8/99):
- 1. Update to Adv Library 5.4.
- 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
- adv_isr_callback(). Remove DID_UNDERRUN constant and other
- no longer needed code that previously documented the lack
- of underrun handling.
-
- 3.2J (10/14/99):
- 1. Eliminate compile errors for v2.0 and earlier kernels.
-
- 3.2K (11/15/99):
- 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
- 2. Update Adv Library to 5.5.
- 3. Add ifdef handling for /proc changes added in v2.3.28.
- 4. Increase Wide board scatter-gather list maximum length to
- 255 when the driver is compiled into the kernel.
-
- 3.2L (11/18/99):
- 1. Fix bug in adv_get_sglist() that caused an assertion failure
- at line 7475. The reqp->sgblkp pointer must be initialized
- to NULL in adv_get_sglist().
-
- 3.2M (11/29/99):
- 1. Really fix bug in adv_get_sglist().
- 2. Incorporate v2.3.29 changes into driver.
-
- 3.2N (4/1/00):
- 1. Add CONFIG_ISA ifdef code.
- 2. Include advansys_interrupts_enabled name change patch.
- 3. For >= v2.3.28 use new SCSI error handling with new function
- advansys_eh_bus_reset(). Don't include an abort function
- because of base library limitations.
- 4. For >= v2.3.28 use per board lock instead of io_request_lock.
- 5. For >= v2.3.28 eliminate advansys_command() and
- advansys_command_done().
- 6. Add some changes for PowerPC (Big Endian) support, but it isn't
- working yet.
- 7. Fix "nonexistent resource free" problem that occurred on a module
- unload for boards with an I/O space >= 255. The 'n_io_port' field
- is only one byte and can not be used to hold an ioport length more
- than 255.
-
- 3.3A (4/4/00):
- 1. Update to Adv Library 5.8.
- 2. For wide cards add support for CDBs up to 16 bytes.
- 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
-
- 3.3B (5/1/00):
- 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
- still need work.
- 2. Change bitfields to shift and mask access for endian
- portability.
-
- 3.3C (10/13/00):
- 1. Update for latest 2.4 kernel.
- 2. Test ABP-480 CardBus support in 2.4 kernel - works!
- 3. Update to Asc Library S123.
- 4. Update to Adv Library 5.12.
-
- 3.3D (11/22/00):
- 1. Update for latest 2.4 kernel.
- 2. Create patches for 2.2 and 2.4 kernels.
-
- 3.3E (1/9/01):
- 1. Now that 2.4 is released remove ifdef code for kernel versions
- less than 2.2. The driver is now only supported in kernels 2.2,
- 2.4, and greater.
- 2. Add code to release and acquire the io_request_lock in
- the driver entrypoint functions: advansys_detect and
- advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
- still holds the io_request_lock on entry to SCSI low-level drivers.
- This was supposed to be removed before 2.4 was released but never
- happened. When the mid-level SCSI driver is changed all references
- to the io_request_lock should be removed from the driver.
- 3. Simplify error handling by removing advansys_abort(),
- AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
- now handled by resetting the SCSI bus and fully re-initializing
- the chip. This simple method of error recovery has proven to work
- most reliably after attempts at different methods. Also now only
- support the "new" error handling method and remove the obsolete
- error handling interface.
- 4. Fix debug build errors.
-
- 3.3F (1/24/01):
- 1. Merge with ConnectCom version from Andy Kellner which
- updates Adv Library to 5.14.
- 2. Make PowerPC (Big Endian) work for narrow cards and
- fix problems writing EEPROM for wide cards.
- 3. Remove interrupts_enabled assertion function.
-
- 3.3G (2/16/01):
- 1. Return an error from narrow boards if passed a 16 byte
- CDB. The wide board can already handle 16 byte CDBs.
-
- 3.3GJ (4/15/02):
- 1. hacks for lk 2.5 series (D. Gilbert)
-
- 3.3GJD (10/14/02):
- 1. change select_queue_depths to slave_configure
- 2. make cmd_per_lun be sane again
-
- 3.3K [2004/06/24]:
- 1. continuing cleanup for lk 2.6 series
- 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
- 3. Fix problem that oopsed ISA cards
-
- I. Known Problems/Fix List (XXX)
-
- 1. Need to add memory mapping workaround. Test the memory mapping.
- If it doesn't work revert to I/O port access. Can a test be done
- safely?
- 2. Handle an interrupt not working. Keep an interrupt counter in
- the interrupt handler. In the timeout function if the interrupt
- has not occurred then print a message and run in polled mode.
- 3. Allow bus type scanning order to be changed.
- 4. Need to add support for target mode commands, cf. CAM XPT.
-
- J. Credits (Chronological Order)
-
- Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
- and maintained it up to 3.3F. He continues to answer questions
- and help maintain the driver.
-
- Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
- basis for the Linux v1.3.X changes which were included in the
- 1.2 release.
-
- Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
- in advansys_biosparam() which was fixed in the 1.3 release.
-
- Erik Ratcliffe <erik@caldera.com> has done testing of the
- AdvanSys driver in the Caldera releases.
-
- Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
- AscWaitTixISRDone() which he found necessary to make the
- driver work with a SCSI-1 disk.
-
- Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
- support in the 3.1A driver.
-
- Doug Gilbert <dgilbert@interlog.com> has made changes and
- suggestions to improve the driver and done a lot of testing.
-
- Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
- in 3.2K.
-
- Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
- patch and helped with PowerPC wide and narrow board support.
-
- Philip Blundell <philb@gnu.org> provided an
- advansys_interrupts_enabled patch.
-
- Dave Jones <dave@denial.force9.co.uk> reported the compiler
- warnings generated when CONFIG_PROC_FS was not defined in
- the 3.2M driver.
-
- Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
- problems) for wide cards.
-
- Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
- card error handling.
-
- Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
- board support and fixed a bug in AscGetEEPConfig().
-
- Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
- save_flags/restore_flags changes.
-
- Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
- driver development for ConnectCom (Version > 3.3F).
-
- K. ConnectCom (AdvanSys) Contact Information
-
- Mail: ConnectCom Solutions, Inc.
- 1150 Ringwood Court
- San Jose, CA 95131
- Operator/Sales: 1-408-383-9400
- FAX: 1-408-383-9612
- Tech Support: 1-408-467-2930
- Tech Support E-Mail: linux@connectcom.net
- FTP Site: ftp.connectcom.net (login: anonymous)
- Web Site: http://www.connectcom.net
-
-*/
-
-/*
- * --- Linux Include Files
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
*/
#include <linux/module.h>
-
-#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
-#define CONFIG_ISA
-#endif /* CONFIG_X86 && !CONFIG_ISA */
-
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -771,7 +33,9 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/blkdev.h>
-#include <linux/stat.h>
+#include <linux/isa.h>
+#include <linux/eisa.h>
+#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
@@ -779,49 +43,38 @@
#include <asm/system.h>
#include <asm/dma.h>
-/* FIXME: (by jejb@steeleye.com) This warning is present for two
- * reasons:
- *
- * 1) This driver badly needs converting to the correct driver model
- * probing API
- *
- * 2) Although all of the necessary command mapping places have the
- * appropriate dma_map.. APIs, the driver still processes its internal
- * queue using bus_to_virt() and virt_to_bus() which are illegal under
- * the API. The entire queue processing structure will need to be
- * altered to fix this.
- */
-#warning this driver is still not properly converted to the DMA API
-
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif /* CONFIG_PCI */
-/*
- * --- Driver Options
+/* FIXME:
+ *
+ * 1. Although all of the necessary command mapping places have the
+ * appropriate dma_map.. APIs, the driver still processes its internal
+ * queue using bus_to_virt() and virt_to_bus() which are illegal under
+ * the API. The entire queue processing structure will need to be
+ * altered to fix this.
+ * 2. Need to add memory mapping workaround. Test the memory mapping.
+ * If it doesn't work revert to I/O port access. Can a test be done
+ * safely?
+ * 3. Handle an interrupt not working. Keep an interrupt counter in
+ * the interrupt handler. In the timeout function if the interrupt
+ * has not occurred then print a message and run in polled mode.
+ * 4. Need to add support for target mode commands, cf. CAM XPT.
+ * 5. check DMA mapping functions for failure
+ * 6. Use scsi_transport_spi
+ * 7. advansys_info is not safe against multiple simultaneous callers
+ * 8. Add module_param to override ISA/VLB ioport array
*/
-
-/* Enable driver assertions. */
-#define ADVANSYS_ASSERT
+#warning this driver is still not properly converted to the DMA API
/* Enable driver /proc statistics. */
#define ADVANSYS_STATS
/* Enable driver tracing. */
-/* #define ADVANSYS_DEBUG */
-
-/*
- * --- Asc Library Constants and Macros
- */
-
-#define ASC_LIB_VERSION_MAJOR 1
-#define ASC_LIB_VERSION_MINOR 24
-#define ASC_LIB_SERIAL_NUMBER 123
+#undef ADVANSYS_DEBUG
/*
* Portable Data Types
@@ -837,17 +90,6 @@
#define ASC_DCNT __u32 /* Unsigned Data count type. */
#define ASC_SDCNT __s32 /* Signed Data count type. */
-/*
- * These macros are used to convert a virtual address to a
- * 32-bit value. This currently can be used on Linux Alpha
- * which uses 64-bit virtual address but a 32-bit bus address.
- * This is likely to break in the future, but doing this now
- * will give us time to change the HW and FW to handle 64-bit
- * addresses.
- */
-#define ASC_VADDR_TO_U32 virt_to_bus
-#define ASC_U32_TO_VADDR bus_to_virt
-
typedef unsigned char uchar;
#ifndef TRUE
@@ -857,29 +99,9 @@ typedef unsigned char uchar;
#define FALSE (0)
#endif
-#define EOF (-1)
#define ERR (-1)
#define UW_ERR (uint)(0xFFFF)
#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
-#define AscPCIConfigVendorIDRegister 0x0000
-#define AscPCIConfigDeviceIDRegister 0x0002
-#define AscPCIConfigCommandRegister 0x0004
-#define AscPCIConfigStatusRegister 0x0006
-#define AscPCIConfigRevisionIDRegister 0x0008
-#define AscPCIConfigCacheSize 0x000C
-#define AscPCIConfigLatencyTimer 0x000D
-#define AscPCIIOBaseRegister 0x0010
-#define AscPCICmdRegBits_IOMemBusMaster 0x0007
-#define ASC_PCI_ID2BUS(id) ((id) & 0xFF)
-#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
-#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
-#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
-#define ASC_PCI_REVISION_3150 0x02
-#define ASC_PCI_REVISION_3050 0x03
-
-#define ASC_DVCLIB_CALL_DONE (1)
-#define ASC_DVCLIB_CALL_FAILED (0)
-#define ASC_DVCLIB_CALL_ERROR (-1)
#define PCI_VENDOR_ID_ASP 0x10cd
#define PCI_DEVICE_ID_ASP_1200A 0x1100
@@ -898,7 +120,7 @@ typedef unsigned char uchar;
#define CC_VERY_LONG_SG_LIST 0
#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
-#define PortAddr unsigned short /* port address size */
+#define PortAddr unsigned int /* port address size */
#define inp(port) inb(port)
#define outp(port, byte) outb((byte), (port))
@@ -918,11 +140,10 @@ typedef unsigned char uchar;
#define ASC_IS_PCMCIA (0x0008)
#define ASC_IS_MCA (0x0020)
#define ASC_IS_VL (0x0040)
-#define ASC_ISA_PNP_PORT_ADDR (0x279)
-#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
#define ASC_IS_WIDESCSI_16 (0x0100)
#define ASC_IS_WIDESCSI_32 (0x0200)
#define ASC_IS_BIG_ENDIAN (0x8000)
+
#define ASC_CHIP_MIN_VER_VL (0x01)
#define ASC_CHIP_MAX_VER_VL (0x07)
#define ASC_CHIP_MIN_VER_PCI (0x09)
@@ -941,16 +162,9 @@ typedef unsigned char uchar;
#define ASC_CHIP_MAX_VER_EISA (0x47)
#define ASC_CHIP_VER_EISA_BIT (0x40)
#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
-#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
-#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
-#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
-#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
-#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
-#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
-#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
#define ASC_SCSI_ID_BITS 3
#define ASC_SCSI_TIX_TYPE uchar
@@ -961,82 +175,17 @@ typedef unsigned char uchar;
#define ASC_SCSI_WIDTH_BIT_SET 0xFF
#define ASC_MAX_SENSE_LEN 32
#define ASC_MIN_SENSE_LEN 14
-#define ASC_MAX_CDB_LEN 12
#define ASC_SCSI_RESET_HOLD_TIME_US 60
-#define ADV_INQ_CLOCKING_ST_ONLY 0x0
-#define ADV_INQ_CLOCKING_DT_ONLY 0x1
-#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
-
/*
- * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
- * and CmdDt (Command Support Data) field bit definitions.
+ * Narrow boards only support 12-byte commands, while wide boards
+ * extend to 16-byte commands.
*/
-#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
-#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
-#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
-#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
-
-#define ASC_SCSIDIR_NOCHK 0x00
-#define ASC_SCSIDIR_T2H 0x08
-#define ASC_SCSIDIR_H2T 0x10
-#define ASC_SCSIDIR_NODATA 0x18
-#define SCSI_ASC_NOMEDIA 0x3A
-#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
-#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
-#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
-#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
-#define MS_CMD_DONE 0x00
-#define MS_EXTEND 0x01
+#define ASC_MAX_CDB_LEN 12
+#define ADV_MAX_CDB_LEN 16
+
#define MS_SDTR_LEN 0x03
-#define MS_SDTR_CODE 0x01
#define MS_WDTR_LEN 0x02
-#define MS_WDTR_CODE 0x03
-#define MS_MDP_LEN 0x05
-#define MS_MDP_CODE 0x00
-
-/*
- * Inquiry data structure and bitfield macros
- *
- * Only quantities of more than 1 bit are shifted, since the others are
- * just tested for true or false. C bitfields aren't portable between big
- * and little-endian platforms so they are not used.
- */
-
-#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
-#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
-#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
-#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
-#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
-#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
-#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
-#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
-#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
-#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
-#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
-#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
-#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
-#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
-#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
-#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
-#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
-#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
-#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
-#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
- uchar periph;
- uchar devtype;
- uchar ver;
- uchar byte3;
- uchar add_len;
- uchar res1;
- uchar res2;
- uchar flags;
- uchar vendor_id[8];
- uchar product_id[16];
- uchar product_rev_level[4];
-} ASC_SCSI_INQUIRY;
#define ASC_SG_LIST_PER_Q 7
#define QS_FREE 0x00
@@ -1215,22 +364,9 @@ typedef struct asc_sg_head {
ushort queue_cnt;
ushort entry_to_copy;
ushort res;
- ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
+ ASC_SG_LIST sg_list[0];
} ASC_SG_HEAD;
-#define ASC_MIN_SG_LIST 2
-
-typedef struct asc_min_sg_head {
- ushort entry_cnt;
- ushort queue_cnt;
- ushort entry_to_copy;
- ushort res;
- ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
-} ASC_MIN_SG_HEAD;
-
-#define QCX_SORT (0x0001)
-#define QCX_COALEASE (0x0002)
-
typedef struct asc_scsi_q {
ASC_SCSIQ_1 q1;
ASC_SCSIQ_2 q2;
@@ -1287,45 +423,12 @@ typedef struct asc_risc_sg_list_q {
ASC_SG_LIST sg_list[7];
} ASC_RISC_SG_LIST_Q;
-#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
-#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
-#define ASCQ_ERR_NO_ERROR 0
-#define ASCQ_ERR_IO_NOT_FOUND 1
-#define ASCQ_ERR_LOCAL_MEM 2
-#define ASCQ_ERR_CHKSUM 3
-#define ASCQ_ERR_START_CHIP 4
-#define ASCQ_ERR_INT_TARGET_ID 5
-#define ASCQ_ERR_INT_LOCAL_MEM 6
-#define ASCQ_ERR_HALT_RISC 7
-#define ASCQ_ERR_GET_ASPI_ENTRY 8
-#define ASCQ_ERR_CLOSE_ASPI 9
-#define ASCQ_ERR_HOST_INQUIRY 0x0A
-#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
-#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
#define ASCQ_ERR_Q_STATUS 0x0D
-#define ASCQ_ERR_WR_SCSIQ 0x0E
-#define ASCQ_ERR_PC_ADDR 0x0F
-#define ASCQ_ERR_SYN_OFFSET 0x10
-#define ASCQ_ERR_SYN_XFER_TIME 0x11
-#define ASCQ_ERR_LOCK_DMA 0x12
-#define ASCQ_ERR_UNLOCK_DMA 0x13
-#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
-#define ASCQ_ERR_MICRO_CODE_HALT 0x15
-#define ASCQ_ERR_SET_LRAM_ADDR 0x16
#define ASCQ_ERR_CUR_QNG 0x17
#define ASCQ_ERR_SG_Q_LINKS 0x18
-#define ASCQ_ERR_SCSIQ_PTR 0x19
#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
-#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
-#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
-#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
-#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
-#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
-#define ASCQ_ERR_SEND_SCSI_Q 0x22
-#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
-#define ASCQ_ERR_RESET_SDTR 0x24
/*
* Warning code values are set in ASC_DVC_VAR 'warn_code'.
@@ -1338,84 +441,51 @@ typedef struct asc_risc_sg_list_q {
#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
#define ASC_WARN_EEPROM_RECOVER 0x0020
#define ASC_WARN_CFG_MSW_RECOVER 0x0040
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
/*
- * Error code values are set in ASC_DVC_VAR 'err_code'.
+ * Error code values are set in {ASC/ADV}_DVC_VAR 'err_code'.
*/
-#define ASC_IERR_WRITE_EEPROM 0x0001
-#define ASC_IERR_MCODE_CHKSUM 0x0002
-#define ASC_IERR_SET_PC_ADDR 0x0004
-#define ASC_IERR_START_STOP_CHIP 0x0008
-#define ASC_IERR_IRQ_NO 0x0010
-#define ASC_IERR_SET_IRQ_NO 0x0020
-#define ASC_IERR_CHIP_VERSION 0x0040
-#define ASC_IERR_SET_SCSI_ID 0x0080
-#define ASC_IERR_GET_PHY_ADDR 0x0100
-#define ASC_IERR_BAD_SIGNATURE 0x0200
-#define ASC_IERR_NO_BUS_TYPE 0x0400
-#define ASC_IERR_SCAM 0x0800
-#define ASC_IERR_SET_SDTR 0x1000
-#define ASC_IERR_RW_LRAM 0x8000
-
-#define ASC_DEF_IRQ_NO 10
-#define ASC_MAX_IRQ_NO 15
-#define ASC_MIN_IRQ_NO 10
-#define ASC_MIN_REMAIN_Q (0x02)
+#define ASC_IERR_NO_CARRIER 0x0001 /* No more carrier memory */
+#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_SET_PC_ADDR 0x0004
+#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0010 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE 0x0020 /* SE device on DIFF bus */
+#define ASC_IERR_REVERSED_CABLE 0x0040 /* Narrow flat cable reversed */
+#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD device on LVD port */
+#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
+#define ASC_IERR_NO_BUS_TYPE 0x0400
+#define ASC_IERR_BIST_PRE_TEST 0x0800 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST 0x1000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE 0x2000 /* Invalid chip_type setting */
+
#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
#define ASC_MIN_TAG_Q_PER_DVC (0x04)
-#define ASC_DEF_TAG_Q_PER_DVC (0x04)
-#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
+#define ASC_MIN_FREE_Q (0x02)
#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
#define ASC_MAX_TOTAL_QNG 240
#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
#define ASC_MAX_INRAM_TAG_QNG 16
-#define ASC_IOADR_TABLE_MAX_IX 11
#define ASC_IOADR_GAP 0x10
-#define ASC_SEARCH_IOP_GAP 0x10
-#define ASC_MIN_IOP_ADDR (PortAddr)0x0100
-#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0
-#define ASC_IOADR_1 (PortAddr)0x0110
-#define ASC_IOADR_2 (PortAddr)0x0130
-#define ASC_IOADR_3 (PortAddr)0x0150
-#define ASC_IOADR_4 (PortAddr)0x0190
-#define ASC_IOADR_5 (PortAddr)0x0210
-#define ASC_IOADR_6 (PortAddr)0x0230
-#define ASC_IOADR_7 (PortAddr)0x0250
-#define ASC_IOADR_8 (PortAddr)0x0330
-#define ASC_IOADR_DEF ASC_IOADR_8
-#define ASC_LIB_SCSIQ_WK_SP 256
-#define ASC_MAX_SYN_XFER_NO 16
#define ASC_SYN_MAX_OFFSET 0x0F
#define ASC_DEF_SDTR_OFFSET 0x0F
-#define ASC_DEF_SDTR_INDEX 0x00
#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
-#define SYN_XFER_NS_0 25
-#define SYN_XFER_NS_1 30
-#define SYN_XFER_NS_2 35
-#define SYN_XFER_NS_3 40
-#define SYN_XFER_NS_4 50
-#define SYN_XFER_NS_5 60
-#define SYN_XFER_NS_6 70
-#define SYN_XFER_NS_7 85
-#define SYN_ULTRA_XFER_NS_0 12
-#define SYN_ULTRA_XFER_NS_1 19
-#define SYN_ULTRA_XFER_NS_2 25
-#define SYN_ULTRA_XFER_NS_3 32
-#define SYN_ULTRA_XFER_NS_4 38
-#define SYN_ULTRA_XFER_NS_5 44
-#define SYN_ULTRA_XFER_NS_6 50
-#define SYN_ULTRA_XFER_NS_7 57
-#define SYN_ULTRA_XFER_NS_8 63
-#define SYN_ULTRA_XFER_NS_9 69
-#define SYN_ULTRA_XFER_NS_10 75
-#define SYN_ULTRA_XFER_NS_11 82
-#define SYN_ULTRA_XFER_NS_12 88
-#define SYN_ULTRA_XFER_NS_13 94
-#define SYN_ULTRA_XFER_NS_14 100
-#define SYN_ULTRA_XFER_NS_15 107
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+
+/* The narrow chip only supports a limited selection of transfer rates.
+ * These are encoded in the range 0..7 or 0..15 depending whether the chip
+ * is Ultra-capable or not. These tables let us convert from one to the other.
+ */
+static const unsigned char asc_syn_xfer_period[8] = {
+ 25, 30, 35, 40, 50, 60, 70, 85
+};
+
+static const unsigned char asc_syn_ultra_xfer_period[16] = {
+ 12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107
+};
typedef struct ext_msg {
uchar msg_type;
@@ -1456,22 +526,16 @@ typedef struct asc_dvc_cfg {
uchar isa_dma_speed;
uchar isa_dma_channel;
uchar chip_version;
- ushort lib_serial_no;
- ushort lib_version;
ushort mcode_date;
ushort mcode_version;
uchar max_tag_qng[ASC_MAX_TID + 1];
- uchar *overrun_buf;
uchar sdtr_period_offset[ASC_MAX_TID + 1];
- ushort pci_slot_info;
uchar adapter_info[6];
- struct device *dev;
} ASC_DVC_CFG;
#define ASC_DEF_DVC_CNTL 0xFFFF
#define ASC_DEF_CHIP_SCSI_ID 7
#define ASC_DEF_ISA_DMA_SPEED 4
-#define ASC_INIT_STATE_NULL 0x0000
#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
#define ASC_INIT_STATE_END_GET_CFG 0x0002
#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
@@ -1484,43 +548,39 @@ typedef struct asc_dvc_cfg {
#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
-#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
#define ASC_MIN_TAGGED_CMD 7
#define ASC_MAX_SCSI_RESET_WAIT 30
+#define ASC_OVERRUN_BSIZE 64
struct asc_dvc_var; /* Forward Declaration. */
-typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
-typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
-
typedef struct asc_dvc_var {
PortAddr iop_base;
ushort err_code;
ushort dvc_cntl;
ushort bug_fix_cntl;
ushort bus_type;
- ASC_ISR_CALLBACK isr_callback;
- ASC_EXE_CALLBACK exe_callback;
ASC_SCSI_BIT_ID_TYPE init_sdtr;
ASC_SCSI_BIT_ID_TYPE sdtr_done;
ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
ASC_SCSI_BIT_ID_TYPE unit_not_ready;
ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
ASC_SCSI_BIT_ID_TYPE start_motor;
+ uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8);
+ dma_addr_t overrun_dma;
uchar scsi_reset_wait;
uchar chip_no;
char is_in_int;
uchar max_total_qng;
uchar cur_total_qng;
uchar in_critical_cnt;
- uchar irq_no;
uchar last_q_shortage;
ushort init_state;
uchar cur_dvc_qng[ASC_MAX_TID + 1];
uchar max_dvc_qng[ASC_MAX_TID + 1];
ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
- uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+ const uchar *sdtr_period_tbl;
ASC_DVC_CFG *cfg;
ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
char redo_scam;
@@ -1529,9 +589,11 @@ typedef struct asc_dvc_var {
ASC_DCNT max_dma_count;
ASC_SCSI_BIT_ID_TYPE no_scam;
ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+ uchar min_sdtr_index;
uchar max_sdtr_index;
- uchar host_init_sdtr_index;
struct asc_board *drv_ptr;
+ int ptr_map_count;
+ void **ptr_map;
ASC_DCNT uc_break;
} ASC_DVC_VAR;
@@ -1568,12 +630,7 @@ typedef struct asc_cap_info_array {
#define ASC_EEP_MAX_DVC_ADDR_VL 15
#define ASC_EEP_DVC_CFG_BEG 32
#define ASC_EEP_MAX_DVC_ADDR 45
-#define ASC_EEP_DEFINED_WORDS 10
-#define ASC_EEP_MAX_ADDR 63
-#define ASC_EEP_RES_WORDS 0
#define ASC_EEP_MAX_RETRY 20
-#define ASC_MAX_INIT_BUSY_RETRY 8
-#define ASC_EEP_ISA_PNP_WSIZE 16
/*
* These macros keep the chip SCSI id and ISA DMA speed
@@ -1609,17 +666,10 @@ typedef struct asceep_config {
ushort chksum;
} ASCEEP_CONFIG;
-#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
-#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
-#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
-
#define ASC_EEP_CMD_READ 0x80
#define ASC_EEP_CMD_WRITE 0x40
#define ASC_EEP_CMD_WRITE_ABLE 0x30
#define ASC_EEP_CMD_WRITE_DISABLE 0x00
-#define ASC_OVERRUN_BSIZE 0x00000048UL
-#define ASC_CTRL_BREAK_ONCE 0x0001
-#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
#define ASCV_MSGOUT_BEG 0x0000
#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
@@ -1796,16 +846,9 @@ typedef struct asceep_config {
#define ASC_1000_ID0W 0x04C1
#define ASC_1000_ID0W_FIX 0x00C1
#define ASC_1000_ID1B 0x25
-#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50)
-#define ASC_EISA_SMALL_IOP_GAP (0x0020)
-#define ASC_EISA_MIN_IOP_ADDR (0x0C30)
-#define ASC_EISA_MAX_IOP_ADDR (0xFC50)
#define ASC_EISA_REV_IOP_MASK (0x0C83)
-#define ASC_EISA_PID_IOP_MASK (0x0C80)
#define ASC_EISA_CFG_IOP_MASK (0x0C86)
#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
-#define ASC_EISA_ID_740 0x01745004UL
-#define ASC_EISA_ID_750 0x01755004UL
#define INS_HALTINT (ushort)0x6281
#define INS_HALT (ushort)0x6280
#define INS_SINT (ushort)0x6200
@@ -1828,11 +871,10 @@ typedef struct asc_mc_saved {
#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
-#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
-#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
-#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
-#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
+#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data))
+#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id))
+#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data)
+#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id))
#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
@@ -1887,125 +929,6 @@ typedef struct asc_mc_saved {
#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
-static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-static void AscWaitEEPRead(void);
-static void AscWaitEEPWrite(void);
-static ushort AscReadEEPWord(PortAddr, uchar);
-static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscStartChip(PortAddr);
-static int AscStopChip(PortAddr);
-static void AscSetChipIH(PortAddr, ushort);
-static int AscIsChipHalted(PortAddr);
-static void AscAckInterrupt(PortAddr);
-static void AscDisableInterrupt(PortAddr);
-static void AscEnableInterrupt(PortAddr);
-static void AscSetBank(PortAddr, uchar);
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
-#ifdef CONFIG_ISA
-static ushort AscGetIsaDmaChannel(PortAddr);
-static ushort AscSetIsaDmaChannel(PortAddr, ushort);
-static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
-static uchar AscGetIsaDmaSpeed(PortAddr);
-#endif /* CONFIG_ISA */
-static uchar AscReadLramByte(PortAddr, ushort);
-static ushort AscReadLramWord(PortAddr, ushort);
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
-#endif /* CC_VERY_LONG_SG_LIST */
-static void AscWriteLramWord(PortAddr, ushort, ushort);
-static void AscWriteLramByte(PortAddr, ushort, uchar);
-static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
-static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
-static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
-static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitFromEEP(ASC_DVC_VAR *);
-static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
-static int AscTestExternalLram(ASC_DVC_VAR *);
-static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
-static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
-static void AscSetChipSDTR(PortAddr, uchar, uchar);
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
-static uchar AscAllocFreeQueue(PortAddr, uchar);
-static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-static int AscHostReqRiscHalt(PortAddr);
-static int AscStopQueueExe(PortAddr);
-static int AscSendScsiQueue(ASC_DVC_VAR *,
- ASC_SCSI_Q *scsiq, uchar n_q_required);
-static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-static ushort AscInitLram(ASC_DVC_VAR *);
-static ushort AscInitQLinkVar(ASC_DVC_VAR *);
-static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-static int AscIsrChipHalted(ASC_DVC_VAR *);
-static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
- ASC_QDONE_INFO *, ASC_DCNT);
-static int AscIsrQDone(ASC_DVC_VAR *);
-static int AscCompareString(uchar *, uchar *, int);
-#ifdef CONFIG_ISA
-static ushort AscGetEisaChipCfg(PortAddr);
-static ASC_DCNT AscGetEisaProductID(PortAddr);
-static PortAddr AscSearchIOPortAddrEISA(PortAddr);
-static PortAddr AscSearchIOPortAddr11(PortAddr);
-static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
-static void AscSetISAPNPWaitForKey(void);
-#endif /* CONFIG_ISA */
-static uchar AscGetChipScsiCtrl(PortAddr);
-static uchar AscSetChipScsiID(PortAddr, uchar);
-static uchar AscGetChipVersion(PortAddr, ushort);
-static ushort AscGetChipBusType(PortAddr);
-static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
-static int AscFindSignature(PortAddr);
-static void AscToggleIRQAct(PortAddr);
-static uchar AscGetChipIRQ(PortAddr, ushort);
-static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-#ifdef CONFIG_PCI
-static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
-static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
-#endif /* CONFIG_PCI */
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static void DvcSleepMilliSecond(ASC_DCNT);
-static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
-static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
-static ushort AscInitGetConfig(ASC_DVC_VAR *);
-static ushort AscInitSetConfig(ASC_DVC_VAR *);
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
-static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
-static int AscISR(ASC_DVC_VAR *);
-static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
-static int AscSgListToQueue(int);
-#ifdef CONFIG_ISA
-static void AscEnableIsaDma(uchar);
-#endif /* CONFIG_ISA */
-static ASC_DCNT AscGetMaxDmaCount(ushort);
-static const char *advansys_info(struct Scsi_Host *shost);
-
-/*
- * --- Adv Library Constants and Macros
- */
-
-#define ADV_LIB_VERSION_MAJOR 5
-#define ADV_LIB_VERSION_MINOR 14
-
-/*
- * Define Adv Library required special types.
- */
-
/*
* Portable Data Types
*
@@ -2045,12 +968,6 @@ static const char *advansys_info(struct Scsi_Host *shost);
#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
/*
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
-#define ADV_MAX_CDB_LEN 16
-
-/*
* Define total number of simultaneous maximum element scatter-gather
* request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
* maximum number of outstanding commands per wide host adapter. Each
@@ -2058,28 +975,14 @@ static const char *advansys_info(struct Scsi_Host *shost);
* elements. Allow each command to have at least one ADV_SG_BLOCK structure.
* This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
* structures or 255 scatter-gather elements.
- *
*/
#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
/*
- * Define Adv Library required maximum number of scatter-gather
- * elements per request.
+ * Define maximum number of scatter-gather elements per request.
*/
#define ADV_MAX_SG_LIST 255
-
-/* Number of SG blocks needed. */
-#define ADV_NUM_SG_BLOCK \
- ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
-
-/* Total contiguous memory needed for SG blocks. */
-#define ADV_SG_TOTAL_MEM_SIZE \
- (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
-
-#define ADV_PAGE_SIZE PAGE_SIZE
-
-#define ADV_NUM_PAGE_CROSSING \
- ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+#define NO_OF_SG_PER_BLOCK 15
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
@@ -2385,10 +1288,6 @@ typedef struct adveep_38C1600_config {
* EEPROM Commands
*/
#define ASC_EEP_CMD_DONE 0x0200
-#define ASC_EEP_CMD_DONE_ERR 0x0001
-
-/* cfg_word */
-#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
/* bios_ctrl */
#define BIOS_CTRL_BIOS 0x0001
@@ -2405,10 +1304,8 @@ typedef struct adveep_38C1600_config {
#define BIOS_CTRL_AIPP_DIS 0x2000
#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
-#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
/*
* XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
@@ -2418,8 +1315,6 @@ typedef struct adveep_38C1600_config {
* #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
*/
#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
-#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
/*
* Byte I/O register address from base of 'iop_base'.
@@ -2549,8 +1444,6 @@ typedef struct adveep_38C1600_config {
#define ADV_CHIP_ID_BYTE 0x25
#define ADV_CHIP_ID_WORD 0x04C1
-#define ADV_SC_SCSI_BUS_RESET 0x2000
-
#define ADV_INTR_ENABLE_HOST_INTR 0x01
#define ADV_INTR_ENABLE_SEL_INTR 0x02
#define ADV_INTR_ENABLE_DPR_INTR 0x04
@@ -2590,8 +1483,6 @@ typedef struct adveep_38C1600_config {
#define ADV_TICKLE_B 0x02
#define ADV_TICKLE_C 0x03
-#define ADV_SCSI_CTRL_RSTOUT 0x2000
-
#define AdvIsIntPending(port) \
(AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
@@ -2744,14 +1635,11 @@ typedef struct adveep_38C1600_config {
*/
#define INTAB 0x01
-/* a_advlib.h */
-
/*
* Adv Library Status Definitions
*/
#define ADV_TRUE 1
#define ADV_FALSE 0
-#define ADV_NOERROR 1
#define ADV_SUCCESS 1
#define ADV_BUSY 0
#define ADV_ERROR (-1)
@@ -2762,31 +1650,12 @@ typedef struct adveep_38C1600_config {
#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
#define ADV_MAX_TID 15 /* max. target identifier */
#define ADV_MAX_LUN 7 /* max. logical unit number */
/*
- * Error code values are set in ADV_DVC_VAR 'err_code'.
- */
-#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
-#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
-#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
-#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
-#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
-#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
-#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
-#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
-#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
-#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
-#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
-#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
-
-/*
* Fixed locations of microcode operating variables.
*/
#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
@@ -2902,8 +1771,7 @@ typedef struct adv_carr_t {
#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
#define ADV_CARRIER_NUM_PAGE_CROSSING \
- (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
- (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+ (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + (PAGE_SIZE - 1))/PAGE_SIZE)
#define ADV_CARRIER_BUFSIZE \
((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
@@ -2937,80 +1805,17 @@ typedef struct adv_dvc_cfg {
ushort disc_enable; /* enable disconnection */
uchar chip_version; /* chip version */
uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
- ushort lib_version; /* Adv Library version number */
ushort control_flag; /* Microcode Control Flag */
ushort mcode_date; /* Microcode date */
ushort mcode_version; /* Microcode version */
- ushort pci_slot_info; /* high byte device/function number */
- /* bits 7-3 device num., bits 2-0 function num. */
- /* low byte bus num. */
ushort serial1; /* EEPROM serial number word 1 */
ushort serial2; /* EEPROM serial number word 2 */
ushort serial3; /* EEPROM serial number word 3 */
- struct device *dev; /* pointer to the pci dev structure for this board */
} ADV_DVC_CFG;
struct adv_dvc_var;
struct adv_scsi_req_q;
-typedef void (*ADV_ISR_CALLBACK)
- (struct adv_dvc_var *, struct adv_scsi_req_q *);
-
-typedef void (*ADV_ASYNC_CALLBACK)
- (struct adv_dvc_var *, uchar);
-
-/*
- * Adapter operation variable structure.
- *
- * One structure is required per host adapter.
- *
- * Field naming convention:
- *
- * *_able indicates both whether a feature should be enabled or disabled
- * and whether a device isi capable of the feature. At initialization
- * this field may be set, but later if a device is found to be incapable
- * of the feature, the field is cleared.
- */
-typedef struct adv_dvc_var {
- AdvPortAddr iop_base; /* I/O port address */
- ushort err_code; /* fatal error code */
- ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
- ADV_ISR_CALLBACK isr_callback;
- ADV_ASYNC_CALLBACK async_callback;
- ushort wdtr_able; /* try WDTR for a device */
- ushort sdtr_able; /* try SDTR for a device */
- ushort ultra_able; /* try SDTR Ultra speed for a device */
- ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
- ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
- ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
- ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
- ushort tagqng_able; /* try tagged queuing with a device */
- ushort ppr_able; /* PPR message capable per TID bitmask. */
- uchar max_dvc_qng; /* maximum number of tagged commands per device */
- ushort start_motor; /* start motor command allowed */
- uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
- uchar chip_no; /* should be assigned by caller */
- uchar max_host_qng; /* maximum number of Q'ed command allowed */
- uchar irq_no; /* IRQ number */
- ushort no_scam; /* scam_tolerant of EEPROM */
- struct asc_board *drv_ptr; /* driver pointer to private structure */
- uchar chip_scsi_id; /* chip SCSI target ID */
- uchar chip_type;
- uchar bist_err_code;
- ADV_CARR_T *carrier_buf;
- ADV_CARR_T *carr_freelist; /* Carrier free list. */
- ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
- ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
- ushort carr_pending_cnt; /* Count of pending carriers. */
- /*
- * Note: The following fields will not be used after initialization. The
- * driver may discard the buffer after initialization is done.
- */
- ADV_DVC_CFG *cfg; /* temporary configuration structure */
-} ADV_DVC_VAR;
-
-#define NO_OF_SG_PER_BLOCK 15
-
typedef struct asc_sg_block {
uchar reserved1;
uchar reserved2;
@@ -3069,6 +1874,83 @@ typedef struct adv_scsi_req_q {
} ADV_SCSI_REQ_Q;
/*
+ * The following two structures are used to process Wide Board requests.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
+ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
+ * up to 255 scatter-gather elements may be used per request or
+ * ADV_SCSI_REQ_Q.
+ *
+ * Both structures must be 32 byte aligned.
+ */
+typedef struct adv_sgblk {
+ ADV_SG_BLOCK sg_block; /* Sgblock structure. */
+ uchar align[32]; /* Sgblock structure padding. */
+ struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+ ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
+ uchar align[32]; /* Request structure padding. */
+ struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
+ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
+ struct adv_req *next_reqp; /* Next Request Structure. */
+} adv_req_t;
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device isi capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+ AdvPortAddr iop_base; /* I/O port address */
+ ushort err_code; /* fatal error code */
+ ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
+ ushort wdtr_able; /* try WDTR for a device */
+ ushort sdtr_able; /* try SDTR for a device */
+ ushort ultra_able; /* try SDTR Ultra speed for a device */
+ ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
+ ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
+ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
+ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
+ ushort tagqng_able; /* try tagged queuing with a device */
+ ushort ppr_able; /* PPR message capable per TID bitmask. */
+ uchar max_dvc_qng; /* maximum number of tagged commands per device */
+ ushort start_motor; /* start motor command allowed */
+ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
+ uchar chip_no; /* should be assigned by caller */
+ uchar max_host_qng; /* maximum number of Q'ed command allowed */
+ ushort no_scam; /* scam_tolerant of EEPROM */
+ struct asc_board *drv_ptr; /* driver pointer to private structure */
+ uchar chip_scsi_id; /* chip SCSI target ID */
+ uchar chip_type;
+ uchar bist_err_code;
+ ADV_CARR_T *carrier_buf;
+ ADV_CARR_T *carr_freelist; /* Carrier free list. */
+ ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
+ ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
+ ushort carr_pending_cnt; /* Count of pending carriers. */
+ struct adv_req *orig_reqp; /* adv_req_t memory block. */
+ /*
+ * Note: The following fields will not be used after initialization. The
+ * driver may discard the buffer after initialization is done.
+ */
+ ADV_DVC_CFG *cfg; /* temporary configuration structure */
+} ADV_DVC_VAR;
+
+/*
* Microcode idle loop commands
*/
#define IDLE_CMD_COMPLETED 0
@@ -3092,10 +1974,8 @@ typedef struct adv_scsi_req_q {
/*
* Wait loop time out values.
*/
-#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
-#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
#define SCSI_MAX_RETRY 10 /* retry count */
#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
@@ -3105,53 +1985,6 @@ typedef struct adv_scsi_req_q {
#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
-/*
- * Device drivers must define the following functions.
- */
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-static void DvcSleepMilliSecond(ADV_DCNT);
-static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
-static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
- uchar *, ASC_SDCNT *, int);
-static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
-
-/*
- * Adv Library functions available to drivers.
- */
-static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvISR(ADV_DVC_VAR *);
-static int AdvInitGetConfig(ADV_DVC_VAR *);
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
-static int AdvResetChipAndSB(ADV_DVC_VAR *);
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
-
-/*
- * Internal Adv Library functions.
- */
-static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
-static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
-static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvWaitEEPCmd(AdvPortAddr);
-static ushort AdvReadEEPWord(AdvPortAddr, int);
-
-/*
- * PCI Bus Definitions
- */
-#define AscPCICmdRegBits_BusMastering 0x0007
-#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
-
/* Read byte from a register. */
#define AdvReadByteRegister(iop_base, reg_off) \
(ADV_MEM_READB((iop_base) + (reg_off)))
@@ -3319,23 +2152,6 @@ do { \
#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
-/*
- * Default EEPROM Configuration structure defined in a_init.c.
- */
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
-
-/*
- * DvcGetPhyAddr() flag arguments
- */
-#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
-#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
-#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
-#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
-#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
-#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
-
/* Return the address that is aligned at the next doubleword >= to 'addr'. */
#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
@@ -3353,92 +2169,10 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
(sizeof(ADV_SG_BLOCK) * \
((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
-/*
- * Inquiry data structure and bitfield macros
- *
- * Using bitfields to access the subchar data isn't portable across
- * endianness, so instead mask and shift. Only quantities of more
- * than 1 bit are shifted, since the others are just tested for true
- * or false.
- */
-
-#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
-#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
-#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
-#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
-#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
-#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
-#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
-#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
-#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
-#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
-#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
-#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
-#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
-#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
-#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
-#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
-#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
-#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
-#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
-#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
- uchar periph; /* peripheral device type [0:4] */
- /* peripheral qualifier [5:7] */
- uchar devtype; /* device type modifier (for SCSI I) [0:6] */
- /* RMB - removable medium bit [7] */
- uchar ver; /* ANSI approved version [0:2] */
- /* ECMA version [3:5] */
- /* ISO version [6:7] */
- uchar byte3; /* response data format [0:3] */
- /* 0 SCSI 1 */
- /* 1 CCS */
- /* 2 SCSI-2 */
- /* 3-F reserved */
- /* reserved [4:5] */
- /* terminate I/O process bit (see 5.6.22) [6] */
- /* asynch. event notification (processor) [7] */
- uchar add_len; /* additional length */
- uchar res1; /* reserved */
- uchar res2; /* reserved */
- uchar flags; /* soft reset implemented [0] */
- /* command queuing [1] */
- /* reserved [2] */
- /* linked command for this logical unit [3] */
- /* synchronous data transfer [4] */
- /* wide bus 16 bit data transfer [5] */
- /* wide bus 32 bit data transfer [6] */
- /* relative addressing mode [7] */
- uchar vendor_id[8]; /* vendor identification */
- uchar product_id[16]; /* product identification */
- uchar product_rev_level[4]; /* product revision level */
- uchar vendor_specific[20]; /* vendor specific */
- uchar info; /* information unit supported [0] */
- /* quick arbitrate supported [1] */
- /* clocking field [2:3] */
- /* reserved [4:7] */
- uchar res3; /* reserved */
-} ADV_SCSI_INQUIRY; /* 58 bytes */
-
-/*
- * --- Driver Constants and Macros
- */
-
-#define ASC_NUM_BOARD_SUPPORTED 16
-#define ASC_NUM_IOPORT_PROBE 4
-#define ASC_NUM_BUS 4
-
-/* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
-
-/* asc_board_t flags */
-#define ASC_HOST_IN_RESET 0x01
+/* struct asc_board flags */
#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
-#define ASC_SELECT_QUEUE_DEPTHS 0x08
#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
-#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
@@ -3473,82 +2207,14 @@ typedef struct {
#define HOST_BYTE(byte) ((byte) << 16)
#define DRIVER_BYTE(byte) ((byte) << 24)
-/*
- * The following definitions and macros are OS independent interfaces to
- * the queue functions:
- * REQ - SCSI request structure
- * REQP - pointer to SCSI request structure
- * REQPTID(reqp) - reqp's target id
- * REQPNEXT(reqp) - reqp's next pointer
- * REQPNEXTP(reqp) - pointer to reqp's next pointer
- * REQPTIME(reqp) - reqp's time stamp value
- * REQTIMESTAMP() - system time stamp value
- */
-typedef struct scsi_cmnd REQ, *REQP;
-#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
-#define REQPTID(reqp) ((reqp)->device->id)
-#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
-#define REQTIMESTAMP() (jiffies)
-
-#define REQTIMESTAT(function, ascq, reqp, tid) \
-{ \
- /*
- * If the request time stamp is less than the system time stamp, then \
- * maybe the system time stamp wrapped. Set the request time to zero.\
- */ \
- if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
- REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
- } else { \
- /* Indicate an error occurred with the assertion. */ \
- ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
- REQPTIME(reqp) = 0; \
- } \
- /* Handle first minimum time case without external initialization. */ \
- if (((ascq)->q_tot_cnt[tid] == 1) || \
- (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
- (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
- (function), (tid), (ascq)->q_min_tim[tid]); \
- } \
- if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
- (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
- (function), tid, (ascq)->q_max_tim[tid]); \
- } \
- (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
- /* Reset the time stamp field. */ \
- REQPTIME(reqp) = 0; \
-}
-
-/* asc_enqueue() flags */
-#define ASC_FRONT 1
-#define ASC_BACK 2
-
-/* asc_dequeue_list() argument */
-#define ASC_TID_ALL (-1)
-
-/* Return non-zero, if the queue is empty. */
-#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
-
-#define PCI_MAX_SLOT 0x1F
-#define PCI_MAX_BUS 0xFF
-#define PCI_IOADDRESS_MASK 0xFFFE
-#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
-
+#define ASC_STATS(shost, counter) ASC_STATS_ADD(shost, counter, 1)
#ifndef ADVANSYS_STATS
-#define ASC_STATS(shost, counter)
#define ASC_STATS_ADD(shost, counter, count)
#else /* ADVANSYS_STATS */
-#define ASC_STATS(shost, counter) \
- (ASC_BOARDP(shost)->asc_stats.counter++)
-
#define ASC_STATS_ADD(shost, counter, count) \
- (ASC_BOARDP(shost)->asc_stats.counter += (count))
+ (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count))
#endif /* ADVANSYS_STATS */
-#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-
/* If the result wraps when calculating tenths, return 0. */
#define ASC_TENTHS(num, den) \
(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
@@ -3589,13 +2255,8 @@ typedef struct scsi_cmnd REQ, *REQP;
#ifndef ADVANSYS_DEBUG
-#define ASC_DBG(lvl, s)
-#define ASC_DBG1(lvl, s, a1)
-#define ASC_DBG2(lvl, s, a1, a2)
-#define ASC_DBG3(lvl, s, a1, a2, a3)
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define ASC_DBG(lvl, s...)
#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
@@ -3614,40 +2275,11 @@ typedef struct scsi_cmnd REQ, *REQP;
* 2-N: Verbose Tracing
*/
-#define ASC_DBG(lvl, s) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk(s); \
- } \
- }
-
-#define ASC_DBG1(lvl, s, a1) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1)); \
- } \
- }
-
-#define ASC_DBG2(lvl, s, a1, a2) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2)); \
- } \
- }
-
-#define ASC_DBG3(lvl, s, a1, a2, a3) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2), (a3)); \
- } \
- }
-
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2), (a3), (a4)); \
- } \
- }
+#define ASC_DBG(lvl, format, arg...) { \
+ if (asc_dbglvl >= (lvl)) \
+ printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \
+ __FUNCTION__ , ## arg); \
+}
#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
{ \
@@ -3656,13 +2288,6 @@ typedef struct scsi_cmnd REQ, *REQP;
} \
}
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- asc_prt_scsi_cmnd(s); \
- } \
- }
-
#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
{ \
if (asc_dbglvl >= (lvl)) { \
@@ -3701,24 +2326,6 @@ typedef struct scsi_cmnd REQ, *REQP;
ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
#endif /* ADVANSYS_DEBUG */
-#ifndef ADVANSYS_ASSERT
-#define ASC_ASSERT(a)
-#else /* ADVANSYS_ASSERT */
-
-#define ASC_ASSERT(a) \
- { \
- if (!(a)) { \
- printk("ASC_ASSERT() Failure: file %s, line %d\n", \
- __FILE__, __LINE__); \
- } \
- }
-
-#endif /* ADVANSYS_ASSERT */
-
-/*
- * --- Driver Structures
- */
-
#ifdef ADVANSYS_STATS
/* Per board statistics structure */
@@ -3739,72 +2346,23 @@ struct asc_stats {
ADV_DCNT exe_error; /* # ASC_ERROR returns. */
ADV_DCNT exe_unknown; /* # unknown returns. */
/* Data Transfer Statistics */
- ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
- ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
- ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
- ADV_DCNT sg_elem; /* # scatter-gather elements */
- ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
+ ADV_DCNT xfer_cnt; /* # I/O requests received */
+ ADV_DCNT xfer_elem; /* # scatter-gather elements */
+ ADV_DCNT xfer_sect; /* # 512-byte blocks */
};
#endif /* ADVANSYS_STATS */
/*
- * Request queuing structure
- */
-typedef struct asc_queue {
- ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
- REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
- REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
-#ifdef ADVANSYS_STATS
- short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
- short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
- ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
- ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
- ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
- ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
-#endif /* ADVANSYS_STATS */
-} asc_queue_t;
-
-/*
- * Adv Library Request Structures
- *
- * The following two structures are used to process Wide Board requests.
- *
- * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
- * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
- * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
- * Mid-Level SCSI request structure.
- *
- * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
- * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
- * up to 255 scatter-gather elements may be used per request or
- * ADV_SCSI_REQ_Q.
- *
- * Both structures must be 32 byte aligned.
- */
-typedef struct adv_sgblk {
- ADV_SG_BLOCK sg_block; /* Sgblock structure. */
- uchar align[32]; /* Sgblock structure padding. */
- struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
-} adv_sgblk_t;
-
-typedef struct adv_req {
- ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
- uchar align[32]; /* Request structure padding. */
- struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
- adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
- struct adv_req *next_reqp; /* Next Request Structure. */
-} adv_req_t;
-
-/*
* Structure allocated for each board.
*
- * This structure is allocated by scsi_register() at the end
+ * This structure is allocated by scsi_host_alloc() at the end
* of the 'Scsi_Host' structure starting at the 'hostdata'
* field. It is guaranteed to be allocated from DMA-able memory.
*/
-typedef struct asc_board {
- int id; /* Board Id */
+struct asc_board {
+ struct device *dev;
uint flags; /* Board flags */
+ unsigned int irq;
union {
ASC_DVC_VAR asc_dvc_var; /* Narrow board */
ADV_DVC_VAR adv_dvc_var; /* Wide board */
@@ -3814,11 +2372,7 @@ typedef struct asc_board {
ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
} dvc_cfg;
ushort asc_n_io_port; /* Number I/O ports. */
- asc_queue_t active; /* Active command queue */
- asc_queue_t waiting; /* Waiting command queue */
- asc_queue_t done; /* Done command queue */
ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
- struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
@@ -3829,2409 +2383,529 @@ typedef struct asc_board {
ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
} eep_config;
ulong last_reset; /* Saved last reset time */
- spinlock_t lock; /* Board spinlock */
-#ifdef CONFIG_PROC_FS
/* /proc/scsi/advansys/[0...] */
char *prtbuf; /* /proc print buffer */
-#endif /* CONFIG_PROC_FS */
#ifdef ADVANSYS_STATS
struct asc_stats asc_stats; /* Board statistics */
#endif /* ADVANSYS_STATS */
/*
* The following fields are used only for Narrow Boards.
*/
- /* The following three structures must be in DMA-able memory. */
- ASC_SCSI_REQ_Q scsireqq;
- ASC_CAP_INFO cap_info;
- ASC_SCSI_INQUIRY inquiry;
uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
/*
* The following fields are used only for Wide Boards.
*/
void __iomem *ioremap_addr; /* I/O Memory remap address. */
ushort ioport; /* I/O Port address. */
- ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
- adv_req_t *orig_reqp; /* adv_req_t memory block. */
adv_req_t *adv_reqp; /* Request structures. */
adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
ushort bios_signature; /* BIOS Signature. */
ushort bios_version; /* BIOS Version. */
ushort bios_codeseg; /* BIOS Code Segment. */
ushort bios_codelen; /* BIOS Code Segment Length. */
-} asc_board_t;
-
-/*
- * PCI configuration structures
- */
-typedef struct _PCI_DATA_ {
- uchar type;
- uchar bus;
- uchar slot;
- uchar func;
- uchar offset;
-} PCI_DATA;
-
-typedef struct _PCI_DEVICE_ {
- ushort vendorID;
- ushort deviceID;
- ushort slotNumber;
- ushort slotFound;
- uchar busNumber;
- uchar maxBusNumber;
- uchar devFunc;
- ushort startSlot;
- ushort endSlot;
- uchar bridge;
- uchar type;
-} PCI_DEVICE;
-
-typedef struct _PCI_CONFIG_SPACE_ {
- ushort vendorID;
- ushort deviceID;
- ushort command;
- ushort status;
- uchar revision;
- uchar classCode[3];
- uchar cacheSize;
- uchar latencyTimer;
- uchar headerType;
- uchar bist;
- ADV_PADDR baseAddress[6];
- ushort reserved[4];
- ADV_PADDR optionRomAddr;
- ushort reserved2[4];
- uchar irqLine;
- uchar irqPin;
- uchar minGnt;
- uchar maxLatency;
-} PCI_CONFIG_SPACE;
-
-/*
- * --- Driver Data
- */
-
-/* Note: All driver global data should be initialized. */
-
-/* Number of boards detected in system. */
-static int asc_board_count = 0;
-static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
-
-/* Overrun buffer used by all narrow boards. */
-static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
-
-/*
- * Global structures required to issue a command.
- */
-static ASC_SCSI_Q asc_scsi_q = { {0} };
-static ASC_SG_HEAD asc_sg_head = { 0 };
-
-/* List of supported bus types. */
-static ushort asc_bus[ASC_NUM_BUS] __initdata = {
- ASC_IS_ISA,
- ASC_IS_VL,
- ASC_IS_EISA,
- ASC_IS_PCI,
};
-static int asc_iopflag = ASC_FALSE;
-static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \
+ dvc_var.asc_dvc_var)
+#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
+ dvc_var.adv_dvc_var)
+#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
#ifdef ADVANSYS_DEBUG
-static char *asc_bus_name[ASC_NUM_BUS] = {
- "ASC_IS_ISA",
- "ASC_IS_VL",
- "ASC_IS_EISA",
- "ASC_IS_PCI",
-};
-
static int asc_dbglvl = 3;
-#endif /* ADVANSYS_DEBUG */
-
-/* Declaration for Asc Library internal data referenced by driver. */
-static PortAddr _asc_def_iop_base[];
-
-/*
- * --- Driver Function Prototypes
- *
- * advansys.h contains function prototypes for functions global to Linux.
- */
-
-static irqreturn_t advansys_interrupt(int, void *);
-static int advansys_slave_configure(struct scsi_device *);
-static void asc_scsi_done_list(struct scsi_cmnd *);
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
-static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
-static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
-static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static void adv_async_callback(ADV_DVC_VAR *, uchar);
-static void asc_enqueue(asc_queue_t *, REQP, int);
-static REQP asc_dequeue(asc_queue_t *, int);
-static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-static int asc_rmqueue(asc_queue_t *, REQP);
-static void asc_execute_queue(asc_queue_t *);
-#ifdef CONFIG_PROC_FS
-static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
-static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
-static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
-static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_line(char *, int, char *fmt, ...);
-#endif /* CONFIG_PROC_FS */
-
-/* Declaration for Asc Library internal functions referenced by driver. */
-static int AscFindSignature(PortAddr);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-
-/* Statistics function prototypes. */
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
-static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
-static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
-
-/* Debug function prototypes. */
-#ifdef ADVANSYS_DEBUG
-static void asc_prt_scsi_host(struct Scsi_Host *);
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
-static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
-static void asc_prt_hex(char *f, uchar *, int);
-#endif /* ADVANSYS_DEBUG */
-#ifdef CONFIG_PROC_FS
/*
- * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset into a /proc/scsi/advansys/[0...] file
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written to a
- * /proc/scsi/advansys/[0...] file.
- *
- * Note: This function uses the per board buffer 'prtbuf' which is
- * allocated when the board is initialized in advansys_detect(). The
- * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
- * used to write to the buffer. The way asc_proc_copy() is written
- * if 'prtbuf' is too small it will not be overwritten. Instead the
- * user just won't get all the available statistics.
+ * asc_prt_asc_dvc_var()
*/
-static int
-advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
{
- struct Scsi_Host *shp;
- asc_board_t *boardp;
- int i;
- char *cp;
- int cplen;
- int cnt;
- int totcnt;
- int leftlen;
- char *curbuf;
- off_t advoffset;
-#ifdef ADVANSYS_STATS
- int tgt_id;
-#endif /* ADVANSYS_STATS */
-
- ASC_DBG(1, "advansys_proc_info: begin\n");
-
- /*
- * User write not supported.
- */
- if (inout == TRUE) {
- return (-ENOSYS);
- }
-
- /*
- * User read of /proc/scsi/advansys/[0...] file.
- */
-
- /* Find the specified board. */
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i]->host_no == shost->host_no) {
- break;
- }
- }
- if (i == asc_board_count) {
- return (-ENOENT);
- }
-
- shp = asc_host[i];
- boardp = ASC_BOARDP(shp);
-
- /* Copy read data starting at the beginning of the buffer. */
- *start = buffer;
- curbuf = buffer;
- advoffset = 0;
- totcnt = 0;
- leftlen = length;
-
- /*
- * Get board configuration information.
- *
- * advansys_info() returns the board string from its own static buffer.
- */
- cp = (char *)advansys_info(shp);
- strcat(cp, "\n");
- cplen = strlen(cp);
- /* Copy board information. */
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display Wide Board BIOS Information.
- */
- if (ASC_WIDE_BOARD(boardp)) {
- cp = boardp->prtbuf;
- cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt =
- asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
-
- /*
- * Display driver information for each device attached to the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display EEPROM configuration for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display driver configuration and information for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
-#ifdef ADVANSYS_STATS
- /*
- * Display driver statistics for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
+ "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
- /*
- * Display driver statistics for each target.
- */
- for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
- cp = boardp->prtbuf;
- cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt =
- asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
-#endif /* ADVANSYS_STATS */
+ printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
+ (unsigned)h->init_sdtr);
- /*
- * Display Asc Library dynamic configuration information
- * for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
+ "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
+ (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
+ (unsigned)h->chip_no);
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
+ "%u,\n", (unsigned)h->queue_full_or_busy,
+ (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
- return totcnt;
-}
-#endif /* CONFIG_PROC_FS */
+ printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
+ "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
+ (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
+ (unsigned)h->in_critical_cnt);
-/*
- * advansys_info()
- *
- * Return suitable for printing on the console with the argument
- * adapter's configuration information.
- *
- * Note: The information line should not exceed ASC_INFO_SIZE bytes,
- * otherwise the static 'info' array will be overrun.
- */
-static const char *advansys_info(struct Scsi_Host *shost)
-{
- static char info[ASC_INFO_SIZE];
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- char *busname;
- int iolen;
- char *widename = NULL;
+ printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
+ "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
+ (unsigned)h->init_state, (unsigned)h->no_scam,
+ (unsigned)h->pci_fix_asyn_xfer);
- boardp = ASC_BOARDP(shost);
- if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- ASC_DBG(1, "advansys_info: begin\n");
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
- ASC_IS_ISAPNP) {
- busname = "ISA PnP";
- } else {
- busname = "ISA";
- }
- /* Don't reference 'shost->n_io_port'; It may be truncated. */
- sprintf(info,
- "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
- ASC_VERSION, busname,
- (ulong)shost->io_port,
- (ulong)shost->io_port + boardp->asc_n_io_port -
- 1, shost->irq, shost->dma_channel);
- } else {
- if (asc_dvc_varp->bus_type & ASC_IS_VL) {
- busname = "VL";
- } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
- busname = "EISA";
- } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
- == ASC_IS_PCI_ULTRA) {
- busname = "PCI Ultra";
- } else {
- busname = "PCI";
- }
- } else {
- busname = "?";
- ASC_PRINT2
- ("advansys_info: board %d: unknown bus type %d\n",
- boardp->id, asc_dvc_varp->bus_type);
- }
- /* Don't reference 'shost->n_io_port'; It may be truncated. */
- sprintf(info,
- "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION, busname,
- (ulong)shost->io_port,
- (ulong)shost->io_port + boardp->asc_n_io_port -
- 1, shost->irq);
- }
- } else {
- /*
- * Wide Adapter Information
- *
- * Memory-mapped I/O is used instead of I/O space to access
- * the adapter, but display the I/O Port range. The Memory
- * I/O address is displayed through the driver /proc file.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- iolen = ADV_3550_IOLEN;
- widename = "Ultra-Wide";
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- iolen = ADV_38C0800_IOLEN;
- widename = "Ultra2-Wide";
- } else {
- iolen = ADV_38C1600_IOLEN;
- widename = "Ultra3-Wide";
- }
- sprintf(info,
- "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
- (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
- }
- ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
- ASC_DBG(1, "advansys_info: end\n");
- return info;
+ printk(" cfg 0x%lx\n", (ulong)h->cfg);
}
/*
- * advansys_queuecommand() - interrupt-driven I/O entrypoint.
- *
- * This function always returns 0. Command return status is saved
- * in the 'scp' result field.
+ * asc_prt_asc_dvc_cfg()
*/
-static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
{
- struct Scsi_Host *shost;
- asc_board_t *boardp;
- ulong flags;
- struct scsi_cmnd *done_scp;
-
- shost = scp->device->host;
- boardp = ASC_BOARDP(shost);
- ASC_STATS(shost, queuecommand);
-
- /* host_lock taken by mid-level prior to call but need to protect */
- /* against own ISR */
- spin_lock_irqsave(&boardp->lock, flags);
-
- /*
- * Block new commands while handling a reset or abort request.
- */
- if (boardp->flags & ASC_HOST_IN_RESET) {
- ASC_DBG1(1,
- "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
- (ulong)scp);
- scp->result = HOST_BYTE(DID_RESET);
-
- /*
- * Add blocked requests to the board's 'done' queue. The queued
- * requests will be completed at the end of the abort or reset
- * handling.
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&boardp->lock, flags);
- return 0;
- }
+ printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
- /*
- * Attempt to execute any waiting commands for the board.
- */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1,
- "advansys_queuecommand: before asc_execute_queue() waiting\n");
- asc_execute_queue(&boardp->waiting);
- }
+ printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+ h->can_tagged_qng, h->cmd_qng_enabled);
+ printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+ h->disc_enable, h->sdtr_enable);
- /*
- * Save the function pointer to Linux mid-level 'done' function
- * and attempt to execute the command.
- *
- * If ASC_NOERROR is returned the request has been added to the
- * board's 'active' queue and will be completed by the interrupt
- * handler.
- *
- * If ASC_BUSY is returned add the request to the board's per
- * target waiting list. This is the first time the request has
- * been tried. Add it to the back of the waiting list. It will be
- * retried later.
- *
- * If an error occurred, the request will have been placed on the
- * board's 'done' queue and must be completed before returning.
- */
- scp->scsi_done = done;
- switch (asc_execute_scsi_cmnd(scp)) {
- case ASC_NOERROR:
- break;
- case ASC_BUSY:
- asc_enqueue(&boardp->waiting, scp, ASC_BACK);
- break;
- case ASC_ERROR:
- default:
- done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
- /* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
- break;
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
+ printk(" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, "
+ "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed,
+ h->isa_dma_channel, h->chip_version);
- return 0;
+ printk(" mcode_date 0x%x, mcode_version %d\n",
+ h->mcode_date, h->mcode_version);
}
/*
- * advansys_reset()
- *
- * Reset the bus associated with the command 'scp'.
+ * asc_prt_adv_dvc_var()
*
- * This function runs its own thread. Interrupts must be blocked but
- * sleeping is allowed and no locking other than for host structures is
- * required. Returns SUCCESS or FAILED.
+ * Display an ADV_DVC_VAR structure.
*/
-static int advansys_reset(struct scsi_cmnd *scp)
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
{
- struct Scsi_Host *shost;
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ulong flags;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *tscp, *new_last_scp;
- int status;
- int ret = SUCCESS;
-
- ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
-
-#ifdef ADVANSYS_STATS
- if (scp->device->host != NULL) {
- ASC_STATS(scp->device->host, reset);
- }
-#endif /* ADVANSYS_STATS */
-
- if ((shost = scp->device->host) == NULL) {
- scp->result = HOST_BYTE(DID_ERROR);
- return FAILED;
- }
-
- boardp = ASC_BOARDP(shost);
-
- ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
- boardp->id);
- /*
- * Check for re-entrancy.
- */
- spin_lock_irqsave(&boardp->lock, flags);
- if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&boardp->lock, flags);
- return FAILED;
- }
- boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
-
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-
- /*
- * Reset the chip and SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
- status = AscInitAsc1000Driver(asc_dvc_varp);
-
- /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
- if (asc_dvc_varp->err_code) {
- ASC_PRINT2
- ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ret = FAILED;
- } else if (status) {
- ASC_PRINT2
- ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
- boardp->id, status);
- } else {
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- }
-
- ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
- spin_lock_irqsave(&boardp->lock, flags);
-
- } else {
- /*
- * Wide Board
- *
- * If the suggest reset bus flags are set, then reset the bus.
- * Otherwise only reset the device.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-
- /*
- * Reset the target's SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
- switch (AdvResetChipAndSB(adv_dvc_varp)) {
- case ASC_TRUE:
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- break;
- case ASC_FALSE:
- default:
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset error.\n",
- boardp->id);
- ret = FAILED;
- break;
- }
- spin_lock_irqsave(&boardp->lock, flags);
- (void)AdvISR(adv_dvc_varp);
- }
- /* Board lock is held. */
-
- /*
- * Dequeue all board 'done' requests. A pointer to the last request
- * is returned in 'last_scp'.
- */
- done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
-
- /*
- * Dequeue all board 'active' requests for all devices and set
- * the request status to DID_RESET. A pointer to the last request
- * is returned in 'last_scp'.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->active,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp;
- tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
-
- /*
- * Dequeue all 'waiting' requests and set the request status
- * to DID_RESET.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->waiting,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp;
- tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
+ printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
- /* Save the time of the most recently completed reset. */
- boardp->last_reset = jiffies;
+ printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+ (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
- /* Clear reset flag. */
- boardp->flags &= ~ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
+ printk(" sdtr_able 0x%x, wdtr_able 0x%x\n",
+ (unsigned)h->sdtr_able, (unsigned)h->wdtr_able);
- /*
- * Complete all the 'done_scp' requests.
- */
- if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
- }
+ printk(" start_motor 0x%x, scsi_reset_wait 0x%x\n",
+ (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
- ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+ printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+ (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
+ (ulong)h->carr_freelist);
- return ret;
-}
+ printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
+ (ulong)h->icq_sp, (ulong)h->irq_sp);
-/*
- * advansys_biosparam()
- *
- * Translate disk drive geometry if the "BIOS greater than 1 GB"
- * support is enabled for a drive.
- *
- * ip (information pointer) is an int array with the following definition:
- * ip[0]: heads
- * ip[1]: sectors
- * ip[2]: cylinders
- */
-static int
-advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int ip[])
-{
- asc_board_t *boardp;
+ printk(" no_scam 0x%x, tagqng_able 0x%x\n",
+ (unsigned)h->no_scam, (unsigned)h->tagqng_able);
- ASC_DBG(1, "advansys_biosparam: begin\n");
- ASC_STATS(sdev->host, biosparam);
- boardp = ASC_BOARDP(sdev->host);
- if (ASC_NARROW_BOARD(boardp)) {
- if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
- ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- } else {
- if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
- BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- }
- ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
- ASC_DBG(1, "advansys_biosparam: end\n");
- return 0;
+ printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
+ (unsigned)h->chip_scsi_id, (ulong)h->cfg);
}
-static int __init advansys_detect(struct scsi_host_template *tpnt);
-static int advansys_release(struct Scsi_Host *shp);
-
-static struct scsi_host_template driver_template = {
- .proc_name = "advansys",
-#ifdef CONFIG_PROC_FS
- .proc_info = advansys_proc_info,
-#endif
- .name = "advansys",
- .detect = advansys_detect,
- .release = advansys_release,
- .info = advansys_info,
- .queuecommand = advansys_queuecommand,
- .eh_bus_reset_handler = advansys_reset,
- .bios_param = advansys_biosparam,
- .slave_configure = advansys_slave_configure,
- /*
- * Because the driver may control an ISA adapter 'unchecked_isa_dma'
- * must be set. The flag will be cleared in advansys_detect for non-ISA
- * adapters. Refer to the comment in scsi_module.c for more information.
- */
- .unchecked_isa_dma = 1,
- /*
- * All adapters controlled by this driver are capable of large
- * scatter-gather lists. According to the mid-level SCSI documentation
- * this obviates any performance gain provided by setting
- * 'use_clustering'. But empirically while CPU utilization is increased
- * by enabling clustering, I/O throughput increases as well.
- */
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
-
-/*
- * --- Miscellaneous Driver Functions
- */
-
/*
- * First-level interrupt handler.
+ * asc_prt_adv_dvc_cfg()
*
- * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
- * all boards are currently checked for interrupts on each interrupt, 'dev_id'
- * is not referenced. 'dev_id' could be used to identify an interrupt passed
- * to the AdvanSys driver which is for a device sharing an interrupt with
- * an AdvanSys adapter.
+ * Display an ADV_DVC_CFG structure.
*/
-static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
{
- ulong flags;
- int i;
- asc_board_t *boardp;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *new_last_scp;
- struct Scsi_Host *shost;
-
- ASC_DBG(1, "advansys_interrupt: begin\n");
-
- /*
- * Check for interrupts on all boards.
- * AscISR() will call asc_isr_callback().
- */
- for (i = 0; i < asc_board_count; i++) {
- shost = asc_host[i];
- boardp = ASC_BOARDP(shost);
- ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
- i, (ulong)boardp);
- spin_lock_irqsave(&boardp->lock, flags);
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- if (AscIsIntPending(shost->io_port)) {
- ASC_STATS(shost, interrupt);
- ASC_DBG(1,
- "advansys_interrupt: before AscISR()\n");
- AscISR(&boardp->dvc_var.asc_dvc_var);
- }
- } else {
- /*
- * Wide Board
- */
- ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
- if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(shost, interrupt);
- }
- }
-
- /*
- * Start waiting requests and create a list of completed requests.
- *
- * If a reset request is being performed for the board, the reset
- * handler will complete pending requests after it has completed.
- */
- if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
- ASC_DBG2(1,
- "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
- (ulong)done_scp, (ulong)last_scp);
-
- /* Start any waiting commands for the board. */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1,
- "advansys_interrupt: before asc_execute_queue()\n");
- asc_execute_queue(&boardp->waiting);
- }
-
- /*
- * Add to the list of requests that must be completed.
- *
- * 'done_scp' will always be NULL on the first iteration
- * of this loop. 'last_scp' is set at the same time as
- * 'done_scp'.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->done, &last_scp,
- ASC_TID_ALL);
- } else {
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->
- done,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- last_scp = new_last_scp;
- }
- }
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
- }
-
- /*
- * If interrupts were enabled on entry, then they
- * are now enabled here.
- *
- * Complete all requests on the done list.
- */
-
- asc_scsi_done_list(done_scp);
+ printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
- ASC_DBG(1, "advansys_interrupt: end\n");
- return IRQ_HANDLED;
-}
+ printk(" disc_enable 0x%x, termination 0x%x\n",
+ h->disc_enable, h->termination);
-/*
- * Set the number of commands to queue per device for the
- * specified host adapter.
- */
-static int advansys_slave_configure(struct scsi_device *device)
-{
- asc_board_t *boardp;
+ printk(" chip_version 0x%x, mcode_date 0x%x\n",
+ h->chip_version, h->mcode_date);
- boardp = ASC_BOARDP(device->host);
- boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
- /*
- * Save a pointer to the device and set its initial/maximum
- * queue depth. Only save the pointer for a lun0 dev though.
- */
- if (device->lun == 0)
- boardp->device[device->id] = device;
- if (device->tagged_supported) {
- if (ASC_NARROW_BOARD(boardp)) {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.asc_dvc_var.
- max_dvc_qng[device->id]);
- } else {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.adv_dvc_var.
- max_dvc_qng);
- }
- } else {
- scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
- }
- ASC_DBG4(1,
- "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
- (ulong)device, (ulong)boardp, device->id, device->queue_depth);
- return 0;
+ printk(" mcode_version 0x%x, control_flag 0x%x\n",
+ h->mcode_version, h->control_flag);
}
/*
- * Complete all requests on the singly linked list pointed
- * to by 'scp'.
- *
- * Interrupts can be enabled on entry.
+ * asc_prt_scsi_host()
*/
-static void asc_scsi_done_list(struct scsi_cmnd *scp)
+static void asc_prt_scsi_host(struct Scsi_Host *s)
{
- struct scsi_cmnd *tscp;
-
- ASC_DBG(2, "asc_scsi_done_list: begin\n");
- while (scp != NULL) {
- asc_board_t *boardp;
- struct device *dev;
+ struct asc_board *boardp = shost_priv(s);
- ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
- tscp = REQPNEXT(scp);
- scp->host_scribble = NULL;
-
- boardp = ASC_BOARDP(scp->device->host);
-
- if (ASC_NARROW_BOARD(boardp))
- dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
- else
- dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+ printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id);
+ printk(" host_busy %u, host_no %d, last_reset %d,\n",
+ s->host_busy, s->host_no, (unsigned)s->last_reset);
- if (scp->use_sg)
- dma_unmap_sg(dev,
- (struct scatterlist *)scp->request_buffer,
- scp->use_sg, scp->sc_data_direction);
- else if (scp->request_bufflen)
- dma_unmap_single(dev, scp->SCp.dma_handle,
- scp->request_bufflen,
- scp->sc_data_direction);
+ printk(" base 0x%lx, io_port 0x%lx, irq %d,\n",
+ (ulong)s->base, (ulong)s->io_port, boardp->irq);
- ASC_STATS(scp->device->host, done);
- ASC_ASSERT(scp->scsi_done != NULL);
+ printk(" dma_channel %d, this_id %d, can_queue %d,\n",
+ s->dma_channel, s->this_id, s->can_queue);
- scp->scsi_done(scp);
+ printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
- scp = tscp;
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var);
+ asc_prt_asc_dvc_cfg(&boardp->dvc_cfg.asc_dvc_cfg);
+ } else {
+ asc_prt_adv_dvc_var(&boardp->dvc_var.adv_dvc_var);
+ asc_prt_adv_dvc_cfg(&boardp->dvc_cfg.adv_dvc_cfg);
}
- ASC_DBG(2, "asc_scsi_done_list: done\n");
- return;
}
/*
- * Execute a single 'Scsi_Cmnd'.
- *
- * The function 'done' is called when the request has been completed.
- *
- * Scsi_Cmnd:
- *
- * host - board controlling device
- * device - device to send command
- * target - target of device
- * lun - lun of device
- * cmd_len - length of SCSI CDB
- * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
- * use_sg - if non-zero indicates scatter-gather request with use_sg elements
- *
- * if (use_sg == 0) {
- * request_buffer - buffer address for request
- * request_bufflen - length of request buffer
- * } else {
- * request_buffer - pointer to scatterlist structure
- * }
- *
- * sense_buffer - sense command buffer
- *
- * result (4 bytes of an int):
- * Byte Meaning
- * 0 SCSI Status Byte Code
- * 1 SCSI One Byte Message Code
- * 2 Host Error Code
- * 3 Mid-Level Error Code
- *
- * host driver fields:
- * SCp - Scsi_Pointer used for command processing status
- * scsi_done - used to save caller's done function
- * host_scribble - used for pointer to another struct scsi_cmnd
- *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'active' queue and will be completed from the
- * interrupt handler.
- *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'done' queue and must be completed by the caller.
+ * asc_prt_hex()
*
- * If ASC_BUSY is returned the request will be enqueued by the
- * caller on the target's waiting queue and re-tried later.
+ * Print hexadecimal output in 4 byte groupings 32 bytes
+ * or 8 double-words per line.
*/
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+static void asc_prt_hex(char *f, uchar *s, int l)
{
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ADV_SCSI_REQ_Q *adv_scsiqp;
- struct scsi_device *device;
- int ret;
-
- ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
- (ulong)scp, (ulong)scp->scsi_done);
-
- boardp = ASC_BOARDP(scp->device->host);
- device = boardp->device[scp->device->id];
+ int i;
+ int j;
+ int k;
+ int m;
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Build and execute Narrow Board request.
- */
+ printk("%s: (%d bytes)\n", f, l);
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ for (i = 0; i < l; i += 32) {
- /*
- * Build Asc Library request structure using the
- * global structures 'asc_scsi_req' and 'asc_sg_head'.
- *
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- *
- * asc_build_req() can not return ASC_BUSY.
- */
- if (asc_build_req(boardp, scp) == ASC_ERROR) {
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
+ /* Display a maximum of 8 double-words per line. */
+ if ((k = (l - i) / 4) >= 8) {
+ k = 8;
+ m = 0;
+ } else {
+ m = (l - i) % 4;
}
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
+ for (j = 0; j < k; j++) {
+ printk(" %2.2X%2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
}
- } else {
- /*
- * Build and execute Wide Board request.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- /*
- * Build and get a pointer to an Adv Library request structure.
- *
- * If the request is successfully built then send it below,
- * otherwise return with an error.
- */
- switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_DBG(3,
- "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
- /*
- * If busy is returned the request has not been enqueued.
- * It will be enqueued by the caller on the target's waiting
- * queue and retried later.
- *
- * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
- * count wide board busy conditions. They are updated in
- * adv_build_req and adv_get_sglist, respectively.
- */
- return ASC_BUSY;
- case ASC_ERROR:
- /*
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- */
+ switch (m) {
+ case 0:
default:
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
- }
-
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
+ case 1:
+ printk(" %2.2X", (unsigned)s[i + (j * 4)]);
break;
- case ASC_ERROR:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ case 2:
+ printk(" %2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1]);
break;
- default:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ case 3:
+ printk(" %2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
break;
}
- }
-
- ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- return ret;
-}
-/*
- * Build a request structure for the Asc Library (Narrow Board).
- *
- * The global structures 'asc_scsi_q' and 'asc_sg_head' are
- * used to build the request.
- *
- * If an error occurs, then queue the request on the board done
- * queue and return ASC_ERROR.
- */
-static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
-{
- struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
-
- /*
- * Mutually exclusive access is required to 'asc_scsi_q' and
- * 'asc_sg_head' until after the request is started.
- */
- memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
-
- /*
- * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
- */
- asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
-
- /*
- * Build the ASC_SCSI_Q request.
- *
- * For narrow boards a CDB length maximum of 12 bytes
- * is supported.
- */
- if (scp->cmd_len > ASC_MAX_CDB_LEN) {
- ASC_PRINT3
- ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- asc_scsi_q.cdbptr = &scp->cmnd[0];
- asc_scsi_q.q2.cdb_len = scp->cmd_len;
- asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
- asc_scsi_q.q1.target_lun = scp->device->lun;
- asc_scsi_q.q2.target_ix =
- ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
- asc_scsi_q.q1.sense_addr =
- cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
-
- /*
- * If there are any outstanding requests for the current target,
- * then every 255th request send an ORDERED request. This heuristic
- * tries to retain the benefit of request sorting while preventing
- * request starvation. 255 is the max number of tags or pending commands
- * a device may have outstanding.
- *
- * The request count is incremented below for every successfully
- * started request.
- *
- */
- if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
- (boardp->reqcnt[scp->device->id] % 255) == 0) {
- asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
- } else {
- asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
- }
-
- /*
- * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- ASC_STATS(scp->device->host, cont_cnt);
- scp->SCp.dma_handle = scp->request_bufflen ?
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction) : 0;
- asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
- asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- asc_scsi_q.q1.sg_queue_cnt = 0;
- asc_scsi_q.sg_head = NULL;
- } else {
- /*
- * CDB scatter-gather request list.
- */
- int sgcnt;
- int use_sg;
- struct scatterlist *slp;
-
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg =
- dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > scp->device->host->sg_tablesize) {
- ASC_PRINT3
- ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
- boardp->id, use_sg,
- scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg,
- scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
-
- ASC_STATS(scp->device->host, sg_cnt);
-
- /*
- * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
- * structure to point to it.
- */
- memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
-
- asc_scsi_q.q1.cntl |= QC_SG_HEAD;
- asc_scsi_q.sg_head = &asc_sg_head;
- asc_scsi_q.q1.data_cnt = 0;
- asc_scsi_q.q1.data_addr = 0;
- /* This is a byte value, otherwise it would need to be swapped. */
- asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
- ASC_STATS_ADD(scp->device->host, sg_elem,
- asc_sg_head.entry_cnt);
-
- /*
- * Convert scatter-gather list into ASC_SG_HEAD list.
- */
- for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
- asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(sg_dma_address(slp));
- asc_sg_head.sg_list[sgcnt].bytes =
- cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer,
- ASC_CEILING(sg_dma_len(slp), 512));
- }
+ printk("\n");
}
-
- ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
- return ASC_NOERROR;
}
/*
- * Build a request structure for the Adv Library (Wide Board).
- *
- * If an adv_req_t can not be allocated to issue the request,
- * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
- *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
- * microcode for DMA addresses or math operations are byte swapped
- * to little-endian order.
+ * asc_prt_asc_scsi_q()
*/
-static int
-adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
- ADV_SCSI_REQ_Q **adv_scsiqpp)
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
{
- adv_req_t *reqp;
- ADV_SCSI_REQ_Q *scsiqp;
+ ASC_SG_HEAD *sgp;
int i;
- int ret;
- struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
- /*
- * Allocate an adv_req_t structure from the board to execute
- * the command.
- */
- if (boardp->adv_reqp == NULL) {
- ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
- ASC_STATS(scp->device->host, adv_build_noreq);
- return ASC_BUSY;
- } else {
- reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp->next_reqp;
- reqp->next_reqp = NULL;
- }
-
- /*
- * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
- */
- scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
-
- /*
- * Initialize the structure.
- */
- scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
-
- /*
- * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
- */
- scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
-
- /*
- * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
- */
- reqp->cmndp = scp;
-
- /*
- * Build the ADV_SCSI_REQ_Q request.
- */
-
- /*
- * Set CDB length and copy it to the request structure.
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
- if (scp->cmd_len > ADV_MAX_CDB_LEN) {
- ASC_PRINT3
- ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- scsiqp->cdb_len = scp->cmd_len;
- /* Copy first 12 CDB bytes to cdb[]. */
- for (i = 0; i < scp->cmd_len && i < 12; i++) {
- scsiqp->cdb[i] = scp->cmnd[i];
- }
- /* Copy last 4 CDB bytes, if present, to cdb16[]. */
- for (; i < scp->cmd_len; i++) {
- scsiqp->cdb16[i - 12] = scp->cmnd[i];
- }
-
- scsiqp->target_id = scp->device->id;
- scsiqp->target_lun = scp->device->lun;
-
- scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- scsiqp->sense_len = sizeof(scp->sense_buffer);
-
- /*
- * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
-
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- scsiqp->vdata_addr = scp->request_buffer;
- scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
-
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- reqp->sgblkp = NULL;
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- if (scp->request_bufflen) {
- scsiqp->vdata_addr = scp->request_buffer;
- scp->SCp.dma_handle =
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction);
- } else {
- scsiqp->vdata_addr = NULL;
- scp->SCp.dma_handle = 0;
- }
- scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
- scsiqp->sg_list_ptr = NULL;
- scsiqp->sg_real_addr = 0;
- ASC_STATS(scp->device->host, cont_cnt);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- } else {
- /*
- * CDB scatter-gather request list.
- */
- struct scatterlist *slp;
- int use_sg;
-
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg =
- dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > ADV_MAX_SG_LIST) {
- ASC_PRINT3
- ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
- boardp->id, use_sg,
- scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg,
- scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
- /*
- * Free the 'adv_req_t' structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
+ printk
+ (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+ q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
+ q->q2.tag_code);
- return ASC_ERROR;
- }
+ printk
+ (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->q1.data_addr),
+ (ulong)le32_to_cpu(q->q1.data_cnt),
+ (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
- if ((ret =
- adv_get_sglist(boardp, reqp, scp,
- use_sg)) != ADV_SUCCESS) {
- /*
- * Free the adv_req_t structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
+ printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+ (ulong)q->cdbptr, q->q2.cdb_len,
+ (ulong)q->sg_head, q->q1.sg_queue_cnt);
- return ret;
+ if (q->sg_head) {
+ sgp = q->sg_head;
+ printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
+ printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
+ sgp->queue_cnt);
+ for (i = 0; i < sgp->entry_cnt; i++) {
+ printk(" [%u]: addr 0x%lx, bytes %lu\n",
+ i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
+ (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
}
- ASC_STATS(scp->device->host, sg_cnt);
- ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
}
-
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
- *adv_scsiqpp = scsiqp;
-
- return ASC_NOERROR;
}
/*
- * Build scatter-gather list for Adv Library (Wide Board).
- *
- * Additional ADV_SG_BLOCK structures will need to be allocated
- * if the total number of scatter-gather elements exceeds
- * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
- * assumed to be physically contiguous.
- *
- * Return:
- * ADV_SUCCESS(1) - SG List successfully created
- * ADV_ERROR(-1) - SG List creation failed
+ * asc_prt_asc_qdone_info()
*/
-static int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
- int use_sg)
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
{
- adv_sgblk_t *sgblkp;
- ADV_SCSI_REQ_Q *scsiqp;
- struct scatterlist *slp;
- int sg_elem_cnt;
- ADV_SG_BLOCK *sg_block, *prev_sg_block;
- ADV_PADDR sg_block_paddr;
- int i;
-
- scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
- slp = (struct scatterlist *)scp->request_buffer;
- sg_elem_cnt = use_sg;
- prev_sg_block = NULL;
- reqp->sgblkp = NULL;
-
- do {
- /*
- * Allocate a 'adv_sgblk_t' structure from the board free
- * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
- * (15) scatter-gather elements.
- */
- if ((sgblkp = boardp->adv_sgblkp) == NULL) {
- ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
- ASC_STATS(scp->device->host, adv_build_nosg);
-
- /*
- * Allocation failed. Free 'adv_sgblk_t' structures already
- * allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL) {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
- return ASC_BUSY;
- } else {
- /* Complete 'adv_sgblk_t' board allocation. */
- boardp->adv_sgblkp = sgblkp->next_sgblkp;
- sgblkp->next_sgblkp = NULL;
-
- /*
- * Get 8 byte aligned virtual and physical addresses for
- * the allocated ADV_SG_BLOCK structure.
- */
- sg_block =
- (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
- sg_block_paddr = virt_to_bus(sg_block);
-
- /*
- * Check if this is the first 'adv_sgblk_t' for the request.
- */
- if (reqp->sgblkp == NULL) {
- /* Request's first scatter-gather block. */
- reqp->sgblkp = sgblkp;
-
- /*
- * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
- * address pointers.
- */
- scsiqp->sg_list_ptr = sg_block;
- scsiqp->sg_real_addr =
- cpu_to_le32(sg_block_paddr);
- } else {
- /* Request's second or later scatter-gather block. */
- sgblkp->next_sgblkp = reqp->sgblkp;
- reqp->sgblkp = sgblkp;
-
- /*
- * Point the previous ADV_SG_BLOCK structure to
- * the newly allocated ADV_SG_BLOCK structure.
- */
- ASC_ASSERT(prev_sg_block != NULL);
- prev_sg_block->sg_ptr =
- cpu_to_le32(sg_block_paddr);
- }
- }
-
- for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
- sg_block->sg_list[i].sg_addr =
- cpu_to_le32(sg_dma_address(slp));
- sg_block->sg_list[i].sg_count =
- cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer,
- ASC_CEILING(sg_dma_len(slp), 512));
-
- if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
- sg_block->sg_cnt = i + 1;
- sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
- return ADV_SUCCESS;
- }
- slp++;
- }
- sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
- prev_sg_block = sg_block;
- }
- while (1);
- /* NOTREACHED */
+ printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
+ printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+ (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+ q->d2.tag_code);
+ printk
+ (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+ q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
}
/*
- * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ * asc_prt_adv_sgblock()
*
- * Interrupt callback function for the Narrow SCSI Asc Library.
+ * Display an ADV_SG_BLOCK structure.
*/
-static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
{
- asc_board_t *boardp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shost;
int i;
- ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
- (ulong)asc_dvc_varp, (ulong)qdonep);
- ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
-
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- */
- scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
- ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
-
- if (scp == NULL) {
- ASC_PRINT("asc_isr_callback: scp is NULL\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
-
- /*
- * If the request's host pointer is not valid, display a
- * message and return.
- */
- shost = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shost) {
- break;
- }
- }
- if (i == asc_board_count) {
- ASC_PRINT2
- ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong)scp, (ulong)shost);
- return;
- }
-
- ASC_STATS(shost, callback);
- ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
-
- /*
- * If the request isn't found on the active queue, it may
- * have been removed to handle a reset request.
- * Display a message and return.
- */
- boardp = ASC_BOARDP(shost);
- ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
-
- /*
- * 'qdonep' contains the command's ending status.
- */
- switch (qdonep->d3.done_stat) {
- case QD_NO_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
-
- /*
- * If an INQUIRY command completed successfully, then call
- * the AscInquiryHandling() function to set-up the device.
- */
- if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
- (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
- AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
- (ASC_SCSI_INQUIRY *)scp->
- request_buffer);
- }
-
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
- qdonep->remain_bytes <= scp->request_bufflen) {
- ASC_DBG1(1,
- "asc_isr_callback: underrun condition %u bytes\n",
- (unsigned)qdonep->remain_bytes);
- scp->resid = qdonep->remain_bytes;
- }
- break;
-
- case QD_WITH_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
- switch (qdonep->d3.host_stat) {
- case QHSTA_NO_ERROR:
- if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2,
- "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- } else {
- scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
- }
- break;
-
- default:
- /* QHSTA error occurred */
- ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
- qdonep->d3.host_stat);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result =
- HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
- scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
-
- default:
- ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
- qdonep->d3.done_stat);
- scp->result =
- HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
- scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
- }
-
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- qdonep->d3.done_stat == QD_NO_ERROR &&
- qdonep->d3.host_stat == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+ (ulong)b, sgblockno);
+ printk(" sg_cnt %u, sg_ptr 0x%lx\n",
+ b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
+ BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK);
+ if (b->sg_ptr != 0)
+ BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK);
+ for (i = 0; i < b->sg_cnt; i++) {
+ printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+ i, (ulong)b->sg_list[i].sg_addr,
+ (ulong)b->sg_list[i].sg_count);
}
-
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- return;
}
/*
- * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ * asc_prt_adv_scsi_req_q()
*
- * Callback function for the Wide SCSI Adv Library.
+ * Display an ADV_SCSI_REQ_Q structure.
*/
-static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
{
- asc_board_t *boardp;
- adv_req_t *reqp;
- adv_sgblk_t *sgblkp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shost;
- int i;
- ADV_DCNT resid_cnt;
-
- ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
- (ulong)adv_dvc_varp, (ulong)scsiqp);
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ int sg_blk_cnt;
+ struct asc_sg_block *sg_ptr;
- /*
- * Get the adv_req_t structure for the command that has been
- * completed. The adv_req_t structure actually contains the
- * completed ADV_SCSI_REQ_Q structure.
- */
- reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
- ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
- if (reqp == NULL) {
- ASC_PRINT("adv_isr_callback: reqp is NULL\n");
- return;
- }
+ printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- *
- * Note: The adv_req_t request structure and adv_sgblk_t structure,
- * if any, are dropped, because a board structure pointer can not be
- * determined.
- */
- scp = reqp->cmndp;
- ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
- if (scp == NULL) {
- ASC_PRINT
- ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+ printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+ q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
- /*
- * If the request's host pointer is not valid, display a message
- * and return.
- */
- shost = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shost) {
- break;
- }
- }
- /*
- * Note: If the host structure is not found, the adv_req_t request
- * structure and adv_sgblk_t structure, if any, is dropped.
- */
- if (i == asc_board_count) {
- ASC_PRINT2
- ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong)scp, (ulong)shost);
- return;
- }
+ printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+ q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
- ASC_STATS(shost, callback);
- ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
+ printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->data_cnt),
+ (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
- /*
- * If the request isn't found on the active queue, it may have been
- * removed to handle a reset request. Display a message and return.
- *
- * Note: Because the structure may still be in use don't attempt
- * to free the adv_req_t and adv_sgblk_t, if any, structures.
- */
- boardp = ASC_BOARDP(shost);
- ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
+ printk
+ (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+ q->cdb_len, q->done_status, q->host_status, q->scsi_status);
- /*
- * 'done_status' contains the command's ending status.
- */
- switch (scsiqp->done_status) {
- case QD_NO_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
+ printk(" sg_working_ix 0x%x, target_cmd %u\n",
+ q->sg_working_ix, q->target_cmd);
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- resid_cnt = le32_to_cpu(scsiqp->data_cnt);
- if (scp->request_bufflen != 0 && resid_cnt != 0 &&
- resid_cnt <= scp->request_bufflen) {
- ASC_DBG1(1,
- "adv_isr_callback: underrun condition %lu bytes\n",
- (ulong)resid_cnt);
- scp->resid = resid_cnt;
- }
- break;
+ printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+ (ulong)le32_to_cpu(q->scsiq_rptr),
+ (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
- case QD_WITH_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
- switch (scsiqp->host_status) {
- case QHSTA_NO_ERROR:
- if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2,
- "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(scsiqp->scsi_status);
- } else {
- scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ /* Display the request's ADV_SG_BLOCK structures. */
+ if (q->sg_list_ptr != NULL) {
+ sg_blk_cnt = 0;
+ while (1) {
+ /*
+ * 'sg_ptr' is a physical address. Convert it to a virtual
+ * address by indexing 'sg_blk_cnt' into the virtual address
+ * array 'sg_list_ptr'.
+ *
+ * XXX - Assumes all SG physical blocks are virtually contiguous.
+ */
+ sg_ptr =
+ &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
+ asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+ if (sg_ptr->sg_ptr == 0) {
+ break;
}
- break;
-
- default:
- /* Some other QHSTA error occurred. */
- ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
- scsiqp->host_status);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
+ sg_blk_cnt++;
}
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result =
- HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
- break;
-
- default:
- ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
- scsiqp->done_status);
- scp->result =
- HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
- break;
- }
-
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- scsiqp->done_status == QD_NO_ERROR &&
- scsiqp->host_status == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
- }
-
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- /*
- * Free all 'adv_sgblk_t' structures allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL) {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
}
-
- /*
- * Free the adv_req_t structure used with the command by adding
- * it back to the board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
-
- ASC_DBG(1, "adv_isr_callback: done\n");
-
- return;
}
+#endif /* ADVANSYS_DEBUG */
/*
- * adv_async_callback() - Adv Library asynchronous event callback function.
+ * The advansys chip/microcode contains a 32-bit identifier for each command
+ * known as the 'srb'. I don't know what it stands for. The driver used
+ * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it
+ * with bus_to_virt. Now the driver keeps a per-host map of integers to
+ * pointers. It auto-expands when full, unless it can't allocate memory.
+ * Note that an srb of 0 is treated specially by the chip/firmware, hence
+ * the return of i+1 in this routine, and the corresponding subtraction in
+ * the inverse routine.
*/
-static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+#define BAD_SRB 0
+static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr)
{
- switch (code) {
- case ADV_ASYNC_SCSI_BUS_RESET_DET:
- /*
- * The firmware detected a SCSI Bus reset.
- */
- ASC_DBG(0,
- "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
- break;
+ int i;
+ void **new_ptr;
- case ADV_ASYNC_RDMA_FAILURE:
- /*
- * Handle RDMA failure by resetting the SCSI Bus and
- * possibly the chip if it is unresponsive. Log the error
- * with a unique code.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
- AdvResetChipAndSB(adv_dvc_varp);
- break;
+ for (i = 0; i < asc_dvc->ptr_map_count; i++) {
+ if (!asc_dvc->ptr_map[i])
+ goto out;
+ }
- case ADV_HOST_SCSI_BUS_RESET:
- /*
- * Host generated SCSI bus reset occurred.
- */
- ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
- break;
+ if (asc_dvc->ptr_map_count == 0)
+ asc_dvc->ptr_map_count = 1;
+ else
+ asc_dvc->ptr_map_count *= 2;
- default:
- ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
- break;
- }
+ new_ptr = krealloc(asc_dvc->ptr_map,
+ asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC);
+ if (!new_ptr)
+ return BAD_SRB;
+ asc_dvc->ptr_map = new_ptr;
+ out:
+ ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i);
+ asc_dvc->ptr_map[i] = ptr;
+ return i + 1;
}
-/*
- * Add a 'REQP' to the end of specified queue. Set 'tidmask'
- * to indicate a command is queued for the device.
- *
- * 'flag' may be either ASC_FRONT or ASC_BACK.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
+static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb)
{
- int tid;
-
- ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
- (ulong)ascq, (ulong)reqp, flag);
- ASC_ASSERT(reqp != NULL);
- ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if (flag == ASC_FRONT) {
- reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
- ascq->q_first[tid] = reqp;
- /* If the queue was empty, set the last pointer. */
- if (ascq->q_last[tid] == NULL) {
- ascq->q_last[tid] = reqp;
- }
- } else { /* ASC_BACK */
- if (ascq->q_last[tid] != NULL) {
- ascq->q_last[tid]->host_scribble =
- (unsigned char *)reqp;
- }
- ascq->q_last[tid] = reqp;
- reqp->host_scribble = NULL;
- /* If the queue was empty, set the first pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_first[tid] = reqp;
- }
- }
- /* The queue has at least one entry, set its bit. */
- ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_tot_cnt[tid]++;
- ascq->q_cur_cnt[tid]++;
- if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
- ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
- ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
- tid, ascq->q_max_cnt[tid]);
- }
- REQPTIME(reqp) = REQTIMESTAMP();
-#endif /* ADVANSYS_STATS */
- ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
- return;
-}
+ void *ptr;
-/*
- * Return first queued 'REQP' on the specified queue for
- * the specified target device. Clear the 'tidmask' bit for
- * the device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static REQP asc_dequeue(asc_queue_t *ascq, int tid)
-{
- REQP reqp;
-
- ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if ((reqp = ascq->q_first[tid]) != NULL) {
- ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_cur_cnt[tid]--;
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
- REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
-#endif /* ADVANSYS_STATS */
+ srb--;
+ if (srb >= asc_dvc->ptr_map_count) {
+ printk("advansys: bad SRB %u, max %u\n", srb,
+ asc_dvc->ptr_map_count);
+ return NULL;
}
- ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
- return reqp;
+ ptr = asc_dvc->ptr_map[srb];
+ asc_dvc->ptr_map[srb] = NULL;
+ ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb);
+ return ptr;
}
/*
- * Return a pointer to a singly linked list of all the requests queued
- * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
- *
- * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
- * the last request returned in the singly linked list.
- *
- * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
- * then all queued requests are concatenated into one list and
- * returned.
+ * advansys_info()
*
- * Note: If 'lastpp' is used to append a new list to the end of
- * an old list, only change the old list last pointer if '*lastpp'
- * (or the function return value) is not NULL, i.e. use a temporary
- * variable for 'lastpp' and check its value after the function return
- * before assigning it to the list last pointer.
+ * Return suitable for printing on the console with the argument
+ * adapter's configuration information.
*
- * Unfortunately collecting queuing time statistics adds overhead to
- * the function that isn't inherent to the function's algorithm.
+ * Note: The information line should not exceed ASC_INFO_SIZE bytes,
+ * otherwise the static 'info' array will be overrun.
*/
-static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+static const char *advansys_info(struct Scsi_Host *shost)
{
- REQP firstp, lastp;
- int i;
-
- ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
- ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+ static char info[ASC_INFO_SIZE];
+ struct asc_board *boardp = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ char *busname;
+ char *widename = NULL;
- /*
- * If 'tid' is not ASC_TID_ALL, return requests only for
- * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
- * requests for all tids.
- */
- if (tid != ASC_TID_ALL) {
- /* Return all requests for the specified 'tid'. */
- if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
- /* List is empty; Set first and last return pointers to NULL. */
- firstp = lastp = NULL;
- } else {
- firstp = ascq->q_first[tid];
- lastp = ascq->q_last[tid];
- ascq->q_first[tid] = ascq->q_last[tid] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- ascq->q_cur_cnt[tid] = 0;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq,
- reqp, tid);
- }
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ASC_DBG(1, "begin\n");
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
+ ASC_IS_ISAPNP) {
+ busname = "ISA PnP";
+ } else {
+ busname = "ISA";
}
-#endif /* ADVANSYS_STATS */
- }
- } else {
- /* Return all requests for all tids. */
- firstp = lastp = NULL;
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if (firstp == NULL) {
- firstp = ascq->q_first[i];
- lastp = ascq->q_last[i];
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+ ASC_VERSION, busname,
+ (ulong)shost->io_port,
+ (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+ boardp->irq, shost->dma_channel);
+ } else {
+ if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+ busname = "VL";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+ busname = "EISA";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+ == ASC_IS_PCI_ULTRA) {
+ busname = "PCI Ultra";
} else {
- ASC_ASSERT(lastp != NULL);
- lastp->host_scribble =
- (unsigned char *)ascq->q_first[i];
- lastp = ascq->q_last[i];
+ busname = "PCI";
}
- ascq->q_first[i] = ascq->q_last[i] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-#ifdef ADVANSYS_STATS
- ascq->q_cur_cnt[i] = 0;
-#endif /* ADVANSYS_STATS */
- }
- }
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq, reqp,
- reqp->device->id);
+ } else {
+ busname = "?";
+ shost_printk(KERN_ERR, shost, "unknown bus "
+ "type %d\n", asc_dvc_varp->bus_type);
}
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, busname, (ulong)shost->io_port,
+ (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+ boardp->irq);
}
-#endif /* ADVANSYS_STATS */
- }
- if (lastpp) {
- *lastpp = lastp;
- }
- ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
- return firstp;
-}
-
-/*
- * Remove the specified 'REQP' from the specified queue for
- * the specified target device. Clear the 'tidmask' bit for the
- * device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's the next pointer.
- *
- * Return ASC_TRUE if the command was found and removed,
- * otherwise return ASC_FALSE.
- */
-static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
-{
- REQP currp, prevp;
- int tid;
- int ret = ASC_FALSE;
-
- ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
- (ulong)ascq, (ulong)reqp);
- ASC_ASSERT(reqp != NULL);
-
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
- /*
- * Handle the common case of 'reqp' being the first
- * entry on the queue.
- */
- if (reqp == ascq->q_first[tid]) {
- ret = ASC_TRUE;
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is now empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
- } else if (ascq->q_first[tid] != NULL) {
- ASC_ASSERT(ascq->q_last[tid] != NULL);
+ } else {
/*
- * Because the case of 'reqp' being the first entry has been
- * handled above and it is known the queue is not empty, if
- * 'reqp' is found on the queue it is guaranteed the queue will
- * not become empty and that 'q_first[tid]' will not be changed.
+ * Wide Adapter Information
*
- * Set 'prevp' to the first entry, 'currp' to the second entry,
- * and search for 'reqp'.
+ * Memory-mapped I/O is used instead of I/O space to access
+ * the adapter, but display the I/O Port range. The Memory
+ * I/O address is displayed through the driver /proc file.
*/
- for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
- currp; prevp = currp, currp = REQPNEXT(currp)) {
- if (currp == reqp) {
- ret = ASC_TRUE;
- prevp->host_scribble =
- (unsigned char *)REQPNEXT(currp);
- reqp->host_scribble = NULL;
- if (ascq->q_last[tid] == reqp) {
- ascq->q_last[tid] = prevp;
- }
- break;
- }
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ widename = "Ultra-Wide";
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ widename = "Ultra2-Wide";
+ } else {
+ widename = "Ultra3-Wide";
}
+ sprintf(info,
+ "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
+ (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq);
}
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- if (ret == ASC_TRUE) {
- ascq->q_cur_cnt[tid]--;
- REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
- }
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-#endif /* ADVANSYS_STATS */
- ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
- return ret;
+ BUG_ON(strlen(info) >= ASC_INFO_SIZE);
+ ASC_DBG(1, "end\n");
+ return info;
}
+#ifdef CONFIG_PROC_FS
/*
- * Execute as many queued requests as possible for the specified queue.
+ * asc_prt_line()
+ *
+ * If 'cp' is NULL print to the console, otherwise print to a buffer.
*
- * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
+ * Return 0 if printing to the console, otherwise return the number of
+ * bytes written to the buffer.
+ *
+ * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
+ * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
*/
-static void asc_execute_queue(asc_queue_t *ascq)
+static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
{
- ADV_SCSI_BIT_ID_TYPE scan_tidmask;
- REQP reqp;
- int i;
+ va_list args;
+ int ret;
+ char s[ASC_PRTLINE_SIZE];
- ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
- /*
- * Execute queued commands for devices attached to
- * the current board in round-robin fashion.
- */
- scan_tidmask = ascq->q_tidmask;
- do {
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if ((reqp = asc_dequeue(ascq, i)) == NULL) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- } else
- if (asc_execute_scsi_cmnd
- ((struct scsi_cmnd *)reqp)
- == ASC_BUSY) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- /*
- * The request returned ASC_BUSY. Enqueue at the front of
- * target's waiting list to maintain correct ordering.
- */
- asc_enqueue(ascq, reqp, ASC_FRONT);
- }
- }
- }
- } while (scan_tidmask);
- return;
+ va_start(args, fmt);
+ ret = vsprintf(s, fmt, args);
+ BUG_ON(ret >= ASC_PRTLINE_SIZE);
+ if (buf == NULL) {
+ (void)printk(s);
+ ret = 0;
+ } else {
+ ret = min(buflen, ret);
+ memcpy(buf, s, ret);
+ }
+ va_end(args);
+ return ret;
}
-#ifdef CONFIG_PROC_FS
/*
* asc_prt_board_devices()
*
@@ -6245,14 +2919,13 @@ static void asc_execute_queue(asc_queue_t *ascq)
*/
static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
int chip_scsi_id;
int i;
- boardp = ASC_BOARDP(shost);
leftlen = cplen;
totlen = len = 0;
@@ -6286,13 +2959,12 @@ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
ushort major, minor, letter;
- boardp = ASC_BOARDP(shost);
leftlen = cplen;
totlen = len = 0;
@@ -6452,7 +3124,7 @@ static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
*/
static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp;
int leftlen;
int totlen;
@@ -6464,7 +3136,6 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
#endif /* CONFIG_ISA */
uchar serialstr[13];
- boardp = ASC_BOARDP(shost);
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
ep = &boardp->eep_config.asc_eep;
@@ -6586,7 +3257,7 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
*/
static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
ADV_DVC_VAR *adv_dvc_varp;
int leftlen;
int totlen;
@@ -6601,7 +3272,6 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
ushort *wordp;
ushort sdtr_speed = 0;
- boardp = ASC_BOARDP(shost);
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
ep_3550 = &boardp->eep_config.adv_3550_eep;
@@ -6873,14 +3543,12 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
*/
static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
int chip_scsi_id;
- boardp = ASC_BOARDP(shost);
-
leftlen = cplen;
totlen = len = 0;
@@ -6912,10 +3580,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
boardp->asc_n_io_port);
ASC_PRT_NEXT();
- /* 'shost->n_io_port' may be truncated because it is only one byte. */
- len = asc_prt_line(cp, leftlen,
- " io_port 0x%x, n_io_port 0x%x\n",
- shost->io_port, shost->n_io_port);
+ len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
ASC_PRT_NEXT();
if (ASC_NARROW_BOARD(boardp)) {
@@ -6940,7 +3605,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int chip_scsi_id;
int leftlen;
int totlen;
@@ -6950,7 +3615,6 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
int i;
int renegotiate = 0;
- boardp = ASC_BOARDP(shost);
v = &boardp->dvc_var.asc_dvc_var;
c = &boardp->dvc_cfg.asc_dvc_cfg;
chip_scsi_id = c->chip_scsi_id;
@@ -6963,15 +3627,10 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
shost->host_no);
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
- c->chip_version, c->lib_version, c->lib_serial_no,
- c->mcode_date);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
- " mcode_version 0x%x, err_code %u\n",
- c->mcode_version, v->err_code);
+ len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x, err_code %u\n",
+ c->chip_version, c->mcode_date, c->mcode_version,
+ v->err_code);
ASC_PRT_NEXT();
/* Current number of commands waiting for the host. */
@@ -7128,7 +3787,7 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
@@ -7145,7 +3804,6 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
ushort period = 0;
int renegotiate = 0;
- boardp = ASC_BOARDP(shost);
v = &boardp->dvc_var.adv_dvc_var;
c = &boardp->dvc_cfg.adv_dvc_cfg;
iop_base = v->iop_base;
@@ -7167,10 +3825,9 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
v->err_code);
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
- c->chip_version, c->lib_version, c->mcode_date,
- c->mcode_version);
+ len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x\n", c->chip_version,
+ c->mcode_date, c->mcode_version);
ASC_PRT_NEXT();
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
@@ -7376,12 +4033,12 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
{
int cnt = 0;
- ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+ ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n",
(unsigned)offset, (unsigned)advoffset, cplen);
if (offset <= advoffset) {
/* Read offset below current offset, copy everything. */
cnt = min(cplen, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
(ulong)curbuf, (ulong)cp, cnt);
memcpy(curbuf, cp, cnt);
} else if (offset < advoffset + cplen) {
@@ -7389,1125 +4046,4537 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
cnt = (advoffset + cplen) - offset;
cp = (cp + cplen) - cnt;
cnt = min(cnt, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
(ulong)curbuf, (ulong)cp, cnt);
memcpy(curbuf, cp, cnt);
}
return cnt;
}
+#ifdef ADVANSYS_STATS
/*
- * asc_prt_line()
+ * asc_prt_board_stats()
*
- * If 'cp' is NULL print to the console, otherwise print to a buffer.
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
*
- * Return 0 if printing to the console, otherwise return the number of
- * bytes written to the buffer.
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
+{
+ struct asc_board *boardp = shost_priv(shost);
+ struct asc_stats *s = &boardp->asc_stats;
+
+ int leftlen = cplen;
+ int len, totlen = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+ s->queuecommand, s->reset, s->biosparam,
+ s->interrupt);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+ s->callback, s->done, s->build_error,
+ s->adv_build_noreq, s->adv_build_nosg);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+ s->exe_noerror, s->exe_busy, s->exe_error,
+ s->exe_unknown);
+ ASC_PRT_NEXT();
+
+ /*
+ * Display data transfer statistics.
+ */
+ if (s->xfer_cnt > 0) {
+ len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ",
+ s->xfer_cnt, s->xfer_elem);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n",
+ s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
+ ASC_PRT_NEXT();
+
+ /* Scatter gather transfer statistics */
+ len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+ s->xfer_elem / s->xfer_cnt,
+ ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+ (s->xfer_sect / 2) / s->xfer_elem,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+ (s->xfer_sect / 2) / s->xfer_cnt,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
+ ASC_PRT_NEXT();
+ }
+
+ return totlen;
+}
+#endif /* ADVANSYS_STATS */
+
+/*
+ * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
*
- * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
- * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset into a /proc/scsi/advansys/[0...] file
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written to a
+ * /proc/scsi/advansys/[0...] file.
+ *
+ * Note: This function uses the per board buffer 'prtbuf' which is
+ * allocated when the board is initialized in advansys_detect(). The
+ * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
+ * used to write to the buffer. The way asc_proc_copy() is written
+ * if 'prtbuf' is too small it will not be overwritten. Instead the
+ * user just won't get all the available statistics.
*/
-static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
+static int
+advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
- va_list args;
- int ret;
- char s[ASC_PRTLINE_SIZE];
+ struct asc_board *boardp = shost_priv(shost);
+ char *cp;
+ int cplen;
+ int cnt;
+ int totcnt;
+ int leftlen;
+ char *curbuf;
+ off_t advoffset;
- va_start(args, fmt);
- ret = vsprintf(s, fmt, args);
- ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
- if (buf == NULL) {
- (void)printk(s);
- ret = 0;
+ ASC_DBG(1, "begin\n");
+
+ /*
+ * User write not supported.
+ */
+ if (inout == TRUE)
+ return -ENOSYS;
+
+ /*
+ * User read of /proc/scsi/advansys/[0...] file.
+ */
+
+ /* Copy read data starting at the beginning of the buffer. */
+ *start = buffer;
+ curbuf = buffer;
+ advoffset = 0;
+ totcnt = 0;
+ leftlen = length;
+
+ /*
+ * Get board configuration information.
+ *
+ * advansys_info() returns the board string from its own static buffer.
+ */
+ cp = (char *)advansys_info(shost);
+ strcat(cp, "\n");
+ cplen = strlen(cp);
+ /* Copy board information. */
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display Wide Board BIOS Information.
+ */
+ if (!ASC_NARROW_BOARD(boardp)) {
+ cp = boardp->prtbuf;
+ cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+ cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+ }
+
+ /*
+ * Display driver information for each device attached to the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display EEPROM configuration for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
} else {
- ret = min(buflen, ret);
- memcpy(buf, s, ret);
+ cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
}
- va_end(args);
- return ret;
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display driver configuration and information for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+#ifdef ADVANSYS_STATS
+ /*
+ * Display driver statistics for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+#endif /* ADVANSYS_STATS */
+
+ /*
+ * Display Asc Library dynamic configuration information
+ * for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
+ }
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+
+ return totcnt;
}
#endif /* CONFIG_PROC_FS */
-/*
- * --- Functions Required by the Asc Library
- */
+static void asc_scsi_done(struct scsi_cmnd *scp)
+{
+ scsi_dma_unmap(scp);
+ ASC_STATS(scp->device->host, done);
+ scp->scsi_done(scp);
+}
-/*
- * Delay for 'n' milliseconds. Don't use the 'jiffies'
- * global variable which is incremented once every 5 ms
- * from a timer interrupt, because this function may be
- * called when interrupts are disabled.
- */
-static void DvcSleepMilliSecond(ADV_DCNT n)
+static void AscSetBank(PortAddr iop_base, uchar bank)
{
- ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
- mdelay(n);
+ uchar val;
+
+ val = AscGetChipControl(iop_base) &
+ (~
+ (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
+ CC_CHIP_RESET));
+ if (bank == 1) {
+ val |= CC_BANK_ONE;
+ } else if (bank == 2) {
+ val |= CC_DIAG | CC_BANK_ONE;
+ } else {
+ val &= ~CC_BANK_ONE;
+ }
+ AscSetChipControl(iop_base, val);
}
-/*
- * Currently and inline noop but leave as a placeholder.
- * Leave DvcEnterCritical() as a noop placeholder.
- */
-static inline ulong DvcEnterCritical(void)
+static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
{
- return 0;
+ AscSetBank(iop_base, 1);
+ AscWriteChipIH(iop_base, ins_code);
+ AscSetBank(iop_base, 0);
}
-/*
- * Critical sections are all protected by the board spinlock.
- * Leave DvcLeaveCritical() as a noop placeholder.
- */
-static inline void DvcLeaveCritical(ulong flags)
+static int AscStartChip(PortAddr iop_base)
+{
+ AscSetChipControl(iop_base, 0);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ return (0);
+ }
+ return (1);
+}
+
+static int AscStopChip(PortAddr iop_base)
+{
+ uchar cc_val;
+
+ cc_val =
+ AscGetChipControl(iop_base) &
+ (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+ AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+ return (0);
+ }
+ return (1);
+}
+
+static int AscIsChipHalted(PortAddr iop_base)
+{
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
+{
+ PortAddr iop_base;
+ int i = 10;
+
+ iop_base = asc_dvc->iop_base;
+ while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
+ && (i-- > 0)) {
+ mdelay(100);
+ }
+ AscStopChip(iop_base);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+ udelay(60);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+ AscSetChipControl(iop_base, CC_HALT);
+ mdelay(200);
+ AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+ AscSetChipStatus(iop_base, 0);
+ return (AscIsChipHalted(iop_base));
+}
+
+static int AscFindSignature(PortAddr iop_base)
+{
+ ushort sig_word;
+
+ ASC_DBG(1, "AscGetChipSignatureByte(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureByte(iop_base));
+ if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
+ ASC_DBG(1, "AscGetChipSignatureWord(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureWord(iop_base));
+ sig_word = AscGetChipSignatureWord(iop_base);
+ if ((sig_word == (ushort)ASC_1000_ID0W) ||
+ (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void AscEnableInterrupt(PortAddr iop_base)
+{
+ ushort cfg;
+
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+}
+
+static void AscDisableInterrupt(PortAddr iop_base)
+{
+ ushort cfg;
+
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+}
+
+static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
+{
+ unsigned char byte_data;
+ unsigned short word_data;
+
+ if (isodd_word(addr)) {
+ AscSetChipLramAddr(iop_base, addr - 1);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = (word_data >> 8) & 0xFF;
+ } else {
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = word_data & 0xFF;
+ }
+ return byte_data;
+}
+
+static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
+{
+ ushort word_data;
+
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ return (word_data);
+}
+
+#if CC_VERY_LONG_SG_LIST
+static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
+{
+ ushort val_low, val_high;
+ ASC_DCNT dword_data;
+
+ AscSetChipLramAddr(iop_base, addr);
+ val_low = AscGetChipLramData(iop_base);
+ val_high = AscGetChipLramData(iop_base);
+ dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+ return (dword_data);
+}
+#endif /* CC_VERY_LONG_SG_LIST */
+
+static void
+AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
+{
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < words; i++) {
+ AscSetChipLramData(iop_base, set_wval);
+ }
+}
+
+static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
+{
+ AscSetChipLramAddr(iop_base, addr);
+ AscSetChipLramData(iop_base, word_val);
+}
+
+static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
{
- return;
+ ushort word_data;
+
+ if (isodd_word(addr)) {
+ addr--;
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0x00FF;
+ word_data |= (((ushort)byte_val << 8) & 0xFF00);
+ } else {
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0xFF00;
+ word_data |= ((ushort)byte_val & 0x00FF);
+ }
+ AscWriteLramWord(iop_base, addr, word_data);
}
/*
- * void
- * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
- *
- * Calling/Exit State:
- * none
+ * Copy 2 bytes to LRAM.
*
- * Description:
- * Output an ASC_SCSI_Q structure to the chip
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when written to LRAM.
*/
static void
-DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+AscMemWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int words)
{
int i;
- ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
AscSetChipLramAddr(iop_base, s_addr);
for (i = 0; i < 2 * words; i += 2) {
- if (i == 4 || i == 20) {
- continue;
- }
+ /*
+ * On a little-endian system the second argument below
+ * produces a little-endian ushort which is written to
+ * LRAM in little-endian order. On a big-endian system
+ * the second argument produces a big-endian ushort which
+ * is "transparently" byte-swapped by outpw() and written
+ * in little-endian order to LRAM.
+ */
outpw(iop_base + IOP_RAM_DATA,
- ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+ ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
}
}
/*
- * void
- * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+ * Copy 4 bytes to LRAM.
*
- * Calling/Exit State:
- * none
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when writen to LRAM.
+ */
+static void
+AscMemDWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int dwords)
+{
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 4 * dwords; i += 4) {
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
+ }
+}
+
+/*
+ * Copy 2 bytes from LRAM.
*
- * Description:
- * Input an ASC_QDONE_INFO structure from the chip
+ * The source data is assumed to be in little-endian order in LRAM
+ * and is maintained in little-endian order when written to memory.
*/
static void
-DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+AscMemWordCopyPtrFromLram(PortAddr iop_base,
+ ushort s_addr, uchar *d_buffer, int words)
{
int i;
ushort word;
AscSetChipLramAddr(iop_base, s_addr);
for (i = 0; i < 2 * words; i += 2) {
- if (i == 10) {
- continue;
- }
word = inpw(iop_base + IOP_RAM_DATA);
- inbuf[i] = word & 0xff;
- inbuf[i + 1] = (word >> 8) & 0xff;
+ d_buffer[i] = word & 0xff;
+ d_buffer[i + 1] = (word >> 8) & 0xff;
}
- ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
}
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
+static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
{
-#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
-#else /* !defined(CONFIG_PCI) */
- return 0;
-#endif /* !defined(CONFIG_PCI) */
+ ASC_DCNT sum;
+ int i;
+
+ sum = 0L;
+ for (i = 0; i < words; i++, s_addr += 2) {
+ sum += AscReadLramWord(iop_base, s_addr);
+ }
+ return (sum);
}
-/*
- * Write a PCI configuration byte.
- */
-static void __init
-DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
+static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
{
-#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#endif /* CONFIG_PCI */
+ uchar i;
+ ushort s_addr;
+ PortAddr iop_base;
+ ushort warn_code;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+ (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
+ 64) >> 1));
+ i = ASC_MIN_ACTIVE_QNO;
+ s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(i - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ }
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)ASC_QLINK_END);
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)asc_dvc->max_total_qng);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
+ i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+ }
+ return warn_code;
}
-/*
- * Return the BIOS address of the adapter at the specified
- * I/O port and with the specified bus type.
- */
-static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
+static ASC_DCNT
+AscLoadMicroCode(PortAddr iop_base,
+ ushort s_addr, uchar *mcode_buf, ushort mcode_size)
{
- ushort cfg_lsw;
- ushort bios_addr;
+ ASC_DCNT chksum;
+ ushort mcode_word_size;
+ ushort mcode_chksum;
- /*
- * The PCI BIOS is re-located by the motherboard BIOS. Because
- * of this the driver can not determine where a PCI BIOS is
- * loaded and executes.
- */
- if (bus_type & ASC_IS_PCI) {
- return (0);
+ /* Write the microcode buffer starting at LRAM address 0. */
+ mcode_word_size = (ushort)(mcode_size >> 1);
+ AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+ AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
+ chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+ ASC_DBG(1, "chksum 0x%lx\n", (ulong)chksum);
+ mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
+ (ushort)ASC_CODE_SEC_BEG,
+ (ushort)((mcode_size -
+ s_addr - (ushort)
+ ASC_CODE_SEC_BEG) /
+ 2));
+ ASC_DBG(1, "mcode_chksum 0x%lx\n", (ulong)mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+ return chksum;
+}
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static uchar _asc_mcode_buf[] = {
+ 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
+ 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+ 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
+ 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
+ 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
+ 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
+ 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
+ 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
+ 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
+ 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
+ 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+ 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
+ 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
+ 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
+ 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
+ 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
+ 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
+ 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
+ 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
+ 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
+ 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
+ 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+ 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
+ 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
+ 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
+ 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
+ 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
+ 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
+ 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
+ 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
+ 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
+ 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+ 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
+ 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
+ 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
+ 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
+ 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
+ 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
+ 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
+ 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
+ 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
+ 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
+ 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+ 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
+ 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
+ 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
+ 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
+ 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
+ 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
+ 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
+ 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
+ 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
+ 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
+ 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
+ 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+ 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
+ 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
+ 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
+ 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
+ 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
+ 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
+ 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
+ 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
+ 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
+ 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
+ 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
+ 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
+ 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
+ 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
+ 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
+ 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
+ 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
+ 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
+ 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
+ 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
+ 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
+ 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
+ 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
+ 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
+ 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
+ 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
+ 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
+ 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
+ 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
+ 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
+ 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+ 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
+ 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
+ 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
+ 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
+ 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
+ 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
+ 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
+ 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
+ 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
+ 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
+ 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+ 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
+ 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
+ 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
+ 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
+ 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
+ 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
+ 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
+ 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
+ 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
+ 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
+ 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+ 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
+ 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
+ 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
+ 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
+ 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
+ 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
+ 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
+ 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
+ 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
+ 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
+ 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
+ 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+ 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
+ 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
+ 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
+ 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
+ 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
+ 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
+ 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
+ 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
+ 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
+ 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
+ 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+ 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
+ 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
+ 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
+ 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
+ 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
+ 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
+ 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
+ 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
+ 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
+ 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
+ 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
+ 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+ 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
+ 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
+ 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
+ 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
+ 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+ 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
+ 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
+ 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
+ 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
+ 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
+ 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+ 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
+ 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
+ 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
+ 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+ 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
+ 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
+ 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
+ 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
+ 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
+ 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
+ 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+ 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+ 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
+ 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
+ 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
+};
+
+static unsigned short _asc_mcode_size = sizeof(_asc_mcode_buf);
+static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc3550_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
+ 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
+ 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
+ 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
+ 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
+ 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
+ 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
+ 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
+ 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
+ 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+ 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+ 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
+ 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
+ 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+ 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
+ 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
+ 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
+ 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
+ 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
+ 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
+ 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
+ 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
+ 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
+ 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
+ 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
+ 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
+ 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
+ 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
+ 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
+ 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
+ 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
+ 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
+ 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
+ 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
+ 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
+ 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
+ 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
+ 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
+ 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
+ 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
+ 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
+ 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
+ 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
+ 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
+ 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
+ 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
+ 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
+ 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+ 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
+ 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
+ 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
+ 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
+ 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
+ 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
+ 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
+ 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
+ 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
+ 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
+ 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
+ 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
+ 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
+ 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+ 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
+ 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
+ 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
+ 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
+ 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
+ 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
+ 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
+ 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
+ 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
+ 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
+ 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
+ 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
+ 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
+ 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
+ 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
+ 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
+ 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
+ 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
+ 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
+ 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+ 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
+ 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
+ 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
+ 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
+ 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
+ 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
+ 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
+ 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
+ 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
+ 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
+ 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
+ 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
+ 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
+ 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
+ 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
+ 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
+ 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
+ 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
+ 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
+ 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
+ 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
+ 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
+ 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
+ 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
+ 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
+ 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
+ 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
+ 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
+ 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
+ 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
+ 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
+ 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
+ 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
+ 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
+ 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
+ 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
+ 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
+ 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
+ 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
+ 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
+ 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
+ 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
+ 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
+ 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
+ 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
+ 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
+ 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
+ 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
+ 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
+ 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
+ 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+ 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
+ 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
+ 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
+ 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
+ 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
+ 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
+ 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
+ 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
+ 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
+ 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
+ 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
+ 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
+ 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
+ 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
+ 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
+ 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
+ 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
+ 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
+ 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
+ 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+ 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
+ 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
+ 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
+ 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
+ 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
+ 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
+ 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
+ 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
+ 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
+ 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
+ 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
+ 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
+ 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
+ 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
+ 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
+ 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
+ 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
+ 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
+ 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
+ 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
+ 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
+ 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
+ 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
+ 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
+ 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
+ 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
+ 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+ 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
+ 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
+ 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
+ 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
+ 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
+ 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
+ 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
+ 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
+ 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
+ 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
+ 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
+ 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
+ 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
+ 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
+ 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
+ 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
+ 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
+ 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
+ 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
+ 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
+ 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
+ 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
+ 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
+ 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
+ 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
+ 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
+ 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
+ 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
+ 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
+ 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
+ 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
+ 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
+ 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
+ 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
+ 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
+ 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
+ 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
+ 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
+ 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
+ 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
+ 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
+ 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
+ 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
+ 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
+ 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
+ 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
+ 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
+ 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
+ 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
+ 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
+ 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
+ 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
+ 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
+ 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
+ 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+ 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
+ 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
+ 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+ 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
+ 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
+ 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
+ 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
+ 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+ 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
+ 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+ 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
+ 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+ 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
+ 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
+ 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
+ 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
+ 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
+ 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
+ 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
+ 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
+ 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
+ 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
+ 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
+ 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
+ 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
+ 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
+ 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
+ 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
+ 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
+ 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
+ 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
+ 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
+ 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
+ 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
+ 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
+ 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
+ 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
+ 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
+ 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
+ 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
+ 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
+ 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
+ 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
+ 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
+ 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
+ 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
+ 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
+ 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
+ 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
+ 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
+ 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
+ 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
+ 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
+ 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
+ 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
+ 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
+ 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
+ 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
+ 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
+ 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
+ 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
+ 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
+ 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
+ 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
+ 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
+ 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
+ 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
+ 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
+ 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+ 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
+ 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+ 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
+ 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
+ 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
+ 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
+ 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
+ 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
+ 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
+ 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
+ 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
+ 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
+ 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
+ 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
+ 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
+ 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
+ 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
+ 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
+ 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
+ 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
+ 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
+ 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
+ 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
+ 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
+ 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
+ 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
+ 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
+ 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
+ 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
+ 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
+ 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
+ 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
+ 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
+ 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
+ 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
+ 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
+ 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
+ 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
+ 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
+ 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
+ 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
+ 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
+ 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
+ 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
+ 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
+ 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
+ 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
+ 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
+ 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
+ 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
+ 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
+ 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
+ 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
+ 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
+ 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
+ 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
+ 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
+ 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
+ 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
+ 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
+ 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
+ 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
+ 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
+ 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
+ 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
+ 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
+ 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
+ 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
+ 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
+ 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
+ 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
+ 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
+ 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
+ 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
+ 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
+ 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
+ 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
+ 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
+ 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
+ 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
+ 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
+ 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
+ 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
+ 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
+ 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
+ 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
+ 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+ 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
+ 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
+ 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
+ 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
+ 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
+ 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
+static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc38C0800_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
+ 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
+ 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
+ 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
+ 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
+ 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
+ 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
+ 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
+ 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
+ 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
+ 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
+ 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+ 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
+ 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
+ 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
+ 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+ 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
+ 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
+ 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
+ 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
+ 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
+ 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
+ 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
+ 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
+ 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+ 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
+ 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
+ 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
+ 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
+ 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
+ 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
+ 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
+ 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
+ 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
+ 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
+ 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
+ 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
+ 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
+ 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
+ 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
+ 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
+ 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
+ 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
+ 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
+ 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
+ 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
+ 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
+ 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
+ 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+ 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
+ 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
+ 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
+ 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
+ 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
+ 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
+ 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
+ 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
+ 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
+ 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
+ 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
+ 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
+ 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
+ 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
+ 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
+ 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
+ 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
+ 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
+ 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
+ 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
+ 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
+ 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
+ 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
+ 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
+ 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
+ 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
+ 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
+ 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
+ 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
+ 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
+ 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
+ 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
+ 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
+ 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
+ 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+ 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
+ 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
+ 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
+ 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
+ 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
+ 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+ 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+ 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
+ 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
+ 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
+ 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
+ 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
+ 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
+ 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
+ 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
+ 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
+ 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
+ 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
+ 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
+ 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
+ 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
+ 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
+ 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
+ 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
+ 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
+ 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
+ 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
+ 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
+ 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
+ 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
+ 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
+ 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
+ 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
+ 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
+ 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
+ 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
+ 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
+ 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
+ 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
+ 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
+ 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
+ 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
+ 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
+ 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
+ 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
+ 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
+ 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
+ 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
+ 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
+ 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
+ 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
+ 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
+ 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
+ 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
+ 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
+ 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
+ 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
+ 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
+ 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
+ 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
+ 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
+ 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
+ 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
+ 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
+ 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
+ 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
+ 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
+ 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
+ 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
+ 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
+ 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
+ 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
+ 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
+ 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
+ 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
+ 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
+ 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
+ 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
+ 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
+ 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
+ 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
+ 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
+ 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
+ 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
+ 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
+ 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
+ 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
+ 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
+ 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
+ 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
+ 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
+ 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
+ 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
+ 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
+ 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
+ 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
+ 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
+ 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
+ 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
+ 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
+ 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
+ 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
+ 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
+ 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
+ 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
+ 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
+ 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
+ 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
+ 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
+ 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
+ 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
+ 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
+ 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
+ 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
+ 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
+ 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
+ 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
+ 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
+ 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
+ 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
+ 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
+ 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
+ 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
+ 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
+ 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
+ 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
+ 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
+ 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
+ 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
+ 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
+ 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
+ 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
+ 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
+ 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
+ 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
+ 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
+ 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
+ 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
+ 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
+ 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
+ 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
+ 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
+ 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
+ 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
+ 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
+ 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
+ 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
+ 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
+ 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
+ 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
+ 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
+ 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
+ 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
+ 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
+ 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
+ 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
+ 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
+ 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
+ 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
+ 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
+ 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
+ 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
+ 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
+ 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
+ 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
+ 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
+ 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
+ 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
+ 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
+ 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
+ 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
+ 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+ 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
+ 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
+ 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+ 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
+ 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
+ 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
+ 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
+ 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+ 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
+ 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+ 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
+ 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+ 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
+ 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
+ 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
+ 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
+ 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
+ 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
+ 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
+ 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
+ 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
+ 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
+ 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
+ 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
+ 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
+ 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
+ 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
+ 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
+ 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
+ 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
+ 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
+ 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
+ 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
+ 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
+ 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
+ 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
+ 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
+ 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
+ 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
+ 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
+ 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
+ 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
+ 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
+ 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
+ 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
+ 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
+ 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
+ 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
+ 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
+ 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
+ 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
+ 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
+ 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
+ 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
+ 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
+ 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
+ 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
+ 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
+ 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
+ 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
+ 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
+ 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
+ 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
+ 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
+ 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
+ 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
+ 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
+ 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+ 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
+ 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+ 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
+ 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
+ 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
+ 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
+ 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
+ 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
+ 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
+ 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
+ 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
+ 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
+ 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
+ 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
+ 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
+ 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
+ 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
+ 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
+ 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
+ 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
+ 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
+ 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
+ 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
+ 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
+ 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
+ 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
+ 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
+ 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
+ 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+ 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+ 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
+ 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
+ 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
+ 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
+ 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
+ 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
+ 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
+ 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
+ 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
+ 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
+ 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
+ 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
+ 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
+ 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
+ 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
+ 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
+ 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
+ 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
+ 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
+ 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
+ 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
+ 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
+ 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
+ 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
+ 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
+ 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
+ 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+ 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
+ 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
+ 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
+ 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
+ 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
+ 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
+ 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
+ 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
+ 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
+ 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
+ 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
+ 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+ 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
+ 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
+ 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
+ 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
+ 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
+ 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
+ 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
+ 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
+ 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
+ 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
+ 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
+ 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
+ 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
+ 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
+ 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
+ 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
+ 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
+ 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
+ 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
+ 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
+ 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
+ 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
+ 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
+ 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
+ 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
+ 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
+ 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
+static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc38C1600_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
+ 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
+ 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
+ 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
+ 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
+ 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
+ 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
+ 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
+ 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
+ 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
+ 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
+ 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
+ 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+ 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
+ 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
+ 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
+ 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
+ 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
+ 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
+ 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
+ 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
+ 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
+ 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
+ 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
+ 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
+ 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
+ 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
+ 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
+ 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
+ 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
+ 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
+ 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
+ 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
+ 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
+ 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
+ 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
+ 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
+ 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
+ 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
+ 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
+ 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
+ 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
+ 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
+ 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
+ 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
+ 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
+ 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
+ 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
+ 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
+ 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
+ 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
+ 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
+ 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
+ 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
+ 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
+ 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
+ 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
+ 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
+ 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
+ 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
+ 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
+ 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
+ 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
+ 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
+ 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+ 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
+ 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
+ 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
+ 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
+ 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
+ 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
+ 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
+ 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
+ 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
+ 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
+ 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
+ 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
+ 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
+ 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
+ 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
+ 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
+ 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
+ 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
+ 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
+ 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
+ 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
+ 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
+ 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
+ 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
+ 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
+ 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
+ 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
+ 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
+ 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
+ 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
+ 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
+ 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
+ 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
+ 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
+ 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
+ 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
+ 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
+ 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
+ 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
+ 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
+ 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
+ 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
+ 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
+ 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
+ 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
+ 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
+ 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
+ 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
+ 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
+ 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
+ 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
+ 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
+ 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
+ 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
+ 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
+ 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
+ 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
+ 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
+ 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
+ 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
+ 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
+ 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
+ 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
+ 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
+ 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
+ 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
+ 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
+ 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
+ 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
+ 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
+ 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
+ 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
+ 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
+ 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
+ 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
+ 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
+ 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
+ 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
+ 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
+ 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
+ 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
+ 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
+ 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
+ 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
+ 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
+ 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
+ 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
+ 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
+ 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
+ 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
+ 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
+ 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
+ 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+ 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
+ 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
+ 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
+ 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
+ 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
+ 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
+ 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
+ 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
+ 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
+ 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
+ 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
+ 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
+ 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
+ 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
+ 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
+ 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
+ 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
+ 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
+ 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
+ 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
+ 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
+ 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
+ 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
+ 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
+ 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
+ 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
+ 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
+ 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
+ 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
+ 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
+ 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
+ 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
+ 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
+ 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
+ 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
+ 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
+ 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
+ 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
+ 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
+ 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
+ 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
+ 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
+ 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
+ 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
+ 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
+ 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
+ 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
+ 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
+ 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
+ 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
+ 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
+ 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
+ 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
+ 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
+ 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
+ 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
+ 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
+ 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
+ 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
+ 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
+ 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
+ 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
+ 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
+ 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
+ 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
+ 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
+ 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
+ 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
+ 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
+ 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
+ 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
+ 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
+ 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
+ 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
+ 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
+ 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
+ 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
+ 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
+ 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
+ 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
+ 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
+ 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
+ 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
+ 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
+ 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
+ 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
+ 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
+ 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
+ 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
+ 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
+ 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
+ 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
+ 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
+ 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
+ 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
+ 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
+ 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
+ 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
+ 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
+ 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
+ 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
+ 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
+ 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
+ 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
+ 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
+ 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
+ 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
+ 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
+ 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
+ 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
+ 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
+ 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
+ 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
+ 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
+ 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
+ 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
+ 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
+ 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
+ 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
+ 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
+ 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
+ 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
+ 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
+ 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
+ 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
+ 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
+ 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
+ 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
+ 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
+ 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
+ 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
+ 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
+ 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
+ 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
+ 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
+ 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
+ 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
+ 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
+ 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
+ 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
+ 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
+ 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
+ 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
+ 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
+ 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
+ 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
+ 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
+ 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+ 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
+ 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
+ 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
+ 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
+ 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
+ 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
+ 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
+ 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
+ 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
+ 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
+ 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
+ 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
+ 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
+ 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
+ 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
+ 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
+ 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
+ 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+ 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
+ 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
+ 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+ 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
+ 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
+ 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
+ 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
+ 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
+ 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
+ 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
+ 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
+ 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
+ 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
+ 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
+ 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
+ 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
+ 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
+ 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
+ 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
+ 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
+ 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
+ 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
+ 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
+ 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
+ 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
+ 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
+ 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
+ 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
+ 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
+ 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
+ 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
+ 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
+ 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
+ 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
+ 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
+ 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
+ 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
+ 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
+ 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
+ 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
+ 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
+ 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
+ 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
+ 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
+ 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
+ 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
+ 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
+ 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
+ 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
+ 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
+ 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
+ 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
+ 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
+ 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
+ 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
+ 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
+ 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
+ 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
+ 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
+ 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
+ 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
+ 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
+ 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
+ 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
+ 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
+ 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
+ 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
+ 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
+ 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
+ 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
+ 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
+ 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
+ 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
+ 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
+ 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
+ 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
+ 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
+ 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
+ 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
+ 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
+ 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
+ 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
+ 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
+ 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
+ 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
+ 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
+ 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
+ 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
+ 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
+ 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
+ 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
+ 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
+ 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
+ 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
+ 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+ 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+ 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
+ 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
+ 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
+ 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
+ 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
+ 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
+ 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
+ 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
+ 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
+ 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
+ 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
+ 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
+ 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
+ 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
+ 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
+ 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
+ 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
+ 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
+ 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
+ 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
+ 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
+ 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
+ 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
+ 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
+ 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
+ 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
+ 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
+ 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
+ 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
+ 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
+ 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
+ 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
+ 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
+ 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
+ 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
+ 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
+ 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
+ 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
+ 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
+ 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
+ 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
+ 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
+ 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
+ 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
+ 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
+ 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
+ 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
+ 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
+ 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
+ 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
+ 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
+ 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
+ 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
+ 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
+ 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
+ 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
+ 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
+ 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
+ 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
+ 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
+ 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
+ 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
+ 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
+ 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
+ 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
+ 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
+ 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
+ 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
+ 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
+ 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
+ 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
+ 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
+ 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
+ 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
+ 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
+ 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
+ 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
+ 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
+ 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
+static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
+
+static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
+{
+ PortAddr iop_base;
+ int i;
+ ushort lram_addr;
+
+ iop_base = asc_dvc->iop_base;
+ AscPutRiscVarFreeQHead(iop_base, 1);
+ AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscPutVarFreeQHead(iop_base, 1);
+ AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 1));
+ AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 2));
+ AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
+ asc_dvc->max_total_qng);
+ AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+ AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+ AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+ AscPutQDoneInProgress(iop_base, 0);
+ lram_addr = ASC_QADR_BEG;
+ for (i = 0; i < 32; i++, lram_addr += 2) {
+ AscWriteLramWord(iop_base, lram_addr, 0);
}
-#ifdef CONFIG_ISA
- if ((bus_type & ASC_IS_EISA) != 0) {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- cfg_lsw &= 0x000F;
- bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
- (cfg_lsw * ASC_BIOS_BANK_SIZE));
- return (bios_addr);
- } /* if */
-#endif /* CONFIG_ISA */
+}
- cfg_lsw = AscGetChipCfgLsw(iop_base);
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
+{
+ int i;
+ ushort warn_code;
+ PortAddr iop_base;
+ ASC_PADDR phy_addr;
+ ASC_DCNT phy_size;
+ struct asc_board *board = asc_dvc_to_board(asc_dvc);
- /*
- * ISA PnP uses the top bit as the 32K BIOS flag
- */
- if (bus_type == ASC_IS_ISAPNP) {
- cfg_lsw &= 0x7FFF;
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ AscPutMCodeInitSDTRAtID(iop_base, i,
+ asc_dvc->cfg->sdtr_period_offset[i]);
}
- /* if */
- bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
- ASC_BIOS_MIN_ADDR);
- return (bios_addr);
+
+ AscInitQLinkVar(asc_dvc);
+ AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+ ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+
+ /* Ensure overrun buffer is aligned on an 8 byte boundary. */
+ BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
+ asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+ (uchar *)&phy_addr, 1);
+ phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+ (uchar *)&phy_size, 1);
+
+ asc_dvc->cfg->mcode_date =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
+ asc_dvc->cfg->mcode_version =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return warn_code;
+ }
+ if (AscStartChip(iop_base) != 1) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return warn_code;
+ }
+
+ return warn_code;
}
-/*
- * --- Functions Required by the Adv Library
- */
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
+{
+ ushort warn_code;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+ !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+ AscResetChipAndScsiBus(asc_dvc);
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+ }
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+ if (asc_dvc->err_code != 0)
+ return UW_ERR;
+ if (!AscFindSignature(asc_dvc->iop_base)) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return warn_code;
+ }
+ AscDisableInterrupt(iop_base);
+ warn_code |= AscInitLram(asc_dvc);
+ if (asc_dvc->err_code != 0)
+ return UW_ERR;
+ ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)_asc_mcode_chksum);
+ if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+ _asc_mcode_size) != _asc_mcode_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return warn_code;
+ }
+ warn_code |= AscInitMicroCodeVar(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+ AscEnableInterrupt(iop_base);
+ return warn_code;
+}
/*
- * DvcGetPhyAddr()
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ * The microcode is stored compressed in the following format:
*
- * Return the physical address of 'vaddr' and set '*lenp' to the
- * number of physically contiguous bytes that follow 'vaddr'.
- * 'flag' indicates the type of structure whose physical address
- * is being translated.
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
*
- * Note: Because Linux currently doesn't page the kernel and all
- * kernel buffers are physically contiguous, leave '*lenp' unchanged.
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ *
+ * Returns 0 or an error if the checksum doesn't match
*/
-ADV_PADDR
-DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
- uchar *vaddr, ADV_SDCNT *lenp, int flag)
+static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
+ int memsize, int chksum)
{
- ADV_PADDR paddr;
+ int i, j, end, len = 0;
+ ADV_DCNT sum;
+
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- paddr = virt_to_bus(vaddr);
+ for (i = 253 * 2; i < size; i++) {
+ if (buf[i] == 0xff) {
+ unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
+ for (j = 0; j < buf[i + 1]; j++) {
+ AdvWriteWordAutoIncLram(iop_base, word);
+ len += 2;
+ }
+ i += 3;
+ } else if (buf[i] == 0xfe) {
+ unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
+ AdvWriteWordAutoIncLram(iop_base, word);
+ i += 2;
+ len += 2;
+ } else {
+ unsigned char off = buf[i] * 2;
+ unsigned short word = (buf[off + 1] << 8) | buf[off];
+ AdvWriteWordAutoIncLram(iop_base, word);
+ len += 2;
+ }
+ }
- ASC_DBG4(4,
- "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
- (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
- (ulong)paddr);
+ end = len;
- return paddr;
+ while (len < memsize) {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ len += 2;
+ }
+
+ /* Verify the microcode checksum. */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ for (len = 0; len < end; len += 2) {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
+
+ if (sum != chksum)
+ return ASC_IERR_MCODE_CHKSUM;
+
+ return 0;
}
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
+static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
{
-#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
-#else /* CONFIG_PCI */
- return 0;
-#endif /* CONFIG_PCI */
+ ADV_CARR_T *carrp;
+ ADV_SDCNT buf_size;
+ ADV_PADDR carr_paddr;
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == asc_dvc->carrier_buf) {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
+
+ do {
+ /* Get physical address of the carrier 'carrp'. */
+ carr_paddr = cpu_to_le32(virt_to_bus(carrp));
+
+ buf_size -= sizeof(ADV_CARR_T);
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = carrp;
+
+ carrp++;
+ } while (buf_size > 0);
}
/*
- * Write a PCI configuration byte.
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
+ *
+ * Return Values:
+ * ADV_TRUE - command completed successfully
+ * ADV_FALSE - command failed
+ * ADV_ERROR - command timed out
*/
-static void __init
-DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
+static int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+ ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
{
-#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#else /* CONFIG_PCI */
- return;
-#endif /* CONFIG_PCI */
+ int result;
+ ADV_DCNT i, j;
+ AdvPortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ * The non-zero result is one of the IDLE_CMD_STATUS_* values
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
+
+ /*
+ * Write the idle command value after the idle command parameter
+ * has been written to avoid a race condition. If the order is not
+ * followed, the microcode may process the idle command before the
+ * parameters have been written to LRAM.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+ cpu_to_le32(idle_cmd_parameter));
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+
+ /*
+ * Tickle the RISC to tell it to process the idle command.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_b' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ }
+
+ /* Wait for up to 100 millisecond for the idle command to timeout. */
+ for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
+ /* Poll once each microsecond for command completion. */
+ for (j = 0; j < SCSI_US_PER_MSEC; j++) {
+ AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
+ result);
+ if (result != 0)
+ return result;
+ udelay(1);
+ }
+ }
+
+ BUG(); /* The idle command should never timeout. */
+ return ADV_ERROR;
}
/*
- * --- Tracing and Debugging Functions
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ * ADV_FALSE(0) - Microcode command failed.
+ * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ * may be hung which requires driver recovery.
*/
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
+{
+ int status;
+
+ /*
+ * Send the SCSI Bus Reset idle start idle command which asserts
+ * the SCSI Bus Reset signal.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
+
+ /*
+ * Delay for the specified SCSI Bus Reset hold time.
+ *
+ * The hold time delay is done on the host because the RISC has no
+ * microsecond accurate timer.
+ */
+ udelay(ASC_SCSI_RESET_HOLD_TIME_US);
+
+ /*
+ * Send the SCSI Bus Reset end idle command which de-asserts
+ * the SCSI Bus Reset signal and purges any pending requests.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
+
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+
+ return status;
+}
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
/*
- * asc_prt_board_stats()
+ * Initialize the ASC-3550.
*
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
*/
-static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- asc_board_t *boardp;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int i;
+ ushort scsi_cfg1;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able = 0, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
- leftlen = cplen;
- totlen = len = 0;
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ return ADV_ERROR;
- boardp = ASC_BOARDP(shost);
- s = &boardp->asc_stats;
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- len = asc_prt_line(cp, leftlen,
- "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- len = asc_prt_line(cp, leftlen,
- " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
- s->queuecommand, s->reset, s->biosparam,
- s->interrupt);
- ASC_PRT_NEXT();
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- len = asc_prt_line(cp, leftlen,
- " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
- s->callback, s->done, s->build_error,
- s->adv_build_noreq, s->adv_build_nosg);
- ASC_PRT_NEXT();
+ /*
+ * Save current per TID negotiated values.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
+ ushort bios_version, major, minor;
- len = asc_prt_line(cp, leftlen,
- " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
- s->exe_noerror, s->exe_busy, s->exe_error,
- s->exe_unknown);
- ASC_PRT_NEXT();
+ bios_version =
+ bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
+ major = (bios_version >> 12) & 0xF;
+ minor = (bios_version >> 8) & 0xF;
+ if (major < 3 || (major == 3 && minor == 1)) {
+ /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+ AdvReadWordLram(iop_base, 0x120, wdtr_able);
+ } else {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ }
+ }
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
+ _adv_asc3550_size, ADV_3550_MEMSIZE,
+ _adv_asc3550_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
/*
- * Display data transfer statistics.
+ * Restore the RISC memory BIOS region.
*/
- if (s->cont_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
- ASC_PRT_NEXT();
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
- s->cont_xfer / 2,
- ASC_TENTHS(s->cont_xfer, 2));
- ASC_PRT_NEXT();
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- /* Contiguous transfer average size */
- len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
- (s->cont_xfer / 2) / s->cont_cnt,
- ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Read and save microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC3550.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
- if (s->sg_cnt > 0) {
+ /*
+ * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+ * threshold of 128 bytes. This register is only accessible to the host.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
- len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
- s->sg_cnt, s->sg_elem);
- ASC_PRT_NEXT();
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
- s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
- ASC_PRT_NEXT();
+ /*
+ * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+ * bitmask. These values determine the maximum SDTR speed negotiated
+ * with a device.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ *
+ * 4-bit speed SDTR speed name
+ * =========== ===============
+ * 0000b (0x0) SDTR disabled
+ * 0001b (0x1) 5 Mhz
+ * 0010b (0x2) 10 Mhz
+ * 0011b (0x3) 20 Mhz (Ultra)
+ * 0100b (0x4) 40 Mhz (LVD/Ultra2)
+ * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
+ * 0110b (0x6) Undefined
+ * .
+ * 1111b (0xF) Undefined
+ */
+ word = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
+ /* Set Ultra speed for TID 'tid'. */
+ word |= (0x3 << (4 * (tid % 4)));
+ } else {
+ /* Set Fast speed for TID 'tid'. */
+ word |= (0x2 << (4 * (tid % 4)));
+ }
+ if (tid == 3) { /* Check if done with sdtr_speed1. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+ word = 0;
+ } else if (tid == 7) { /* Check if done with sdtr_speed2. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+ word = 0;
+ } else if (tid == 11) { /* Check if done with sdtr_speed3. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+ word = 0;
+ } else if (tid == 15) { /* Check if done with sdtr_speed4. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+ /* End of loop. */
+ }
+ }
- /* Scatter gather transfer statistics */
- len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
- s->sg_elem / s->sg_cnt,
- ASC_TENTHS(s->sg_elem, s->sg_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Set microcode operating variable for the disconnect per TID bitmask.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
- len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
- (s->sg_xfer / 2) / s->sg_elem,
- ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
- ASC_PRT_NEXT();
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
- (s->sg_xfer / 2) / s->sg_cnt,
- ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If all three connectors are in use, return an error.
+ */
+ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+ (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+ asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+ return ADV_ERROR;
}
/*
- * Display request queuing statistics.
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
*/
- len = asc_prt_line(cp, leftlen,
- " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
- HZ);
- ASC_PRT_NEXT();
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- return totlen;
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
+ asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If automatic termination control is enabled, then set the
+ * termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting
+ * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+ * is ready to be 'ored' into SCSI_CFG1.
+ */
+ if (asc_dvc->cfg->termination == 0) {
+ /*
+ * The software always controls termination by setting TERM_CTL_SEL.
+ * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+ */
+ asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+ switch (scsi_cfg1 & CABLE_DETECT) {
+ /* TERM_CTL_H: on, TERM_CTL_L: on */
+ case 0x3:
+ case 0x7:
+ case 0xB:
+ case 0xD:
+ case 0xE:
+ case 0xF:
+ asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+ break;
+
+ /* TERM_CTL_H: on, TERM_CTL_L: off */
+ case 0x1:
+ case 0x5:
+ case 0x9:
+ case 0xA:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_CTL_H;
+ break;
+
+ /* TERM_CTL_H: off, TERM_CTL_L: off */
+ case 0x2:
+ case 0x6:
+ break;
+ }
+ }
+
+ /*
+ * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+ */
+ scsi_cfg1 &= ~TERM_CTL;
+
+ /*
+ * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+ * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if TERM_POL is set.
+ */
+ scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set filter value and possibly modified termination control
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+ FLTR_DISABLE | scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-3550 has 8KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_8KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ AdvBuildCarrierFreelist(asc_dvc);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
}
/*
- * asc_prt_target_stats()
+ * Initialize the ASC-38C0800.
*
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * This is separated from asc_prt_board_stats because a full set
- * of targets will overflow ASC_PRTBUF_SIZE.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
*
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * Needed after initialization for error recovery.
*/
-static int
-asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- ushort chip_scsi_id;
- asc_board_t *boardp;
- asc_queue_t *active;
- asc_queue_t *waiting;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
- leftlen = cplen;
- totlen = len = 0;
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ return ADV_ERROR;
- boardp = ASC_BOARDP(shost);
- s = &boardp->asc_stats;
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- active = &ASC_BOARDP(shost)->active;
- waiting = &ASC_BOARDP(shost)->waiting;
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
}
- if ((chip_scsi_id == tgt_id) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
- return 0;
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
- do {
- if (active->q_tot_cnt[tgt_id] > 0
- || waiting->q_tot_cnt[tgt_id] > 0) {
- len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
- ASC_PRT_NEXT();
+ /*
+ * RAM BIST (RAM Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
- len = asc_prt_line(cp, leftlen,
- " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
- active->q_cur_cnt[tgt_id],
- active->q_max_cnt[tgt_id],
- active->q_tot_cnt[tgt_id],
- active->q_min_tim[tgt_id],
- active->q_max_tim[tgt_id],
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : (active->
- q_tot_tim[tgt_id] /
- active->
- q_tot_cnt[tgt_id]),
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : ASC_TENTHS(active->
- q_tot_tim
- [tgt_id],
- active->
- q_tot_cnt
- [tgt_id]));
- ASC_PRT_NEXT();
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
- len = asc_prt_line(cp, leftlen,
- " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
- waiting->q_cur_cnt[tgt_id],
- waiting->q_max_cnt[tgt_id],
- waiting->q_tot_cnt[tgt_id],
- waiting->q_min_tim[tgt_id],
- waiting->q_max_tim[tgt_id],
- (waiting->q_tot_cnt[tgt_id] ==
- 0) ? 0 : (waiting->
- q_tot_tim[tgt_id] /
- waiting->
- q_tot_cnt[tgt_id]),
- (waiting->q_tot_cnt[tgt_id] ==
- 0) ? 0 : ASC_TENTHS(waiting->
- q_tot_tim
- [tgt_id],
- waiting->
- q_tot_cnt
- [tgt_id]));
- ASC_PRT_NEXT();
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
}
- } while (0);
+ }
- return totlen;
-}
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before checking status. */
-#ifdef ADVANSYS_DEBUG
-/*
- * asc_prt_scsi_host()
- */
-static void asc_prt_scsi_host(struct Scsi_Host *s)
-{
- asc_board_t *boardp;
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- boardp = ASC_BOARDP(s);
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
- printk(" host_busy %u, host_no %d, last_reset %d,\n",
- s->host_busy, s->host_no, (unsigned)s->last_reset);
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
+ _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
+ _adv_asc38C0800_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
- printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
- (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- printk(" dma_channel %d, this_id %d, can_queue %d,\n",
- s->dma_channel, s->this_id, s->can_queue);
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
- if (ASC_NARROW_BOARD(boardp)) {
- asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
- asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
- } else {
- asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
- asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+ /*
+ * Set the chip type to indicate the ASC38C0800.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
-}
-/*
- * asc_prt_scsi_cmnd()
- */
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
-{
- printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
+ /*
+ * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+ * bits for the default FIFO threshold.
+ *
+ * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+ *
+ * For DMA Errata #4 set the BC_THRESH_ENB bit.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
+ READ_CMD_MRM);
- printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
- (ulong)s->device->host, (ulong)s->device, s->device->id,
- s->device->lun, s->device->channel);
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
- printk("sc_data_direction %u, resid %d\n",
- s->sc_data_direction, s->resid);
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
- printk(" serial_number 0x%x, retries %d, allowed %d\n",
- (unsigned)s->serial_number, s->retries, s->allowed);
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- printk(" timeout_per_command %d\n", s->timeout_per_command);
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- printk
- (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
- (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
- s->result);
+ /*
+ * All kind of combinations of devices attached to one of four
+ * connectors are acceptable except HVD device attached. For example,
+ * LVD device can be attached to SE connector while SE device attached
+ * to LVD connector. If LVD device attached to SE connector, it only
+ * runs up to Ultra speed.
+ *
+ * If an HVD device is attached to one of LVD connectors, return an
+ * error. However, there is no way to detect HVD device attached to
+ * SE connectors.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
-}
+ /*
+ * If either SE or LVD automatic termination control is enabled, then
+ * set the termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting then
+ * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
+ * to be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
-/*
- * asc_prt_asc_dvc_var()
- */
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
-{
- printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
+ /* TERM_SE_HI: on, TERM_SE_LO: off */
+ case 0x0:
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ break;
+ }
+ }
- printk
- (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
- h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+ if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
+ /* LVD automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_LVD) {
+ /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+ case 0x4:
+ case 0x8:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_LVD;
+ break;
- printk
- (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
- h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
- (unsigned)h->init_sdtr);
+ /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+ case 0x0:
+ break;
+ }
+ }
- printk
- (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
- (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
- (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
+ /*
+ * Clear any set TERM_SE and TERM_LVD bits.
+ */
+ scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
- printk
- (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
- (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
- (unsigned)h->scsi_reset_wait);
+ /*
+ * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
- printk
- (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
- (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
- (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
+ /*
+ * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
+ * bits and set possibly modified termination control bits in the
+ * Microcode SCSI_CFG1 Register Value.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
- printk
- (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
- (unsigned)h->last_q_shortage, (unsigned)h->init_state,
- (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control and reset DIS_TERM_DRV
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
- printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
-}
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C0800 has 16KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
-/*
- * asc_prt_asc_dvc_cfg()
- */
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
-{
- printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
- printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
- h->can_tagged_qng, h->cmd_qng_enabled);
- printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
- h->disc_enable, h->sdtr_enable);
+ AdvBuildCarrierFreelist(asc_dvc);
- printk
- (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
- h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
- h->chip_version);
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
- printk
- (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
- to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
- h->mcode_date);
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
- printk(" mcode_version %d, overrun_buf 0x%lx\n",
- h->mcode_version, (ulong)h->overrun_buf);
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ * carr_pa is LE, must be native before write
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ *
+ * carr_pa is LE, must be native before write *
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
}
/*
- * asc_prt_asc_scsi_q()
+ * Initialize the ASC-38C1600.
+ *
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
*/
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
{
- ASC_SG_HEAD *sgp;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ long word;
int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
+ uchar max_cmd[ASC_MAX_TID + 1];
- printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0) {
+ return ADV_ERROR;
+ }
- printk
- (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
- q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
- q->q2.tag_code);
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- printk
- (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong)le32_to_cpu(q->q1.data_addr),
- (ulong)le32_to_cpu(q->q1.data_cnt),
- (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
- (ulong)q->cdbptr, q->q2.cdb_len,
- (ulong)q->sg_head, q->q1.sg_queue_cnt);
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- if (q->sg_head) {
- sgp = q->sg_head;
- printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
- printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
- sgp->queue_cnt);
- for (i = 0; i < sgp->entry_cnt; i++) {
- printk(" [%u]: addr 0x%lx, bytes %lu\n",
- i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
- (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ /*
+ * RAM BIST (Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
+
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
}
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
}
-}
-/*
- * asc_prt_asc_qdone_info()
- */
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
-{
- printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
- printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
- (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
- q->d2.tag_code);
- printk
- (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
- q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
-}
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before checking status. */
-/*
- * asc_prt_adv_dvc_var()
- *
- * Display an ADV_DVC_VAR structure.
- */
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
-{
- printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
- (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
- (ulong)h->isr_callback, (unsigned)h->sdtr_able,
- (unsigned)h->wdtr_able);
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
+ _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
+ _adv_asc38C1600_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
- printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
- (unsigned)h->start_motor,
- (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
- (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
- (ulong)h->carr_freelist);
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
- (ulong)h->icq_sp, (ulong)h->irq_sp);
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
- printk(" no_scam 0x%x, tagqng_able 0x%x\n",
- (unsigned)h->no_scam, (unsigned)h->tagqng_able);
+ /*
+ * Set the chip type to indicate the ASC38C1600.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
- printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
- (unsigned)h->chip_scsi_id, (ulong)h->cfg);
-}
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
-/*
- * asc_prt_adv_dvc_cfg()
- *
- * Display an ADV_DVC_CFG structure.
- */
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
-{
- printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- printk(" disc_enable 0x%x, termination 0x%x\n",
- h->disc_enable, h->termination);
+ /*
+ * If the BIOS control flag AIPP (Asynchronous Information
+ * Phase Protection) disable bit is not set, then set the firmware
+ * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+ * AIPP checking and encoding.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_ENABLE_AIPP;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- printk(" chip_version 0x%x, mcode_date 0x%x\n",
- h->chip_version, h->mcode_date);
+ /*
+ * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+ * and START_CTL_TH [3:2].
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
- printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
- h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
- h->control_flag, h->pci_slot_info);
-}
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-/*
- * asc_prt_adv_scsi_req_q()
- *
- * Display an ADV_SCSI_REQ_Q structure.
- */
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
-{
- int sg_blk_cnt;
- struct asc_sg_block *sg_ptr;
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
+ /*
+ * Calculate SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ *
+ * Each ASC-38C1600 function has only two cable detect bits.
+ * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
- q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
+ /*
+ * If the cable is reversed all of the SCSI_CTRL register signals
+ * will be set. Check for and return an error if this condition is
+ * found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
- q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
+ /*
+ * Each ASC-38C1600 function has two connectors. Only an HVD device
+ * can not be connected to either connector. An LVD device or SE device
+ * may be connected to either connecor. If an SE device is connected,
+ * then at most Ultra speed (20 Mhz) can be used on both connectors.
+ *
+ * If an HVD device is attached, return an error.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong)le32_to_cpu(q->data_cnt),
- (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
+ /*
+ * Each function in the ASC-38C1600 uses only the SE cable detect and
+ * termination because there are two connectors for each function. Each
+ * function may use either LVD or SE mode. Corresponding the SE automatic
+ * termination control EEPROM bits are used for each function. Each
+ * function has its own EEPROM. If SE automatic control is enabled for
+ * the function, then set the termination value based on a table listed
+ * in a_condor.h.
+ *
+ * If manual termination is specified in the EEPROM for the function,
+ * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+ * ready to be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
- printk
- (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
- q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+ case 0x0:
+ if (PCI_FUNC(pdev->devfn) == 0) {
+ /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+ } else {
+ /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ }
+ break;
+ }
+ }
- printk(" sg_working_ix 0x%x, target_cmd %u\n",
- q->sg_working_ix, q->target_cmd);
+ /*
+ * Clear any set TERM_SE bits.
+ */
+ scsi_cfg1 &= ~TERM_SE;
- printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
- (ulong)le32_to_cpu(q->scsiq_rptr),
- (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
+ /*
+ * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
- /* Display the request's ADV_SG_BLOCK structures. */
- if (q->sg_list_ptr != NULL) {
- sg_blk_cnt = 0;
- while (1) {
+ /*
+ * Clear Big Endian and Terminator Polarity bits and set possibly
+ * modified termination control bits in the Microcode SCSI_CFG1
+ * Register Value.
+ *
+ * Big Endian bit is not used even on big endian machines.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control bits in the Microcode
+ * SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C1600 has 32KB internal memory.
+ *
+ * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+ * out a special 16K Adv Library and Microcode version. After the issue
+ * resolved, we should turn back to the 32K support. Both a_condor.h and
+ * mcode.sas files also need to be updated.
+ *
+ * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ * BIOS_EN | RAM_SZ_32KB);
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ AdvBuildCarrierFreelist(asc_dvc);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value. Initialize the
+ * COMMA register to the same value otherwise the RISC will
+ * prematurely detect a command is available.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * per TID microcode operating variables.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
/*
- * 'sg_ptr' is a physical address. Convert it to a virtual
- * address by indexing 'sg_blk_cnt' into the virtual address
- * array 'sg_list_ptr'.
- *
- * XXX - Assumes all SG physical blocks are virtually contiguous.
+ * Restore per TID negotiated values.
*/
- sg_ptr =
- &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
- asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
- if (sg_ptr->sg_ptr == 0) {
- break;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
}
- sg_blk_cnt++;
}
}
+
+ return warn_code;
}
/*
- * asc_prt_adv_sgblock()
+ * Reset chip and SCSI Bus.
*
- * Display an ADV_SG_BLOCK structure.
+ * Return Value:
+ * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
+ * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
*/
-static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
{
- int i;
+ int status;
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ ushort ppr_able = 0;
+ uchar tid, max_cmd[ADV_MAX_TID + 1];
+ AdvPortAddr iop_base;
+ ushort bios_sig;
- printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
- (ulong)b, sgblockno);
- printk(" sg_cnt %u, sg_ptr 0x%lx\n",
- b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
- ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
- if (b->sg_ptr != 0) {
- ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
- for (i = 0; i < b->sg_cnt; i++) {
- printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
- i, (ulong)b->sg_list[i].sg_addr,
- (ulong)b->sg_list[i].sg_count);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
-}
-/*
- * asc_prt_hex()
- *
- * Print hexadecimal output in 4 byte groupings 32 bytes
- * or 8 double-words per line.
- */
-static void asc_prt_hex(char *f, uchar *s, int l)
-{
- int i;
- int j;
- int k;
- int m;
-
- printk("%s: (%d bytes)\n", f, l);
+ /*
+ * Force the AdvInitAsc3550/38C0800Driver() function to
+ * perform a SCSI Bus Reset by clearing the BIOS signature word.
+ * The initialization functions assumes a SCSI Bus Reset is not
+ * needed if the BIOS signature word is present.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
- for (i = 0; i < l; i += 32) {
+ /*
+ * Stop chip and reset it.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+ mdelay(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
- /* Display a maximum of 8 double-words per line. */
- if ((k = (l - i) / 4) >= 8) {
- k = 8;
- m = 0;
- } else {
- m = (l - i) % 4;
- }
+ /*
+ * Reset Adv Library error code, if any, and try
+ * re-initializing the chip.
+ */
+ asc_dvc->err_code = 0;
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ status = AdvInitAsc38C1600Driver(asc_dvc);
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ status = AdvInitAsc38C0800Driver(asc_dvc);
+ } else {
+ status = AdvInitAsc3550Driver(asc_dvc);
+ }
- for (j = 0; j < k; j++) {
- printk(" %2.2X%2.2X%2.2X%2.2X",
- (unsigned)s[i + (j * 4)],
- (unsigned)s[i + (j * 4) + 1],
- (unsigned)s[i + (j * 4) + 2],
- (unsigned)s[i + (j * 4) + 3]);
- }
+ /* Translate initialization return value to status value. */
+ if (status == 0) {
+ status = ADV_TRUE;
+ } else {
+ status = ADV_FALSE;
+ }
- switch (m) {
- case 0:
- default:
- break;
- case 1:
- printk(" %2.2X", (unsigned)s[i + (j * 4)]);
- break;
- case 2:
- printk(" %2.2X%2.2X",
- (unsigned)s[i + (j * 4)],
- (unsigned)s[i + (j * 4) + 1]);
- break;
- case 3:
- printk(" %2.2X%2.2X%2.2X",
- (unsigned)s[i + (j * 4) + 1],
- (unsigned)s[i + (j * 4) + 2],
- (unsigned)s[i + (j * 4) + 3]);
- break;
- }
+ /*
+ * Restore the BIOS signature word.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
- printk("\n");
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
+
+ return status;
}
-#endif /* ADVANSYS_DEBUG */
/*
- * --- Asc Library Functions
+ * adv_async_callback() - Adv Library asynchronous event callback function.
*/
-
-static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
+static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
{
- PortAddr eisa_cfg_iop;
+ switch (code) {
+ case ADV_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+ break;
- eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) (ASC_EISA_CFG_IOP_MASK);
- return (inpw(eisa_cfg_iop));
-}
+ case ADV_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the SCSI Bus and
+ * possibly the chip if it is unresponsive. Log the error
+ * with a unique code.
+ */
+ ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n");
+ AdvResetChipAndSB(adv_dvc_varp);
+ break;
-static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
-{
- ushort cfg_lsw;
+ case ADV_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n");
+ break;
- if (AscGetChipScsiID(iop_base) == new_host_id) {
- return (new_host_id);
+ default:
+ ASC_DBG(0, "unknown code 0x%x\n", code);
+ break;
}
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- cfg_lsw &= 0xF8FF;
- cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipScsiID(iop_base));
}
-static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
+/*
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ *
+ * Callback function for the Wide SCSI Adv Library.
+ */
+static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
{
- uchar sc;
+ struct asc_board *boardp;
+ adv_req_t *reqp;
+ adv_sgblk_t *sgblkp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+ ADV_DCNT resid_cnt;
- AscSetBank(iop_base, 1);
- sc = inp(iop_base + IOP_REG_SC);
- AscSetBank(iop_base, 0);
- return (sc);
-}
+ ASC_DBG(1, "adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+ (ulong)adv_dvc_varp, (ulong)scsiqp);
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
-static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
-{
- if ((bus_type & ASC_IS_EISA) != 0) {
- PortAddr eisa_iop;
- uchar revision;
- eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) ASC_EISA_REV_IOP_MASK;
- revision = inp(eisa_iop);
- return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+ /*
+ * Get the adv_req_t structure for the command that has been
+ * completed. The adv_req_t structure actually contains the
+ * completed ADV_SCSI_REQ_Q structure.
+ */
+ reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+ ASC_DBG(1, "reqp 0x%lx\n", (ulong)reqp);
+ if (reqp == NULL) {
+ ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+ return;
}
- return (AscGetChipVerNo(iop_base));
-}
-static ushort __init AscGetChipBusType(PortAddr iop_base)
-{
- ushort chip_ver;
-
- chip_ver = AscGetChipVerNo(iop_base);
- if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
- && (chip_ver <= ASC_CHIP_MAX_VER_VL)
- ) {
- if (((iop_base & 0x0C30) == 0x0C30)
- || ((iop_base & 0x0C50) == 0x0C50)
- ) {
- return (ASC_IS_EISA);
- }
- return (ASC_IS_VL);
+ /*
+ * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+ * command that has been completed.
+ *
+ * Note: The adv_req_t request structure and adv_sgblk_t structure,
+ * if any, are dropped, because a board structure pointer can not be
+ * determined.
+ */
+ scp = reqp->cmndp;
+ ASC_DBG(1, "scp 0x%p\n", scp);
+ if (scp == NULL) {
+ ASC_PRINT
+ ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+ return;
}
- if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
- (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
- if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
- return (ASC_IS_ISAPNP);
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ shost = scp->device->host;
+ ASC_STATS(shost, callback);
+ ASC_DBG(1, "shost 0x%p\n", shost);
+
+ boardp = shost_priv(shost);
+ BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var);
+
+ /*
+ * 'done_status' contains the command's ending status.
+ */
+ switch (scsiqp->done_status) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "QD_NO_ERROR\n");
+ scp->result = 0;
+
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * then return the number of underrun bytes.
+ */
+ resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+ if (scsi_bufflen(scp) != 0 && resid_cnt != 0 &&
+ resid_cnt <= scsi_bufflen(scp)) {
+ ASC_DBG(1, "underrun condition %lu bytes\n",
+ (ulong)resid_cnt);
+ scsi_set_resid(scp, resid_cnt);
}
- return (ASC_IS_ISA);
- } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
- (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
- return (ASC_IS_PCI);
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "QD_WITH_ERROR\n");
+ switch (scsiqp->host_status) {
+ case QHSTA_NO_ERROR:
+ if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by
+ * target drivers defined in scsi.h shifts the
+ * status byte returned by host drivers right
+ * by 1 bit. This is why target drivers also
+ * use right shifted status byte definitions.
+ * For instance target drivers use
+ * CHECK_CONDITION, defined to 0x1, instead of
+ * the SCSI defined check condition value of
+ * 0x2. Host drivers are supposed to return
+ * the status byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(scsiqp->scsi_status);
+ } else {
+ scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ }
+ break;
+
+ default:
+ /* Some other QHSTA error occurred. */
+ ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+
+ default:
+ ASC_DBG(1, "done_status 0x%x\n", scsiqp->done_status);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
}
- return (0);
-}
-static ASC_DCNT
-AscLoadMicroCode(PortAddr iop_base,
- ushort s_addr, uchar *mcode_buf, ushort mcode_size)
-{
- ASC_DCNT chksum;
- ushort mcode_word_size;
- ushort mcode_chksum;
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ scsiqp->done_status == QD_NO_ERROR &&
+ scsiqp->host_status == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
- /* Write the microcode buffer starting at LRAM address 0. */
- mcode_word_size = (ushort)(mcode_size >> 1);
- AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
- AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+ asc_scsi_done(scp);
- chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
- ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
- mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
- (ushort)ASC_CODE_SEC_BEG,
- (ushort)((mcode_size -
- s_addr - (ushort)
- ASC_CODE_SEC_BEG) /
- 2));
- ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
- (ulong)mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
- return (chksum);
+ /*
+ * Free all 'adv_sgblk_t' structures allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
+ }
+
+ /*
+ * Free the adv_req_t structure used with the command by adding
+ * it back to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ ASC_DBG(1, "done\n");
}
-static int AscFindSignature(PortAddr iop_base)
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ * This function is called by a driver's interrupt service routine.
+ * The function disables and re-enables interrupts.
+ *
+ * When a microcode idle command is completed, the ADV_DVC_VAR
+ * 'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ * Note: AdvISR() can be called when interrupts are disabled or even
+ * when there is no hardware interrupt condition present. It will
+ * always check for completed idle commands and microcode requests.
+ * This is an important feature that shouldn't be changed because it
+ * allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ * ADV_TRUE(1) - interrupt was pending
+ * ADV_FALSE(0) - no interrupt was pending
+ */
+static int AdvISR(ADV_DVC_VAR *asc_dvc)
{
- ushort sig_word;
+ AdvPortAddr iop_base;
+ uchar int_stat;
+ ushort target_bit;
+ ADV_CARR_T *free_carrp;
+ ADV_VADDR irq_next_vpa;
+ ADV_SCSI_REQ_Q *scsiq;
- ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureByte(iop_base));
- if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
- ASC_DBG2(1,
- "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureWord(iop_base));
- sig_word = AscGetChipSignatureWord(iop_base);
- if ((sig_word == (ushort)ASC_1000_ID0W) ||
- (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
- return (1);
- }
+ iop_base = asc_dvc->iop_base;
+
+ /* Reading the register clears the interrupt. */
+ int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+ ADV_INTR_STATUS_INTRC)) == 0) {
+ return ADV_FALSE;
}
- return (0);
-}
-static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
- 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
- ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
-};
+ /*
+ * Notify the driver of an asynchronous microcode condition by
+ * calling the adv_async_callback function. The function
+ * is passed the microcode ASC_MC_INTRB_CODE byte value.
+ */
+ if (int_stat & ADV_INTR_STATUS_INTRB) {
+ uchar intrb_code;
-#ifdef CONFIG_ISA
-static uchar _isa_pnp_inited __initdata = 0;
+ AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
-{
- if (bus_type & ASC_IS_VL) {
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if (AscGetChipVersion(iop_beg, bus_type) <=
- ASC_CHIP_MAX_VER_VL) {
- return (iop_beg);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+ asc_dvc->carr_pending_cnt != 0) {
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ AdvWriteByteRegister(iop_base,
+ IOPB_TICKLE,
+ ADV_TICKLE_NOP);
+ }
}
}
- return (0);
+
+ adv_async_callback(asc_dvc, intrb_code);
}
- if (bus_type & ASC_IS_ISA) {
- if (_isa_pnp_inited == 0) {
- AscSetISAPNPWaitForKey();
- _isa_pnp_inited++;
- }
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if ((AscGetChipVersion(iop_beg, bus_type) &
- ASC_CHIP_VER_ISA_BIT) != 0) {
- return (iop_beg);
- }
+
+ /*
+ * Check if the IRQ stopper carrier contains a completed request.
+ */
+ while (((irq_next_vpa =
+ le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
+ /*
+ * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+ * The RISC will have set 'areq_vpa' to a virtual address.
+ *
+ * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+ * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+ * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+ * in AdvExeScsiQueue().
+ */
+ scsiq = (ADV_SCSI_REQ_Q *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+ /*
+ * Request finished with good status and the queue was not
+ * DMAed to host memory by the firmware. Set all status fields
+ * to indicate good status.
+ */
+ if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
+ scsiq->done_status = QD_NO_ERROR;
+ scsiq->host_status = scsiq->scsi_status = 0;
+ scsiq->data_cnt = 0L;
}
- return (0);
+
+ /*
+ * Advance the stopper pointer to the next carrier
+ * ignoring the lower four bits. Free the previous
+ * stopper carrier.
+ */
+ free_carrp = asc_dvc->irq_sp;
+ asc_dvc->irq_sp = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+
+ free_carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = free_carrp;
+ asc_dvc->carr_pending_cnt--;
+
+ target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+ /*
+ * Clear request microcode control flag.
+ */
+ scsiq->cntl = 0;
+
+ /*
+ * Notify the driver of the completed request by passing
+ * the ADV_SCSI_REQ_Q pointer to its callback function.
+ */
+ scsiq->a_flag |= ADV_SCSIQ_DONE;
+ adv_isr_callback(asc_dvc, scsiq);
+ /*
+ * Note: After the driver callback function is called, 'scsiq'
+ * can no longer be referenced.
+ *
+ * Fall through and continue processing other completed
+ * requests...
+ */
}
- if (bus_type & ASC_IS_EISA) {
- if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
- return (iop_beg);
- }
- return (0);
+ return ADV_TRUE;
+}
+
+static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
+{
+ if (asc_dvc->err_code == 0) {
+ asc_dvc->err_code = err_code;
+ AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+ err_code);
}
- return (0);
+ return err_code;
}
-static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
+static void AscAckInterrupt(PortAddr iop_base)
{
- int i;
- PortAddr iop_base;
+ uchar host_flag;
+ uchar risc_flag;
+ ushort loop;
- for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- if (_asc_def_iop_base[i] > s_addr) {
+ loop = 0;
+ do {
+ risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+ if (loop++ > 0x7FFF) {
break;
}
- }
- for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- iop_base = _asc_def_iop_base[i];
- if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
- ASC_DBG1(1,
- "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
- iop_base);
- continue;
- }
- ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
- iop_base);
- release_region(iop_base, ASC_IOADR_GAP);
- if (AscFindSignature(iop_base)) {
- return (iop_base);
+ } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+ host_flag =
+ AscReadLramByte(iop_base,
+ ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+ (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ loop = 0;
+ while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ if (loop++ > 3) {
+ break;
}
}
- return (0);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
}
-static void __init AscSetISAPNPWaitForKey(void)
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
{
- outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
- outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
- return;
+ const uchar *period_table;
+ int max_index;
+ int min_index;
+ int i;
+
+ period_table = asc_dvc->sdtr_period_tbl;
+ max_index = (int)asc_dvc->max_sdtr_index;
+ min_index = (int)asc_dvc->min_sdtr_index;
+ if ((syn_time <= period_table[max_index])) {
+ for (i = min_index; i < (max_index - 1); i++) {
+ if (syn_time <= period_table[i]) {
+ return (uchar)i;
+ }
+ }
+ return (uchar)max_index;
+ } else {
+ return (uchar)(max_index + 1);
+ }
}
-#endif /* CONFIG_ISA */
-static void __init AscToggleIRQAct(PortAddr iop_base)
+static uchar
+AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
{
- AscSetChipStatus(iop_base, CIW_IRQ_ACT);
- AscSetChipStatus(iop_base, 0);
- return;
+ EXT_MSG sdtr_buf;
+ uchar sdtr_period_index;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ sdtr_buf.msg_type = EXTENDED_MESSAGE;
+ sdtr_buf.msg_len = MS_SDTR_LEN;
+ sdtr_buf.msg_req = EXTENDED_SDTR;
+ sdtr_buf.xfer_period = sdtr_period;
+ sdtr_offset &= ASC_SYN_MAX_OFFSET;
+ sdtr_buf.req_ack_offset = sdtr_offset;
+ sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
+ AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return ((sdtr_period_index << 4) | sdtr_offset);
+ } else {
+ sdtr_buf.req_ack_offset = 0;
+ AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return 0;
+ }
}
-static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
+static uchar
+AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
{
- ushort cfg_lsw;
- uchar chip_irq;
+ uchar byte;
+ uchar sdtr_period_ix;
- if ((bus_type & ASC_IS_EISA) != 0) {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
- if ((chip_irq == 13) || (chip_irq > 15)) {
- return (0);
- }
- return (chip_irq);
- }
- if ((bus_type & ASC_IS_VL) != 0) {
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
- if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
- return (0);
- }
- return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
- }
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
- if (chip_irq == 3)
- chip_irq += (uchar)2;
- return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
+ sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ if (sdtr_period_ix > asc_dvc->max_sdtr_index)
+ return 0xFF;
+ byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+ return byte;
}
-static uchar __init
-AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
+static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
{
- ushort cfg_lsw;
+ ASC_SCSI_BIT_ID_TYPE org_id;
+ int i;
+ int sta = TRUE;
- if ((bus_type & ASC_IS_VL) != 0) {
- if (irq_no != 0) {
- if ((irq_no < ASC_MIN_IRQ_NO)
- || (irq_no > ASC_MAX_IRQ_NO)) {
- irq_no = 0;
- } else {
- irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
- }
+ AscSetBank(iop_base, 1);
+ org_id = AscReadChipDvcID(iop_base);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if (org_id == (0x01 << i))
+ break;
+ }
+ org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+ AscWriteChipDvcID(iop_base, id);
+ if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+ AscSetBank(iop_base, 0);
+ AscSetChipSyn(iop_base, sdtr_data);
+ if (AscGetChipSyn(iop_base) != sdtr_data) {
+ sta = FALSE;
}
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
- cfg_lsw |= (ushort)0x0010;
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
- cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- return (AscGetChipIRQ(iop_base, bus_type));
- }
- if ((bus_type & (ASC_IS_ISA)) != 0) {
- if (irq_no == 15)
- irq_no -= (uchar)2;
- irq_no -= (uchar)ASC_MIN_IRQ_NO;
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
- cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipIRQ(iop_base, bus_type));
+ } else {
+ sta = FALSE;
}
- return (0);
+ AscSetBank(iop_base, 1);
+ AscWriteChipDvcID(iop_base, org_id);
+ AscSetBank(iop_base, 0);
+ return (sta);
}
-#ifdef CONFIG_ISA
-static void __init AscEnableIsaDma(uchar dma_channel)
+static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
{
- if (dma_channel < 4) {
- outp(0x000B, (ushort)(0xC0 | dma_channel));
- outp(0x000A, dma_channel);
- } else if (dma_channel < 8) {
- outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
- outp(0x00D4, (ushort)(dma_channel - 4));
- }
- return;
+ AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
}
-#endif /* CONFIG_ISA */
static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
{
@@ -8528,9 +8597,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
uchar cur_dvc_qng;
uchar asyn_sdtr;
uchar scsi_status;
- asc_board_t *boardp;
+ struct asc_board *boardp;
- ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+ BUG_ON(!asc_dvc->drv_ptr);
boardp = asc_dvc->drv_ptr;
iop_base = asc_dvc->iop_base;
@@ -8541,8 +8610,7 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
target_ix = AscReadLramByte(iop_base,
(ushort)(halt_q_addr +
(ushort)ASC_SCSIQ_B_TARGET_IX));
- q_cntl =
- AscReadLramByte(iop_base,
+ q_cntl = AscReadLramByte(iop_base,
(ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
tid_no = ASC_TIX_TO_TID(target_ix);
target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
@@ -8566,14 +8634,13 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
return (0);
} else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
-
AscMemWordCopyPtrFromLram(iop_base,
ASCV_MSGIN_BEG,
(uchar *)&ext_msg,
sizeof(EXT_MSG) >> 1);
- if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_SDTR_CODE &&
+ if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+ ext_msg.msg_req == EXTENDED_SDTR &&
ext_msg.msg_len == MS_SDTR_LEN) {
sdtr_accept = TRUE;
if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
@@ -8582,15 +8649,14 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
}
if ((ext_msg.xfer_period <
- asc_dvc->sdtr_period_tbl[asc_dvc->
- host_init_sdtr_index])
+ asc_dvc->sdtr_period_tbl[asc_dvc->min_sdtr_index])
|| (ext_msg.xfer_period >
asc_dvc->sdtr_period_tbl[asc_dvc->
max_sdtr_index])) {
sdtr_accept = FALSE;
ext_msg.xfer_period =
asc_dvc->sdtr_period_tbl[asc_dvc->
- host_init_sdtr_index];
+ min_sdtr_index];
}
if (sdtr_accept) {
sdtr_data =
@@ -8614,7 +8680,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
} else {
if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
-
q_cntl &= ~QC_MSG_OUT;
asc_dvc->sdtr_done |= target_id;
asc_dvc->init_sdtr |= target_id;
@@ -8629,7 +8694,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
tid_no);
boardp->sdtr_data[tid_no] = sdtr_data;
} else {
-
q_cntl |= QC_MSG_OUT;
AscMsgOutSDTR(asc_dvc,
ext_msg.xfer_period,
@@ -8655,8 +8719,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
q_cntl);
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
return (0);
- } else if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_WDTR_CODE &&
+ } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+ ext_msg.msg_req == EXTENDED_WDTR &&
ext_msg.msg_len == MS_WDTR_LEN) {
ext_msg.wdtr_width = 0;
@@ -8749,9 +8813,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
(uchar *)&out_msg,
sizeof(EXT_MSG) >> 1);
- if ((out_msg.msg_type == MS_EXTEND) &&
+ if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
(out_msg.msg_len == MS_SDTR_LEN) &&
- (out_msg.msg_req == MS_SDTR_CODE)) {
+ (out_msg.msg_req == EXTENDED_SDTR)) {
asc_dvc->init_sdtr &= ~target_id;
asc_dvc->sdtr_done &= ~target_id;
@@ -8797,9 +8861,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
cur_dvc_qng);
/*
- * Set the device queue depth to the number of
- * active requests when the QUEUE FULL condition
- * was encountered.
+ * Set the device queue depth to the
+ * number of active requests when the
+ * QUEUE FULL condition was encountered.
*/
boardp->queue_full |= target_id;
boardp->queue_full_cnt[tid_no] =
@@ -8825,9 +8889,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
int i;
q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
- if (q_no == ASC_QLINK_END) {
- return (0);
- }
+ if (q_no == ASC_QLINK_END)
+ return 0;
q_addr = ASC_QNO_TO_QADDR(q_no);
@@ -8879,8 +8942,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
sg_entry_cnt = ASC_MAX_SG_LIST - 1;
/*
- * Keep track of remaining number of SG elements that will
- * need to be handled on the next interrupt.
+ * Keep track of remaining number of SG elements that
+ * will need to be handled on the next interrupt.
*/
scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
} else {
@@ -8971,6 +9034,34 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
return (0);
}
+/*
+ * void
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+ *
+ * Calling/Exit State:
+ * none
+ *
+ * Description:
+ * Input an ASC_QDONE_INFO structure from the chip
+ */
+static void
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+{
+ int i;
+ ushort word;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 10) {
+ continue;
+ }
+ word = inpw(iop_base + IOP_RAM_DATA);
+ inbuf[i] = word & 0xff;
+ inbuf[i + 1] = (word >> 8) & 0xff;
+ }
+ ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+}
+
static uchar
_AscCopyLramScsiDoneQ(PortAddr iop_base,
ushort q_addr,
@@ -9014,7 +9105,124 @@ _AscCopyLramScsiDoneQ(PortAddr iop_base,
ASC_SCSIQ_DW_REMAIN_XFER_CNT));
scsiq->remain_bytes &= max_dma_count;
- return (sg_queue_cnt);
+ return sg_queue_cnt;
+}
+
+/*
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
+ */
+static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+{
+ struct asc_board *boardp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+
+ ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep);
+ ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+
+ scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr);
+ if (!scp)
+ return;
+
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ shost = scp->device->host;
+ ASC_STATS(shost, callback);
+ ASC_DBG(1, "shost 0x%p\n", shost);
+
+ boardp = shost_priv(shost);
+ BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
+
+ dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ /*
+ * 'qdonep' contains the command's ending status.
+ */
+ switch (qdonep->d3.done_stat) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "QD_NO_ERROR\n");
+ scp->result = 0;
+
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * return the number of underrun bytes.
+ */
+ if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 &&
+ qdonep->remain_bytes <= scsi_bufflen(scp)) {
+ ASC_DBG(1, "underrun condition %u bytes\n",
+ (unsigned)qdonep->remain_bytes);
+ scsi_set_resid(scp, qdonep->remain_bytes);
+ }
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "QD_WITH_ERROR\n");
+ switch (qdonep->d3.host_stat) {
+ case QHSTA_NO_ERROR:
+ if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by
+ * target drivers defined in scsi.h shifts the
+ * status byte returned by host drivers right
+ * by 1 bit. This is why target drivers also
+ * use right shifted status byte definitions.
+ * For instance target drivers use
+ * CHECK_CONDITION, defined to 0x1, instead of
+ * the SCSI defined check condition value of
+ * 0x2. Host drivers are supposed to return
+ * the status byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ } else {
+ scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+ }
+ break;
+
+ default:
+ /* QHSTA error occurred */
+ ASC_DBG(1, "host_stat 0x%x\n", qdonep->d3.host_stat);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+
+ default:
+ ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+ }
+
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ qdonep->d3.done_stat == QD_NO_ERROR &&
+ qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
+
+ asc_scsi_done(scp);
}
static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
@@ -9035,10 +9243,8 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
ASC_QDONE_INFO scsiq_buf;
ASC_QDONE_INFO *scsiq;
int false_overrun;
- ASC_ISR_CALLBACK asc_isr_callback;
iop_base = asc_dvc->iop_base;
- asc_isr_callback = asc_dvc->isr_callback;
n_q_used = 1;
scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
@@ -9141,7 +9347,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
AscSetChipControl(iop_base,
(uchar)(CC_SCSI_RESET
| CC_HALT));
- DvcDelayNanoSecond(asc_dvc, 60000);
+ udelay(60);
AscSetChipControl(iop_base, CC_HALT);
AscSetChipStatus(iop_base,
CIW_CLR_SCSI_RESET_INT);
@@ -9150,7 +9356,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
}
}
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
+ asc_isr_callback(asc_dvc, scsiq);
} else {
if ((AscReadLramByte(iop_base,
(ushort)(q_addr + (ushort)
@@ -9168,7 +9374,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
FATAL_ERR_QDONE:
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
+ asc_isr_callback(asc_dvc, scsiq);
}
return (0x80);
}
@@ -9190,22 +9396,19 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
iop_base = asc_dvc->iop_base;
int_pending = FALSE;
- if (AscIsIntPending(iop_base) == 0) {
+ if (AscIsIntPending(iop_base) == 0)
return int_pending;
- }
- if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
- || (asc_dvc->isr_callback == 0)
- ) {
- return (ERR);
+ if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
+ return ERR;
}
if (asc_dvc->in_critical_cnt != 0) {
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
- return (ERR);
+ return ERR;
}
if (asc_dvc->is_in_int) {
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
- return (ERR);
+ return ERR;
}
asc_dvc->is_in_int = TRUE;
ctrl_reg = AscGetChipControl(iop_base);
@@ -9220,7 +9423,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
saved_ctrl_reg &= (uchar)(~CC_HALT);
while ((AscGetChipStatus(iop_base) &
CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
- DvcSleepMilliSecond(100);
+ mdelay(100);
}
AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
AscSetChipControl(iop_base, CC_HALT);
@@ -9235,9 +9438,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
(uchar)(~ASC_HOST_FLAG_IN_ISR);
AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
(uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
- if ((chipstat & CSW_INT_PENDING)
- || (int_pending)
- ) {
+ if ((chipstat & CSW_INT_PENDING) || (int_pending)) {
AscAckInterrupt(iop_base);
int_pending = TRUE;
if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
@@ -9268,615 +9469,767 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
AscSetChipLramAddr(iop_base, saved_ram_addr);
AscSetChipControl(iop_base, saved_ctrl_reg);
asc_dvc->is_in_int = FALSE;
- return (int_pending);
+ return int_pending;
}
-/* Microcode buffer is kept after initialization for error recovery. */
-static uchar _asc_mcode_buf[] = {
- 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
- 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
- 0x03, 0x23, 0x36, 0x40,
- 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
- 0xC2, 0x00, 0x92, 0x80,
- 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
- 0xB6, 0x00, 0x92, 0x80,
- 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
- 0x92, 0x80, 0x80, 0x62,
- 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
- 0xCD, 0x04, 0x4D, 0x00,
- 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
- 0xE6, 0x84, 0xD2, 0xC1,
- 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
- 0xC6, 0x81, 0xC2, 0x88,
- 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
- 0x84, 0x97, 0x07, 0xA6,
- 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
- 0xC2, 0x88, 0xCE, 0x00,
- 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
- 0x80, 0x63, 0x07, 0xA6,
- 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
- 0x34, 0x01, 0x00, 0x33,
- 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
- 0x68, 0x98, 0x4D, 0x04,
- 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
- 0xF8, 0x88, 0xFB, 0x23,
- 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
- 0x00, 0x33, 0x0A, 0x00,
- 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
- 0xC2, 0x88, 0xCD, 0x04,
- 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
- 0x06, 0xAB, 0x82, 0x01,
- 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
- 0x3C, 0x01, 0x00, 0x05,
- 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
- 0x15, 0x23, 0xA1, 0x01,
- 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
- 0x06, 0x61, 0x00, 0xA0,
- 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
- 0xC2, 0x88, 0x06, 0x23,
- 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
- 0x57, 0x60, 0x00, 0xA0,
- 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
- 0x4B, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
- 0x4F, 0x00, 0x84, 0x97,
- 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
- 0x48, 0x04, 0x84, 0x80,
- 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
- 0x81, 0x73, 0x06, 0x29,
- 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
- 0x04, 0x98, 0xF0, 0x80,
- 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
- 0x34, 0x02, 0x03, 0xA6,
- 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
- 0x46, 0x82, 0xFE, 0x95,
- 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
- 0x07, 0xA6, 0x5A, 0x02,
- 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
- 0x48, 0x82, 0x60, 0x96,
- 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
- 0x04, 0x01, 0x0C, 0xDC,
- 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
- 0x6F, 0x00, 0xA5, 0x01,
- 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
- 0x02, 0xA6, 0xAA, 0x02,
- 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
- 0x01, 0xA6, 0xB4, 0x02,
- 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
- 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
- 0x04, 0x61, 0x84, 0x01,
- 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
- 0x00, 0x00, 0xEA, 0x82,
- 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
- 0x00, 0x33, 0x1F, 0x00,
- 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
- 0xB6, 0x2D, 0x01, 0xA6,
- 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
- 0x10, 0x03, 0x03, 0xA6,
- 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
- 0x7C, 0x95, 0xEE, 0x82,
- 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
- 0x04, 0x01, 0x2D, 0xC8,
- 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
- 0x05, 0x05, 0x86, 0x98,
- 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
- 0x3C, 0x04, 0x06, 0xA6,
- 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
- 0x7C, 0x95, 0x32, 0x83,
- 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
- 0xEB, 0x04, 0x00, 0x33,
- 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
- 0xFF, 0xA2, 0x7A, 0x03,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
- 0x00, 0xA2, 0x9A, 0x03,
- 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
- 0x01, 0xA6, 0x96, 0x03,
- 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
- 0xA4, 0x03, 0x00, 0xA6,
- 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
- 0x07, 0xA6, 0xB2, 0x03,
- 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
- 0xA8, 0x98, 0x80, 0x42,
- 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
- 0xC0, 0x83, 0x00, 0x33,
- 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
- 0xA0, 0x01, 0x12, 0x23,
- 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
- 0x80, 0x67, 0x05, 0x23,
- 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
- 0x06, 0xA6, 0x0A, 0x04,
- 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
- 0xF4, 0x83, 0x20, 0x84,
- 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
- 0x83, 0x03, 0x80, 0x63,
- 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
- 0x38, 0x04, 0x00, 0x33,
- 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
- 0x1D, 0x01, 0x06, 0xCC,
- 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
- 0xA2, 0x0D, 0x80, 0x63,
- 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
- 0x80, 0x63, 0xA3, 0x01,
- 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
- 0x76, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1E, 0x00,
- 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
- 0x08, 0x23, 0x22, 0xA3,
- 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
- 0xC4, 0x04, 0x42, 0x23,
- 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
- 0xF8, 0x88, 0x04, 0x98,
- 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
- 0x81, 0x62, 0xE8, 0x81,
- 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
- 0x00, 0x33, 0x00, 0x81,
- 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
- 0xF8, 0x88, 0x04, 0x23,
- 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
- 0xF4, 0x04, 0x00, 0x33,
- 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
- 0x04, 0x23, 0xA0, 0x01,
- 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
- 0x00, 0xA3, 0x22, 0x05,
- 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
- 0x46, 0x97, 0xCD, 0x04,
- 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
- 0x82, 0x01, 0x34, 0x85,
- 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
- 0x1D, 0x01, 0x04, 0xD6,
- 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
- 0x49, 0x00, 0x81, 0x01,
- 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
- 0x49, 0x04, 0x80, 0x01,
- 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
- 0x01, 0x23, 0xEA, 0x00,
- 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
- 0x07, 0xA4, 0xF8, 0x05,
- 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
- 0xC2, 0x88, 0x04, 0xA0,
- 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0xA4, 0x05,
- 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
- 0x62, 0x97, 0x04, 0x85,
- 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
- 0xF4, 0x85, 0x03, 0xA0,
- 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
- 0xCC, 0x86, 0x07, 0xA0,
- 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
- 0x80, 0x67, 0x80, 0x63,
- 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
- 0xF8, 0x88, 0x07, 0x23,
- 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
- 0x00, 0x63, 0x4A, 0x00,
- 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
- 0x07, 0x41, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
- 0x1D, 0x01, 0x01, 0xD6,
- 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
- 0x07, 0xA6, 0x7C, 0x05,
- 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
- 0x52, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
- 0x00, 0x63, 0x1D, 0x01,
- 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
- 0x07, 0x41, 0x00, 0x63,
- 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
- 0xDF, 0x00, 0x06, 0xA6,
- 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
- 0x00, 0x40, 0xC0, 0x20,
- 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
- 0x06, 0xA6, 0x94, 0x06,
- 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
- 0x40, 0x0E, 0x80, 0x63,
- 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
- 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
- 0x80, 0x67, 0x40, 0x0E,
- 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
- 0x07, 0xA6, 0xD6, 0x06,
- 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
- 0x0A, 0x2B, 0x07, 0xA6,
- 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
- 0xF4, 0x06, 0xC0, 0x0E,
- 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
- 0x81, 0x62, 0x04, 0x01,
- 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
- 0x8C, 0x06, 0x00, 0x33,
- 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6,
- 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
- 0x00, 0x00, 0x80, 0x67,
- 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
- 0xBF, 0x23, 0x04, 0x61,
- 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
- 0x00, 0x01, 0xF2, 0x00,
- 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
- 0x80, 0x05, 0x81, 0x05,
- 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
- 0x70, 0x00, 0x81, 0x01,
- 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
- 0x70, 0x00, 0x80, 0x01,
- 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
- 0xF1, 0x00, 0x70, 0x00,
- 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
- 0x71, 0x04, 0x70, 0x00,
- 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
- 0xA3, 0x01, 0xA2, 0x01,
- 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
- 0xC4, 0x07, 0x00, 0x33,
- 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
- 0x48, 0x00, 0xB0, 0x01,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
- 0x00, 0xA2, 0xE4, 0x07,
- 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
- 0x05, 0x05, 0x00, 0x63,
- 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
- 0x76, 0x08, 0x80, 0x02,
- 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
- 0x00, 0x02, 0x00, 0xA0,
- 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
- 0x00, 0x63, 0xF3, 0x04,
- 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
- 0x00, 0xA2, 0x44, 0x08,
- 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
- 0x24, 0x08, 0x04, 0x98,
- 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
- 0x5A, 0x88, 0x02, 0x01,
- 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
- 0x00, 0xA3, 0x64, 0x08,
- 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
- 0x06, 0xA6, 0x76, 0x08,
- 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
- 0x00, 0x63, 0x38, 0x2B,
- 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
- 0x05, 0x05, 0xB2, 0x09,
- 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
- 0x80, 0x32, 0x80, 0x36,
- 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
- 0x40, 0x36, 0x40, 0x3A,
- 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
- 0x5D, 0x00, 0xFE, 0xC3,
- 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
- 0xFF, 0xFD, 0x80, 0x73,
- 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
- 0xA1, 0x23, 0xA1, 0x01,
- 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
- 0x80, 0x00, 0x03, 0xC2,
- 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
- 0xA0, 0x01, 0xE6, 0x84,
-};
+/*
+ * advansys_reset()
+ *
+ * Reset the bus associated with the command 'scp'.
+ *
+ * This function runs its own thread. Interrupts must be blocked but
+ * sleeping is allowed and no locking other than for host structures is
+ * required. Returns SUCCESS or FAILED.
+ */
+static int advansys_reset(struct scsi_cmnd *scp)
+{
+ struct Scsi_Host *shost = scp->device->host;
+ struct asc_board *boardp = shost_priv(shost);
+ unsigned long flags;
+ int status;
+ int ret = SUCCESS;
-static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
-static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+ ASC_DBG(1, "0x%p\n", scp);
-#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
-static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
- INQUIRY,
- REQUEST_SENSE,
- READ_CAPACITY,
- READ_TOC,
- MODE_SELECT,
- MODE_SENSE,
- MODE_SELECT_10,
- MODE_SENSE_10,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF
-};
+ ASC_STATS(shost, reset);
-static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
-{
- PortAddr iop_base;
- ulong last_int_level;
- int sta;
- int n_q_required;
- int disable_syn_offset_one_fix;
- int i;
- ASC_PADDR addr;
- ASC_EXE_CALLBACK asc_exe_callback;
- ushort sg_entry_cnt = 0;
- ushort sg_entry_cnt_minus_one = 0;
- uchar target_ix;
- uchar tid_no;
- uchar sdtr_data;
- uchar extra_bytes;
- uchar scsi_cmd;
- uchar disable_cmd;
- ASC_SG_HEAD *sg_head;
- ASC_DCNT data_cnt;
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset started...\n");
- iop_base = asc_dvc->iop_base;
- sg_head = scsiq->sg_head;
- asc_exe_callback = asc_dvc->exe_callback;
- if (asc_dvc->err_code != 0)
- return (ERR);
- if (scsiq == (ASC_SCSI_Q *)0L) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
- return (ERR);
- }
- scsiq->q1.q_no = 0;
- if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
- scsiq->q1.extra_bytes = 0;
- }
- sta = 0;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- n_q_required = 1;
- if (scsiq->cdbptr[0] == REQUEST_SENSE) {
- if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
- asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
- sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
- AscMsgOutSDTR(asc_dvc,
- asc_dvc->
- sdtr_period_tbl[(sdtr_data >> 4) &
- (uchar)(asc_dvc->
- max_sdtr_index -
- 1)],
- (uchar)(sdtr_data & (uchar)
- ASC_SYN_MAX_OFFSET));
- scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+
+ /* Reset the chip and SCSI bus. */
+ ASC_DBG(1, "before AscInitAsc1000Driver()\n");
+ status = AscInitAsc1000Driver(asc_dvc);
+
+ /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+ if (asc_dvc->err_code) {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset error: "
+ "0x%x\n", asc_dvc->err_code);
+ ret = FAILED;
+ } else if (status) {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
+ "0x%x\n", status);
+ } else {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+ "successful\n");
+ }
+
+ ASC_DBG(1, "after AscInitAsc1000Driver()\n");
+ spin_lock_irqsave(shost->host_lock, flags);
+ } else {
+ /*
+ * If the suggest reset bus flags are set, then reset the bus.
+ * Otherwise only reset the device.
+ */
+ ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
+
+ /*
+ * Reset the target's SCSI bus.
+ */
+ ASC_DBG(1, "before AdvResetChipAndSB()\n");
+ switch (AdvResetChipAndSB(adv_dvc)) {
+ case ASC_TRUE:
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+ "successful\n");
+ break;
+ case ASC_FALSE:
+ default:
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset error\n");
+ ret = FAILED;
+ break;
}
+ spin_lock_irqsave(shost->host_lock, flags);
+ AdvISR(adv_dvc);
}
- last_int_level = DvcEnterCritical();
- if (asc_dvc->in_critical_cnt != 0) {
- DvcLeaveCritical(last_int_level);
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
- return (ERR);
+
+ /* Save the time of the most recently completed reset. */
+ boardp->last_reset = jiffies;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ ASC_DBG(1, "ret %d\n", ret);
+
+ return ret;
+}
+
+/*
+ * advansys_biosparam()
+ *
+ * Translate disk drive geometry if the "BIOS greater than 1 GB"
+ * support is enabled for a drive.
+ *
+ * ip (information pointer) is an int array with the following definition:
+ * ip[0]: heads
+ * ip[1]: sectors
+ * ip[2]: cylinders
+ */
+static int
+advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int ip[])
+{
+ struct asc_board *boardp = shost_priv(sdev->host);
+
+ ASC_DBG(1, "begin\n");
+ ASC_STATS(sdev->host, biosparam);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+ ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
+ } else {
+ if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+ BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
}
- asc_dvc->in_critical_cnt++;
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (ERR);
+ ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+ ASC_DBG(1, "end\n");
+ return 0;
+}
+
+/*
+ * First-level interrupt handler.
+ *
+ * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host.
+ */
+static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+{
+ struct Scsi_Host *shost = dev_id;
+ struct asc_board *boardp = shost_priv(shost);
+ irqreturn_t result = IRQ_NONE;
+
+ ASC_DBG(2, "boardp 0x%p\n", boardp);
+ spin_lock(shost->host_lock);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if (AscIsIntPending(shost->io_port)) {
+ result = IRQ_HANDLED;
+ ASC_STATS(shost, interrupt);
+ ASC_DBG(1, "before AscISR()\n");
+ AscISR(&boardp->dvc_var.asc_dvc_var);
}
-#if !CC_VERY_LONG_SG_LIST
- if (sg_entry_cnt > ASC_MAX_SG_LIST) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (ERR);
+ } else {
+ ASC_DBG(1, "before AdvISR()\n");
+ if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+ result = IRQ_HANDLED;
+ ASC_STATS(shost, interrupt);
}
-#endif /* !CC_VERY_LONG_SG_LIST */
- if (sg_entry_cnt == 1) {
- scsiq->q1.data_addr =
- (ADV_PADDR)sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt =
- (ADV_DCNT)sg_head->sg_list[0].bytes;
- scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+ }
+ spin_unlock(shost->host_lock);
+
+ ASC_DBG(1, "end\n");
+ return result;
+}
+
+static int AscHostReqRiscHalt(PortAddr iop_base)
+{
+ int count = 0;
+ int sta = 0;
+ uchar saved_stop_code;
+
+ if (AscIsChipHalted(iop_base))
+ return (1);
+ saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscIsChipHalted(iop_base)) {
+ sta = 1;
+ break;
}
- sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+ mdelay(100);
+ } while (count++ < 20);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+ return (sta);
+}
+
+static int
+AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
+{
+ int sta = FALSE;
+
+ if (AscHostReqRiscHalt(iop_base)) {
+ sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscStartChip(iop_base);
}
- scsi_cmd = scsiq->cdbptr[0];
- disable_syn_offset_one_fix = FALSE;
- if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
- !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
- if (scsiq->q1.cntl & QC_SG_HEAD) {
- data_cnt = 0;
- for (i = 0; i < sg_entry_cnt; i++) {
- data_cnt +=
- (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
- bytes);
- }
+ return sta;
+}
+
+static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
+{
+ char type = sdev->type;
+ ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
+
+ if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN))
+ return;
+ if (asc_dvc->init_sdtr & tid_bits)
+ return;
+
+ if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0))
+ asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+
+ asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+ if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) ||
+ (type == TYPE_ROM) || (type == TYPE_TAPE))
+ asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+
+ if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+ AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id,
+ ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+}
+
+static void
+advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
+{
+ ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
+ ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+
+ if (sdev->lun == 0) {
+ ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
+ if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
+ asc_dvc->init_sdtr |= tid_bit;
} else {
- data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+ asc_dvc->init_sdtr &= ~tid_bit;
}
- if (data_cnt != 0UL) {
- if (data_cnt < 512UL) {
- disable_syn_offset_one_fix = TRUE;
- } else {
- for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
- i++) {
- disable_cmd =
- _syn_offset_one_disable_cmd[i];
- if (disable_cmd == 0xFF) {
- break;
- }
- if (scsi_cmd == disable_cmd) {
- disable_syn_offset_one_fix =
- TRUE;
- break;
- }
- }
+
+ if (orig_init_sdtr != asc_dvc->init_sdtr)
+ AscAsyncFix(asc_dvc, sdev);
+ }
+
+ if (sdev->tagged_supported) {
+ if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
+ if (sdev->lun == 0) {
+ asc_dvc->cfg->can_tagged_qng |= tid_bit;
+ asc_dvc->use_tagged_qng |= tid_bit;
}
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ asc_dvc->max_dvc_qng[sdev->id]);
+ }
+ } else {
+ if (sdev->lun == 0) {
+ asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+ asc_dvc->use_tagged_qng &= ~tid_bit;
}
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
- if (disable_syn_offset_one_fix) {
- scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
- scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
- ASC_TAG_FLAG_DISABLE_DISCONNECT);
+
+ if ((sdev->lun == 0) &&
+ (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+ asc_dvc->use_tagged_qng);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+ asc_dvc->cfg->can_tagged_qng);
+
+ asc_dvc->max_dvc_qng[sdev->id] =
+ asc_dvc->cfg->max_tag_qng[sdev->id];
+ AscWriteLramByte(asc_dvc->iop_base,
+ (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
+ asc_dvc->max_dvc_qng[sdev->id]);
+ }
+}
+
+/*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device supports wide
+ * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
+ * write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) != 0)
+ return;
+
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode SDTR and WDTR negotiation done indicators for
+ * the target to cause it to negotiate with the new setting set above.
+ * WDTR when accepted causes the target to enter asynchronous mode, so
+ * SDTR must be negotiated.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+}
+
+/*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) != 0)
+ return;
+
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" done indicator for the
+ * target to cause it to negotiate with the new setting set above.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+}
+
+/*
+ * PPR (Parallel Protocol Request) Capable
+ *
+ * If the device supports DT mode, then it must be PPR capable.
+ * The PPR message will be used in place of the SDTR and WDTR
+ * messages to negotiate synchronous speed and offset, transfer
+ * width, and protocol options.
+ */
+static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
+ AdvPortAddr iop_base, unsigned short tidmask)
+{
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+ adv_dvc->ppr_able |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+}
+
+static void
+advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
+{
+ AdvPortAddr iop_base = adv_dvc->iop_base;
+ unsigned short tidmask = 1 << sdev->id;
+
+ if (sdev->lun == 0) {
+ /*
+ * Handle WDTR, SDTR, and Tag Queuing. If the feature
+ * is enabled in the EEPROM and the device supports the
+ * feature, then enable it in the microcode.
+ */
+
+ if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
+ advansys_wide_enable_wdtr(iop_base, tidmask);
+ if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
+ advansys_wide_enable_sdtr(iop_base, tidmask);
+ if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
+ advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
+
+ /*
+ * Tag Queuing is disabled for the BIOS which runs in polled
+ * mode and would see no benefit from Tag Queuing. Also by
+ * disabling Tag Queuing in the BIOS devices with Tag Queuing
+ * bugs will at least work with the BIOS.
+ */
+ if ((adv_dvc->tagqng_able & tidmask) &&
+ sdev->tagged_supported) {
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ cfg_word);
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
+ adv_dvc->max_dvc_qng);
+ }
+ }
+
+ if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ adv_dvc->max_dvc_qng);
} else {
- scsiq->q2.tag_code &= 0x27;
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr =
- (ADV_PADDR)le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- addr) +
- (ADV_DCNT)le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes);
- extra_bytes =
- (uchar)((ushort)addr & 0x0003);
- if ((extra_bytes != 0)
- &&
- ((scsiq->q2.
- tag_code &
- ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- scsiq->q2.tag_code |=
- ASC_TAG_FLAG_EXTRA_BYTES;
- scsiq->q1.extra_bytes =
- extra_bytes;
- data_cnt =
- le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes);
- data_cnt -=
- (ASC_DCNT) extra_bytes;
- sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes =
- cpu_to_le32(data_cnt);
- }
- }
- }
+}
+
+/*
+ * Set the number of commands to queue per device for the
+ * specified host adapter.
+ */
+static int advansys_slave_configure(struct scsi_device *sdev)
+{
+ struct asc_board *boardp = shost_priv(sdev->host);
+
+ if (ASC_NARROW_BOARD(boardp))
+ advansys_narrow_slave_configure(sdev,
+ &boardp->dvc_var.asc_dvc_var);
+ else
+ advansys_wide_slave_configure(sdev,
+ &boardp->dvc_var.adv_dvc_var);
+
+ return 0;
+}
+
+static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
+{
+ struct asc_board *board = shost_priv(scp->device->host);
+ scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ dma_cache_sync(board->dev, scp->sense_buffer,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ return cpu_to_le32(scp->SCp.dma_handle);
+}
+
+static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ struct asc_scsi_q *asc_scsi_q)
+{
+ struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+ int use_sg;
+
+ memset(asc_scsi_q, 0, sizeof(*asc_scsi_q));
+
+ /*
+ * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
+ */
+ asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp);
+ if (asc_scsi_q->q2.srb_ptr == BAD_SRB) {
+ scp->result = HOST_BYTE(DID_SOFT_ERROR);
+ return ASC_ERROR;
+ }
+
+ /*
+ * Build the ASC_SCSI_Q request.
+ */
+ asc_scsi_q->cdbptr = &scp->cmnd[0];
+ asc_scsi_q->q2.cdb_len = scp->cmd_len;
+ asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+ asc_scsi_q->q1.target_lun = scp->device->lun;
+ asc_scsi_q->q2.target_ix =
+ ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+ asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
+ asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
+
+ /*
+ * If there are any outstanding requests for the current target,
+ * then every 255th request send an ORDERED request. This heuristic
+ * tries to retain the benefit of request sorting while preventing
+ * request starvation. 255 is the max number of tags or pending commands
+ * a device may have outstanding.
+ *
+ * The request count is incremented below for every successfully
+ * started request.
+ *
+ */
+ if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) &&
+ (boardp->reqcnt[scp->device->id] % 255) == 0) {
+ asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG;
+ } else {
+ asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG;
+ }
+
+ /* Build ASC_SCSI_Q */
+ use_sg = scsi_dma_map(scp);
+ if (use_sg != 0) {
+ int sgcnt;
+ struct scatterlist *slp;
+ struct asc_sg_head *asc_sg_head;
+
+ if (use_sg > scp->device->host->sg_tablesize) {
+ scmd_printk(KERN_ERR, scp, "use_sg %d > "
+ "sg_tablesize %d\n", use_sg,
+ scp->device->host->sg_tablesize);
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_ERROR);
+ return ASC_ERROR;
}
- sg_head->entry_to_copy = sg_head->entry_cnt;
-#if CC_VERY_LONG_SG_LIST
+
+ asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) +
+ use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC);
+ if (!asc_sg_head) {
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_SOFT_ERROR);
+ return ASC_ERROR;
+ }
+
+ asc_scsi_q->q1.cntl |= QC_SG_HEAD;
+ asc_scsi_q->sg_head = asc_sg_head;
+ asc_scsi_q->q1.data_cnt = 0;
+ asc_scsi_q->q1.data_addr = 0;
+ /* This is a byte value, otherwise it would need to be swapped. */
+ asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg;
+ ASC_STATS_ADD(scp->device->host, xfer_elem,
+ asc_sg_head->entry_cnt);
+
/*
- * Set the sg_entry_cnt to the maximum possible. The rest of
- * the SG elements will be copied when the RISC completes the
- * SG elements that fit and halts.
+ * Convert scatter-gather list into ASC_SG_HEAD list.
*/
- if (sg_entry_cnt > ASC_MAX_SG_LIST) {
- sg_entry_cnt = ASC_MAX_SG_LIST;
+ scsi_for_each_sg(scp, slp, use_sg, sgcnt) {
+ asc_sg_head->sg_list[sgcnt].addr =
+ cpu_to_le32(sg_dma_address(slp));
+ asc_sg_head->sg_list[sgcnt].bytes =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, xfer_sect,
+ DIV_ROUND_UP(sg_dma_len(slp), 512));
}
-#endif /* CC_VERY_LONG_SG_LIST */
- n_q_required = AscSgListToQueue(sg_entry_cnt);
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
- (uint) n_q_required)
- || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta =
- AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
+ }
+
+ ASC_STATS(scp->device->host, xfer_cnt);
+
+ ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+ return ASC_NOERROR;
+}
+
+/*
+ * Build scatter-gather list for Adv Library (Wide Board).
+ *
+ * Additional ADV_SG_BLOCK structures will need to be allocated
+ * if the total number of scatter-gather elements exceeds
+ * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
+ * assumed to be physically contiguous.
+ *
+ * Return:
+ * ADV_SUCCESS(1) - SG List successfully created
+ * ADV_ERROR(-1) - SG List creation failed
+ */
+static int
+adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
+ int use_sg)
+{
+ adv_sgblk_t *sgblkp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ struct scatterlist *slp;
+ int sg_elem_cnt;
+ ADV_SG_BLOCK *sg_block, *prev_sg_block;
+ ADV_PADDR sg_block_paddr;
+ int i;
+
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+ slp = scsi_sglist(scp);
+ sg_elem_cnt = use_sg;
+ prev_sg_block = NULL;
+ reqp->sgblkp = NULL;
+
+ for (;;) {
+ /*
+ * Allocate a 'adv_sgblk_t' structure from the board free
+ * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+ * (15) scatter-gather elements.
+ */
+ if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+ ASC_DBG(1, "no free adv_sgblk_t\n");
+ ASC_STATS(scp->device->host, adv_build_nosg);
+
+ /*
+ * Allocation failed. Free 'adv_sgblk_t' structures
+ * already allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
}
+ return ASC_BUSY;
}
- } else {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr =
- le32_to_cpu(scsiq->q1.data_addr) +
- le32_to_cpu(scsiq->q1.data_cnt);
- extra_bytes =
- (uchar)((ushort)addr & 0x0003);
- if ((extra_bytes != 0)
- &&
- ((scsiq->q2.
- tag_code &
- ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- data_cnt =
- le32_to_cpu(scsiq->q1.
- data_cnt);
- if (((ushort)data_cnt & 0x01FF)
- == 0) {
- scsiq->q2.tag_code |=
- ASC_TAG_FLAG_EXTRA_BYTES;
- data_cnt -= (ASC_DCNT)
- extra_bytes;
- scsiq->q1.data_cnt =
- cpu_to_le32
- (data_cnt);
- scsiq->q1.extra_bytes =
- extra_bytes;
- }
- }
- }
- }
+
+ /* Complete 'adv_sgblk_t' board allocation. */
+ boardp->adv_sgblkp = sgblkp->next_sgblkp;
+ sgblkp->next_sgblkp = NULL;
+
+ /*
+ * Get 8 byte aligned virtual and physical addresses
+ * for the allocated ADV_SG_BLOCK structure.
+ */
+ sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
+ sg_block_paddr = virt_to_bus(sg_block);
+
+ /*
+ * Check if this is the first 'adv_sgblk_t' for the
+ * request.
+ */
+ if (reqp->sgblkp == NULL) {
+ /* Request's first scatter-gather block. */
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+ * address pointers.
+ */
+ scsiqp->sg_list_ptr = sg_block;
+ scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
+ } else {
+ /* Request's second or later scatter-gather block. */
+ sgblkp->next_sgblkp = reqp->sgblkp;
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Point the previous ADV_SG_BLOCK structure to
+ * the newly allocated ADV_SG_BLOCK structure.
+ */
+ prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
}
- n_q_required = 1;
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
- ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
+
+ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+ sg_block->sg_list[i].sg_addr =
+ cpu_to_le32(sg_dma_address(slp));
+ sg_block->sg_list[i].sg_count =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, xfer_sect,
+ DIV_ROUND_UP(sg_dma_len(slp), 512));
+
+ if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
+ sg_block->sg_cnt = i + 1;
+ sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
+ return ADV_SUCCESS;
}
+ slp++;
}
+ sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+ prev_sg_block = sg_block;
}
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (sta);
}
+/*
+ * Build a request structure for the Adv Library (Wide Board).
+ *
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
+ * microcode for DMA addresses or math operations are byte swapped
+ * to little-endian order.
+ */
static int
-AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
+adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ ADV_SCSI_REQ_Q **adv_scsiqpp)
{
- PortAddr iop_base;
- uchar free_q_head;
- uchar next_qp;
- uchar tid_no;
- uchar target_ix;
- int sta;
+ adv_req_t *reqp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ int i;
+ int ret;
+ int use_sg;
- iop_base = asc_dvc->iop_base;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- sta = 0;
- free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
- if (n_q_required > 1) {
- if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
- free_q_head, (uchar)
- (n_q_required)))
- != (uchar)ASC_QLINK_END) {
- asc_dvc->last_q_shortage = 0;
- scsiq->sg_head->queue_cnt = n_q_required - 1;
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng += (uchar)(n_q_required);
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
+ /*
+ * Allocate an adv_req_t structure from the board to execute
+ * the command.
+ */
+ if (boardp->adv_reqp == NULL) {
+ ASC_DBG(1, "no free adv_req_t\n");
+ ASC_STATS(scp->device->host, adv_build_noreq);
+ return ASC_BUSY;
+ } else {
+ reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp->next_reqp;
+ reqp->next_reqp = NULL;
+ }
+
+ /*
+ * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+ */
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+
+ /*
+ * Initialize the structure.
+ */
+ scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
+
+ /*
+ * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+ */
+ scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp);
+
+ /*
+ * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
+ */
+ reqp->cmndp = scp;
+
+ /*
+ * Build the ADV_SCSI_REQ_Q request.
+ */
+
+ /* Set CDB length and copy it to the request structure. */
+ scsiqp->cdb_len = scp->cmd_len;
+ /* Copy first 12 CDB bytes to cdb[]. */
+ for (i = 0; i < scp->cmd_len && i < 12; i++) {
+ scsiqp->cdb[i] = scp->cmnd[i];
+ }
+ /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+ for (; i < scp->cmd_len; i++) {
+ scsiqp->cdb16[i - 12] = scp->cmnd[i];
+ }
+
+ scsiqp->target_id = scp->device->id;
+ scsiqp->target_lun = scp->device->lun;
+
+ scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+ scsiqp->sense_len = sizeof(scp->sense_buffer);
+
+ /* Build ADV_SCSI_REQ_Q */
+
+ use_sg = scsi_dma_map(scp);
+ if (use_sg == 0) {
+ /* Zero-length transfer */
+ reqp->sgblkp = NULL;
+ scsiqp->data_cnt = 0;
+ scsiqp->vdata_addr = NULL;
+
+ scsiqp->data_addr = 0;
+ scsiqp->sg_list_ptr = NULL;
+ scsiqp->sg_real_addr = 0;
+ } else {
+ if (use_sg > ADV_MAX_SG_LIST) {
+ scmd_printk(KERN_ERR, scp, "use_sg %d > "
+ "ADV_MAX_SG_LIST %d\n", use_sg,
+ scp->device->host->sg_tablesize);
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_ERROR);
+
+ /*
+ * Free the 'adv_req_t' structure by adding it back
+ * to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ASC_ERROR;
}
- } else if (n_q_required == 1) {
- if ((next_qp = AscAllocFreeQueue(iop_base,
- free_q_head)) !=
- ASC_QLINK_END) {
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng++;
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
+
+ scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));
+
+ ret = adv_get_sglist(boardp, reqp, scp, use_sg);
+ if (ret != ADV_SUCCESS) {
+ /*
+ * Free the adv_req_t structure by adding it back to
+ * the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ret;
}
+
+ ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg);
}
- return (sta);
+
+ ASC_STATS(scp->device->host, xfer_cnt);
+
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+ *adv_scsiqpp = scsiqp;
+
+ return ASC_NOERROR;
}
static int AscSgListToQueue(int sg_list)
@@ -9886,7 +10239,7 @@ static int AscSgListToQueue(int sg_list)
n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
n_sg_list_qs++;
- return (n_sg_list_qs + 1);
+ return n_sg_list_qs + 1;
}
static uint
@@ -9901,7 +10254,7 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
tid_no = ASC_TIX_TO_TID(target_ix);
if ((asc_dvc->unit_not_ready & target_id) ||
(asc_dvc->queue_full_or_busy & target_id)) {
- return (0);
+ return 0;
}
if (n_qs == 1) {
cur_used_qs = (uint) asc_dvc->cur_total_qng +
@@ -9914,9 +10267,9 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
if (asc_dvc->cur_dvc_qng[tid_no] >=
asc_dvc->max_dvc_qng[tid_no]) {
- return (0);
+ return 0;
}
- return (cur_free_qs);
+ return cur_free_qs;
}
if (n_qs > 1) {
if ((n_qs > asc_dvc->last_q_shortage)
@@ -9924,7 +10277,62 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
asc_dvc->last_q_shortage = n_qs;
}
}
- return (0);
+ return 0;
+}
+
+static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
+{
+ ushort q_addr;
+ uchar next_qp;
+ uchar q_status;
+
+ q_addr = ASC_QNO_TO_QADDR(free_q_head);
+ q_status = (uchar)AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_STATUS));
+ next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
+ if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END))
+ return next_qp;
+ return ASC_QLINK_END;
+}
+
+static uchar
+AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
+{
+ uchar i;
+
+ for (i = 0; i < n_free_q; i++) {
+ free_q_head = AscAllocFreeQueue(iop_base, free_q_head);
+ if (free_q_head == ASC_QLINK_END)
+ break;
+ }
+ return free_q_head;
+}
+
+/*
+ * void
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+ *
+ * Calling/Exit State:
+ * none
+ *
+ * Description:
+ * Output an ASC_SCSI_Q structure to the chip
+ */
+static void
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+{
+ int i;
+
+ ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 4 || i == 20) {
+ continue;
+ }
+ outpw(iop_base + IOP_RAM_DATA,
+ ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+ }
}
static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
@@ -9966,7 +10374,7 @@ static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
(ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
(ushort)(((ushort)scsiq->q1.
q_no << 8) | (ushort)QS_READY));
- return (1);
+ return 1;
}
static int
@@ -10104,491 +10512,651 @@ AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
}
static int
-AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
+AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
{
- int sta = FALSE;
+ PortAddr iop_base;
+ uchar free_q_head;
+ uchar next_qp;
+ uchar tid_no;
+ uchar target_ix;
+ int sta;
- if (AscHostReqRiscHalt(iop_base)) {
- sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscStartChip(iop_base);
- return (sta);
+ iop_base = asc_dvc->iop_base;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ sta = 0;
+ free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
+ if (n_q_required > 1) {
+ next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head,
+ (uchar)n_q_required);
+ if (next_qp != ASC_QLINK_END) {
+ asc_dvc->last_q_shortage = 0;
+ scsiq->sg_head->queue_cnt = n_q_required - 1;
+ scsiq->q1.q_no = free_q_head;
+ sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+ free_q_head);
+ }
+ } else if (n_q_required == 1) {
+ next_qp = AscAllocFreeQueue(iop_base, free_q_head);
+ if (next_qp != ASC_QLINK_END) {
+ scsiq->q1.q_no = free_q_head;
+ sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head);
+ }
}
- return (sta);
+ if (sta == 1) {
+ AscPutVarFreeQHead(iop_base, next_qp);
+ asc_dvc->cur_total_qng += n_q_required;
+ asc_dvc->cur_dvc_qng[tid_no]++;
+ }
+ return sta;
}
-static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
+#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
+static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
+ INQUIRY,
+ REQUEST_SENSE,
+ READ_CAPACITY,
+ READ_TOC,
+ MODE_SELECT,
+ MODE_SENSE,
+ MODE_SELECT_10,
+ MODE_SENSE_10,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+};
+
+static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
{
- ASC_SCSI_BIT_ID_TYPE org_id;
+ PortAddr iop_base;
+ int sta;
+ int n_q_required;
+ int disable_syn_offset_one_fix;
int i;
- int sta = TRUE;
+ ASC_PADDR addr;
+ ushort sg_entry_cnt = 0;
+ ushort sg_entry_cnt_minus_one = 0;
+ uchar target_ix;
+ uchar tid_no;
+ uchar sdtr_data;
+ uchar extra_bytes;
+ uchar scsi_cmd;
+ uchar disable_cmd;
+ ASC_SG_HEAD *sg_head;
+ ASC_DCNT data_cnt;
- AscSetBank(iop_base, 1);
- org_id = AscReadChipDvcID(iop_base);
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (org_id == (0x01 << i))
- break;
+ iop_base = asc_dvc->iop_base;
+ sg_head = scsiq->sg_head;
+ if (asc_dvc->err_code != 0)
+ return (ERR);
+ scsiq->q1.q_no = 0;
+ if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+ scsiq->q1.extra_bytes = 0;
}
- org_id = (ASC_SCSI_BIT_ID_TYPE) i;
- AscWriteChipDvcID(iop_base, id);
- if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
- AscSetBank(iop_base, 0);
- AscSetChipSyn(iop_base, sdtr_data);
- if (AscGetChipSyn(iop_base) != sdtr_data) {
- sta = FALSE;
+ sta = 0;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ n_q_required = 1;
+ if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+ if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+ asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+ sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+ AscMsgOutSDTR(asc_dvc,
+ asc_dvc->
+ sdtr_period_tbl[(sdtr_data >> 4) &
+ (uchar)(asc_dvc->
+ max_sdtr_index -
+ 1)],
+ (uchar)(sdtr_data & (uchar)
+ ASC_SYN_MAX_OFFSET));
+ scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
}
+ }
+ if (asc_dvc->in_critical_cnt != 0) {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+ return (ERR);
+ }
+ asc_dvc->in_critical_cnt++;
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+ asc_dvc->in_critical_cnt--;
+ return (ERR);
+ }
+#if !CC_VERY_LONG_SG_LIST
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ asc_dvc->in_critical_cnt--;
+ return (ERR);
+ }
+#endif /* !CC_VERY_LONG_SG_LIST */
+ if (sg_entry_cnt == 1) {
+ scsiq->q1.data_addr =
+ (ADV_PADDR)sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt =
+ (ADV_DCNT)sg_head->sg_list[0].bytes;
+ scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+ }
+ sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+ }
+ scsi_cmd = scsiq->cdbptr[0];
+ disable_syn_offset_one_fix = FALSE;
+ if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+ !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+ if (scsiq->q1.cntl & QC_SG_HEAD) {
+ data_cnt = 0;
+ for (i = 0; i < sg_entry_cnt; i++) {
+ data_cnt +=
+ (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
+ bytes);
+ }
+ } else {
+ data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+ }
+ if (data_cnt != 0UL) {
+ if (data_cnt < 512UL) {
+ disable_syn_offset_one_fix = TRUE;
+ } else {
+ for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
+ i++) {
+ disable_cmd =
+ _syn_offset_one_disable_cmd[i];
+ if (disable_cmd == 0xFF) {
+ break;
+ }
+ if (scsi_cmd == disable_cmd) {
+ disable_syn_offset_one_fix =
+ TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (disable_syn_offset_one_fix) {
+ scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+ scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+ ASC_TAG_FLAG_DISABLE_DISCONNECT);
} else {
- sta = FALSE;
+ scsiq->q2.tag_code &= 0x27;
}
- AscSetBank(iop_base, 1);
- AscWriteChipDvcID(iop_base, org_id);
- AscSetBank(iop_base, 0);
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ (ADV_PADDR)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ addr) +
+ (ADV_DCNT)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ data_cnt =
+ le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ data_cnt -=
+ (ASC_DCNT) extra_bytes;
+ sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes =
+ cpu_to_le32(data_cnt);
+ }
+ }
+ }
+ }
+ sg_head->entry_to_copy = sg_head->entry_cnt;
+#if CC_VERY_LONG_SG_LIST
+ /*
+ * Set the sg_entry_cnt to the maximum possible. The rest of
+ * the SG elements will be copied when the RISC completes the
+ * SG elements that fit and halts.
+ */
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ sg_entry_cnt = ASC_MAX_SG_LIST;
+ }
+#endif /* CC_VERY_LONG_SG_LIST */
+ n_q_required = AscSgListToQueue(sg_entry_cnt);
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+ (uint) n_q_required)
+ || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta =
+ AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ return (sta);
+ }
+ }
+ } else {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ le32_to_cpu(scsiq->q1.data_addr) +
+ le32_to_cpu(scsiq->q1.data_cnt);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ data_cnt =
+ le32_to_cpu(scsiq->q1.
+ data_cnt);
+ if (((ushort)data_cnt & 0x01FF)
+ == 0) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ data_cnt -= (ASC_DCNT)
+ extra_bytes;
+ scsiq->q1.data_cnt =
+ cpu_to_le32
+ (data_cnt);
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ }
+ }
+ }
+ }
+ }
+ n_q_required = 1;
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+ ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ return (sta);
+ }
+ }
+ }
+ asc_dvc->in_critical_cnt--;
return (sta);
}
-static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
+/*
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
+ *
+ * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ * add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ * RISC to notify it a new command is ready to be executed.
+ *
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
+ * for DMA addresses or math operations are byte swapped to little-endian
+ * order.
+ *
+ * Return:
+ * ADV_SUCCESS(1) - The request was successfully queued.
+ * ADV_BUSY(0) - Resource unavailable; Retry again after pending
+ * request completes.
+ * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
+ * host IC error.
+ */
+static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
{
- uchar i;
- ushort s_addr;
- PortAddr iop_base;
- ushort warn_code;
+ AdvPortAddr iop_base;
+ ADV_PADDR req_paddr;
+ ADV_CARR_T *new_carrp;
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
- (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
- 64) >> 1)
- );
- i = ASC_MIN_ACTIVE_QNO;
- s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)(i + 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(asc_dvc->max_total_qng));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)i);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)(i + 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(i - 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)i);
- }
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)ASC_QLINK_END);
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(asc_dvc->max_total_qng - 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)asc_dvc->max_total_qng);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
- i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+ /*
+ * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+ */
+ if (scsiq->target_id > ADV_MAX_TID) {
+ scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+ scsiq->done_status = QD_WITH_ERROR;
+ return ADV_ERROR;
}
- return (warn_code);
-}
-
-static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
-{
- PortAddr iop_base;
- int i;
- ushort lram_addr;
iop_base = asc_dvc->iop_base;
- AscPutRiscVarFreeQHead(iop_base, 1);
- AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscPutVarFreeQHead(iop_base, 1);
- AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
- (uchar)((int)asc_dvc->max_total_qng + 1));
- AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
- (uchar)((int)asc_dvc->max_total_qng + 2));
- AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
- asc_dvc->max_total_qng);
- AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
- AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
- AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
- AscPutQDoneInProgress(iop_base, 0);
- lram_addr = ASC_QADR_BEG;
- for (i = 0; i < 32; i++, lram_addr += 2) {
- AscWriteLramWord(iop_base, lram_addr, 0);
- }
- return (0);
-}
-static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
-{
- if (asc_dvc->err_code == 0) {
- asc_dvc->err_code = err_code;
- AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
- err_code);
+ /*
+ * Allocate a carrier ensuring at least one carrier always
+ * remains on the freelist and initialize fields.
+ */
+ if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
+ return ADV_BUSY;
}
- return (err_code);
-}
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+ asc_dvc->carr_pending_cnt++;
-static uchar
-AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
-{
- EXT_MSG sdtr_buf;
- uchar sdtr_period_index;
- PortAddr iop_base;
+ /*
+ * Set the carrier to be a stopper by setting 'next_vpa'
+ * to the stopper value. The current stopper will be changed
+ * below to point to the new stopper.
+ */
+ new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
- iop_base = asc_dvc->iop_base;
- sdtr_buf.msg_type = MS_EXTEND;
- sdtr_buf.msg_len = MS_SDTR_LEN;
- sdtr_buf.msg_req = MS_SDTR_CODE;
- sdtr_buf.xfer_period = sdtr_period;
- sdtr_offset &= ASC_SYN_MAX_OFFSET;
- sdtr_buf.req_ack_offset = sdtr_offset;
- if ((sdtr_period_index =
- AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
- asc_dvc->max_sdtr_index) {
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *)&sdtr_buf,
- sizeof(EXT_MSG) >> 1);
- return ((sdtr_period_index << 4) | sdtr_offset);
- } else {
+ /*
+ * Clear the ADV_SCSI_REQ_Q done flag.
+ */
+ scsiq->a_flag &= ~ADV_SCSIQ_DONE;
- sdtr_buf.req_ack_offset = 0;
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *)&sdtr_buf,
- sizeof(EXT_MSG) >> 1);
- return (0);
- }
-}
+ req_paddr = virt_to_bus(scsiq);
+ BUG_ON(req_paddr & 31);
+ /* Wait for assertion before making little-endian */
+ req_paddr = cpu_to_le32(req_paddr);
-static uchar
-AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
-{
- uchar byte;
- uchar sdtr_period_ix;
+ /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+ scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+ scsiq->scsiq_rptr = req_paddr;
- sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
- if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
- ) {
- return (0xFF);
- }
- byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
- return (byte);
-}
+ scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
+ /*
+ * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+ * order during initialization.
+ */
+ scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
-static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
-{
- AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
- return;
-}
+ /*
+ * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+ * the microcode. The newly allocated stopper will become the new
+ * stopper.
+ */
+ asc_dvc->icq_sp->areq_vpa = req_paddr;
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
-{
- uchar *period_table;
- int max_index;
- int min_index;
- int i;
+ /*
+ * Set the 'next_vpa' pointer for the old stopper to be the
+ * physical address of the new stopper. The RISC can only
+ * follow physical addresses.
+ */
+ asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
- period_table = asc_dvc->sdtr_period_tbl;
- max_index = (int)asc_dvc->max_sdtr_index;
- min_index = (int)asc_dvc->host_init_sdtr_index;
- if ((syn_time <= period_table[max_index])) {
- for (i = min_index; i < (max_index - 1); i++) {
- if (syn_time <= period_table[i]) {
- return ((uchar)i);
- }
+ /*
+ * Set the host adapter stopper pointer to point to the new carrier.
+ */
+ asc_dvc->icq_sp = new_carrp;
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ /*
+ * Tickle the RISC to tell it to read its Command Queue Head pointer.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_a' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_NOP);
}
- return ((uchar)max_index);
- } else {
- return ((uchar)(max_index + 1));
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ /*
+ * Notify the RISC a carrier is ready by writing the physical
+ * address of the new carrier stopper to the COMMA register.
+ */
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(new_carrp->carr_pa));
}
+
+ return ADV_SUCCESS;
}
-static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
+/*
+ * Execute a single 'Scsi_Cmnd'.
+ */
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
{
- ushort q_addr;
- uchar next_qp;
- uchar q_status;
+ int ret, err_code;
+ struct asc_board *boardp = shost_priv(scp->device->host);
- q_addr = ASC_QNO_TO_QADDR(free_q_head);
- q_status = (uchar)AscReadLramByte(iop_base,
- (ushort)(q_addr +
- ASC_SCSIQ_B_STATUS));
- next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
- if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
- return (next_qp);
- }
- return (ASC_QLINK_END);
-}
+ ASC_DBG(1, "scp 0x%p\n", scp);
-static uchar
-AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
-{
- uchar i;
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+ struct asc_scsi_q asc_scsi_q;
- for (i = 0; i < n_free_q; i++) {
- if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
- == ASC_QLINK_END) {
- return (ASC_QLINK_END);
+ /* asc_build_req() can not return ASC_BUSY. */
+ ret = asc_build_req(boardp, scp, &asc_scsi_q);
+ if (ret == ASC_ERROR) {
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
}
- }
- return (free_q_head);
-}
-static int AscHostReqRiscHalt(PortAddr iop_base)
-{
- int count = 0;
- int sta = 0;
- uchar saved_stop_code;
+ ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q);
+ kfree(asc_scsi_q.sg_head);
+ err_code = asc_dvc->err_code;
+ } else {
+ ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
+ ADV_SCSI_REQ_Q *adv_scsiqp;
- if (AscIsChipHalted(iop_base))
- return (1);
- saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
- do {
- if (AscIsChipHalted(iop_base)) {
- sta = 1;
+ switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_DBG(3, "adv_build_req ASC_NOERROR\n");
break;
+ case ASC_BUSY:
+ ASC_DBG(1, "adv_build_req ASC_BUSY\n");
+ /*
+ * The asc_stats fields 'adv_build_noreq' and
+ * 'adv_build_nosg' count wide board busy conditions.
+ * They are updated in adv_build_req and
+ * adv_get_sglist, respectively.
+ */
+ return ASC_BUSY;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "adv_build_req ASC_ERROR\n");
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
}
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
- return (sta);
-}
-static int AscStopQueueExe(PortAddr iop_base)
-{
- int count = 0;
+ ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp);
+ err_code = adv_dvc->err_code;
+ }
- if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_REQ_RISC_STOP);
- do {
- if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
- ASC_STOP_ACK_RISC_STOP) {
- return (1);
- }
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
+ switch (ret) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->device->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device
+ * successful request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->device->id]++;
+ ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ ASC_STATS(scp->device->host, exe_busy);
+ break;
+ case ASC_ERROR:
+ scmd_printk(KERN_ERR, scp, "ExeScsiQueue() ASC_ERROR, "
+ "err_code 0x%x\n", err_code);
+ ASC_STATS(scp->device->host, exe_error);
+ scp->result = HOST_BYTE(DID_ERROR);
+ break;
+ default:
+ scmd_printk(KERN_ERR, scp, "ExeScsiQueue() unknown, "
+ "err_code 0x%x\n", err_code);
+ ASC_STATS(scp->device->host, exe_unknown);
+ scp->result = HOST_BYTE(DID_ERROR);
+ break;
}
- return (0);
-}
-static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
-{
- udelay(micro_sec);
+ ASC_DBG(1, "end\n");
+ return ret;
}
-static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
+/*
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
+ *
+ * This function always returns 0. Command return status is saved
+ * in the 'scp' result field.
+ */
+static int
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
- udelay((nano_sec + 999) / 1000);
-}
+ struct Scsi_Host *shost = scp->device->host;
+ int asc_res, result = 0;
-#ifdef CONFIG_ISA
-static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
-{
- PortAddr eisa_iop;
- ushort product_id_high, product_id_low;
- ASC_DCNT product_id;
-
- eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
- product_id_low = inpw(eisa_iop);
- product_id_high = inpw(eisa_iop + 2);
- product_id = ((ASC_DCNT) product_id_high << 16) |
- (ASC_DCNT) product_id_low;
- return (product_id);
-}
+ ASC_STATS(shost, queuecommand);
+ scp->scsi_done = done;
-static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
-{
- ASC_DCNT eisa_product_id;
+ asc_res = asc_execute_scsi_cmnd(scp);
- if (iop_base == 0) {
- iop_base = ASC_EISA_MIN_IOP_ADDR;
- } else {
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
- }
- while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
- eisa_product_id = AscGetEisaProductID(iop_base);
- if ((eisa_product_id == ASC_EISA_ID_740) ||
- (eisa_product_id == ASC_EISA_ID_750)) {
- if (AscFindSignature(iop_base)) {
- inpw(iop_base + 4);
- return (iop_base);
- }
- }
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
+ switch (asc_res) {
+ case ASC_NOERROR:
+ break;
+ case ASC_BUSY:
+ result = SCSI_MLQUEUE_HOST_BUSY;
+ break;
+ case ASC_ERROR:
+ default:
+ asc_scsi_done(scp);
+ break;
}
- return (0);
+
+ return result;
}
-#endif /* CONFIG_ISA */
-static int AscStartChip(PortAddr iop_base)
+static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
{
- AscSetChipControl(iop_base, 0);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- return (0);
- }
- return (1);
+ PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+ return inpw(eisa_cfg_iop);
}
-static int AscStopChip(PortAddr iop_base)
+/*
+ * Return the BIOS address of the adapter at the specified
+ * I/O port and with the specified bus type.
+ */
+static unsigned short __devinit
+AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
{
- uchar cc_val;
+ unsigned short cfg_lsw;
+ unsigned short bios_addr;
- cc_val =
- AscGetChipControl(iop_base) &
- (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
- AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
- return (0);
- }
- return (1);
-}
+ /*
+ * The PCI BIOS is re-located by the motherboard BIOS. Because
+ * of this the driver can not determine where a PCI BIOS is
+ * loaded and executes.
+ */
+ if (bus_type & ASC_IS_PCI)
+ return 0;
-static int AscIsChipHalted(PortAddr iop_base)
-{
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
- return (1);
- }
+ if ((bus_type & ASC_IS_EISA) != 0) {
+ cfg_lsw = AscGetEisaChipCfg(iop_base);
+ cfg_lsw &= 0x000F;
+ bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
+ return bios_addr;
}
- return (0);
-}
-static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
-{
- AscSetBank(iop_base, 1);
- AscWriteChipIH(iop_base, ins_code);
- AscSetBank(iop_base, 0);
- return;
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+
+ /*
+ * ISA PnP uses the top bit as the 32K BIOS flag
+ */
+ if (bus_type == ASC_IS_ISAPNP)
+ cfg_lsw &= 0x7FFF;
+ bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
+ return bios_addr;
}
-static void AscAckInterrupt(PortAddr iop_base)
+static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
{
- uchar host_flag;
- uchar risc_flag;
- ushort loop;
+ ushort cfg_lsw;
- loop = 0;
- do {
- risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
- if (loop++ > 0x7FFF) {
- break;
- }
- } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
- host_flag =
- AscReadLramByte(iop_base,
- ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
- (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- loop = 0;
- while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- if (loop++ > 3) {
- break;
- }
+ if (AscGetChipScsiID(iop_base) == new_host_id) {
+ return (new_host_id);
}
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
- return;
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ cfg_lsw &= 0xF8FF;
+ cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ return (AscGetChipScsiID(iop_base));
}
-static void AscDisableInterrupt(PortAddr iop_base)
+static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
{
- ushort cfg;
+ unsigned char sc;
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
- return;
+ AscSetBank(iop_base, 1);
+ sc = inp(iop_base + IOP_REG_SC);
+ AscSetBank(iop_base, 0);
+ return sc;
}
-static void AscEnableInterrupt(PortAddr iop_base)
+static unsigned char __devinit
+AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
{
- ushort cfg;
-
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
- return;
+ if (bus_type & ASC_IS_EISA) {
+ PortAddr eisa_iop;
+ unsigned char revision;
+ eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) ASC_EISA_REV_IOP_MASK;
+ revision = inp(eisa_iop);
+ return ASC_CHIP_MIN_VER_EISA - 1 + revision;
+ }
+ return AscGetChipVerNo(iop_base);
}
-static void AscSetBank(PortAddr iop_base, uchar bank)
+#ifdef CONFIG_ISA
+static void __devinit AscEnableIsaDma(uchar dma_channel)
{
- uchar val;
-
- val = AscGetChipControl(iop_base) &
- (~
- (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
- CC_CHIP_RESET));
- if (bank == 1) {
- val |= CC_BANK_ONE;
- } else if (bank == 2) {
- val |= CC_DIAG | CC_BANK_ONE;
- } else {
- val &= ~CC_BANK_ONE;
+ if (dma_channel < 4) {
+ outp(0x000B, (ushort)(0xC0 | dma_channel));
+ outp(0x000A, dma_channel);
+ } else if (dma_channel < 8) {
+ outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
+ outp(0x00D4, (ushort)(dma_channel - 4));
}
- AscSetChipControl(iop_base, val);
- return;
}
+#endif /* CONFIG_ISA */
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
+static int AscStopQueueExe(PortAddr iop_base)
{
- PortAddr iop_base;
- int i = 10;
+ int count = 0;
- iop_base = asc_dvc->iop_base;
- while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
- && (i-- > 0)) {
- DvcSleepMilliSecond(100);
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+ ASC_STOP_ACK_RISC_STOP) {
+ return (1);
+ }
+ mdelay(100);
+ } while (count++ < 20);
}
- AscStopChip(iop_base);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
- DvcDelayNanoSecond(asc_dvc, 60000);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
- AscSetChipControl(iop_base, CC_HALT);
- DvcSleepMilliSecond(200);
- AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
- AscSetChipStatus(iop_base, 0);
- return (AscIsChipHalted(iop_base));
+ return (0);
}
-static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
+static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
{
if (bus_type & ASC_IS_ISA)
- return (ASC_MAX_ISA_DMA_COUNT);
+ return ASC_MAX_ISA_DMA_COUNT;
else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
- return (ASC_MAX_VL_DMA_COUNT);
- return (ASC_MAX_PCI_DMA_COUNT);
+ return ASC_MAX_VL_DMA_COUNT;
+ return ASC_MAX_PCI_DMA_COUNT;
}
#ifdef CONFIG_ISA
-static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
+static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
{
ushort channel;
@@ -10600,7 +11168,7 @@ static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
return (channel + 4);
}
-static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
+static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
{
ushort cfg_lsw;
uchar value;
@@ -10615,19 +11183,10 @@ static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
AscSetChipCfgLsw(iop_base, cfg_lsw);
return (AscGetIsaDmaChannel(iop_base));
}
- return (0);
-}
-
-static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
-{
- speed_value &= 0x07;
- AscSetBank(iop_base, 1);
- AscWriteChipDmaSpeed(iop_base, speed_value);
- AscSetBank(iop_base, 0);
- return (AscGetIsaDmaSpeed(iop_base));
+ return 0;
}
-static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
+static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
{
uchar speed_value;
@@ -10635,223 +11194,20 @@ static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
speed_value = AscReadChipDmaSpeed(iop_base);
speed_value &= 0x07;
AscSetBank(iop_base, 0);
- return (speed_value);
+ return speed_value;
}
-#endif /* CONFIG_ISA */
-static ushort __init
-AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
+static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
{
- uchar lsb, msb;
-
- lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
- msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
- return ((ushort)((msb << 8) | lsb));
-}
-
-static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code;
- PortAddr iop_base;
- ushort PCIDeviceID;
- ushort PCIVendorID;
- uchar PCIRevisionID;
- uchar prevCmdRegBits;
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
- asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
- if (asc_dvc->err_code != 0) {
- return (UW_ERR);
- }
- if (asc_dvc->bus_type == ASC_IS_PCI) {
- PCIVendorID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigVendorIDRegister);
-
- PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigDeviceIDRegister);
-
- PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigRevisionIDRegister);
-
- if (PCIVendorID != PCI_VENDOR_ID_ASP) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister);
-
- if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
- AscPCICmdRegBits_IOMemBusMaster) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister,
- (prevCmdRegBits |
- AscPCICmdRegBits_IOMemBusMaster));
-
- if ((DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_IOMemBusMaster)
- != AscPCICmdRegBits_IOMemBusMaster) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
- (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer, 0x00);
- if (DvcReadPCIConfigByte
- (asc_dvc, AscPCIConfigLatencyTimer)
- != 0x00) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer) <
- 0x20) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer,
- 0x20);
-
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer)
- < 0x20) {
- warn_code |=
- ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- }
- }
-
- if (AscFindSignature(iop_base)) {
- warn_code |= AscInitAscDvcVar(asc_dvc);
- warn_code |= AscInitFromEEP(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
- if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
- asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
- }
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return (warn_code);
-}
-
-static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code = 0;
-
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (AscFindSignature(asc_dvc->iop_base)) {
- warn_code |= AscInitFromAscDvcVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return (warn_code);
+ speed_value &= 0x07;
+ AscSetBank(iop_base, 1);
+ AscWriteChipDmaSpeed(iop_base, speed_value);
+ AscSetBank(iop_base, 0);
+ return AscGetIsaDmaSpeed(iop_base);
}
-
-static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
-{
- PortAddr iop_base;
- ushort cfg_msw;
- ushort warn_code;
- ushort pci_device_id = 0;
-
- iop_base = asc_dvc->iop_base;
-#ifdef CONFIG_PCI
- if (asc_dvc->cfg->dev)
- pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
-#endif
- warn_code = 0;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
- asc_dvc->cfg->cmd_qng_enabled) {
- asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- }
- if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
- if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
- != asc_dvc->irq_no) {
- asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
- }
- }
- if (asc_dvc->bus_type & ASC_IS_PCI) {
- cfg_msw &= 0xFFC0;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
- } else {
- if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
- (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
- asc_dvc->bug_fix_cntl |=
- ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
- == ASC_CHIP_VER_ASYN_BUG) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
- asc_dvc->cfg->chip_scsi_id) {
- asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
- }
-#ifdef CONFIG_ISA
- if (asc_dvc->bus_type & ASC_IS_ISA) {
- AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
- AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
- }
#endif /* CONFIG_ISA */
- return (warn_code);
-}
-
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
- !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort)asc_dvc->scsi_reset_wait * 1000));
- }
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (!AscFindSignature(asc_dvc->iop_base)) {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return (warn_code);
- }
- AscDisableInterrupt(iop_base);
- warn_code |= AscInitLram(asc_dvc);
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
- (ulong)_asc_mcode_chksum);
- if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
- _asc_mcode_size) != _asc_mcode_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return (warn_code);
- }
- warn_code |= AscInitMicroCodeVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
- AscEnableInterrupt(iop_base);
- return (warn_code);
-}
-static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
+static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
{
int i;
PortAddr iop_base;
@@ -10882,7 +11238,7 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->queue_full_or_busy = 0;
asc_dvc->redo_scam = 0;
asc_dvc->res2 = 0;
- asc_dvc->host_init_sdtr_index = 0;
+ asc_dvc->min_sdtr_index = 0;
asc_dvc->cfg->can_tagged_qng = 0;
asc_dvc->cfg->cmd_qng_enabled = 0;
asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
@@ -10894,39 +11250,14 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
- asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
- asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
- ASC_LIB_VERSION_MINOR;
chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
asc_dvc->cfg->chip_version = chip_version;
- asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+ asc_dvc->sdtr_period_tbl = asc_syn_xfer_period;
asc_dvc->max_sdtr_index = 7;
if ((asc_dvc->bus_type & ASC_IS_PCI) &&
(chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
- asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
- asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
- asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
- asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
- asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
- asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
- asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
- asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
- asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+ asc_dvc->sdtr_period_tbl = asc_syn_ultra_xfer_period;
asc_dvc->max_sdtr_index = 15;
if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
AscSetExtraControl(iop_base,
@@ -10943,12 +11274,12 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
}
asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
- if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
- AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
- asc_dvc->bus_type = ASC_IS_ISAPNP;
- }
#ifdef CONFIG_ISA
if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+ if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
+ AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+ asc_dvc->bus_type = ASC_IS_ISAPNP;
+ }
asc_dvc->cfg->isa_dma_channel =
(uchar)AscGetIsaDmaChannel(iop_base);
}
@@ -10960,231 +11291,92 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
}
- return (warn_code);
+ return warn_code;
}
-static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
{
- ASCEEP_CONFIG eep_config_buf;
- ASCEEP_CONFIG *eep_config;
- PortAddr iop_base;
- ushort chksum;
- ushort warn_code;
- ushort cfg_msw, cfg_lsw;
- int i;
- int write_eep = 0;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
- AscStopQueueExe(iop_base);
- if ((AscStopChip(iop_base) == FALSE) ||
- (AscGetChipScsiCtrl(iop_base) != 0)) {
- asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort)asc_dvc->scsi_reset_wait * 1000));
- }
- if (AscIsChipHalted(iop_base) == FALSE) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
- }
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
- }
- eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
- ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
- if (chksum == 0) {
- chksum = 0xaa55;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- if (asc_dvc->cfg->chip_version == 3) {
- if (eep_config->cfg_lsw != cfg_lsw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_lsw =
- AscGetChipCfgLsw(iop_base);
- }
- if (eep_config->cfg_msw != cfg_msw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_msw =
- AscGetChipCfgMsw(iop_base);
- }
- }
- }
- eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
- eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
- ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
- eep_config->chksum);
- if (chksum != eep_config->chksum) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
- ASC_CHIP_VER_PCI_ULTRA_3050) {
- ASC_DBG(1,
- "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
- eep_config->init_sdtr = 0xFF;
- eep_config->disc_enable = 0xFF;
- eep_config->start_motor = 0xFF;
- eep_config->use_cmd_qng = 0;
- eep_config->max_total_qng = 0xF0;
- eep_config->max_tag_qng = 0x20;
- eep_config->cntl = 0xBFFF;
- ASC_EEP_SET_CHIP_ID(eep_config, 7);
- eep_config->no_scam = 0;
- eep_config->adapter_info[0] = 0;
- eep_config->adapter_info[1] = 0;
- eep_config->adapter_info[2] = 0;
- eep_config->adapter_info[3] = 0;
- eep_config->adapter_info[4] = 0;
- /* Indicate EEPROM-less board. */
- eep_config->adapter_info[5] = 0xBB;
- } else {
- ASC_PRINT
- ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
- write_eep = 1;
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
- }
- }
- asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
- asc_dvc->cfg->disc_enable = eep_config->disc_enable;
- asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
- asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
- asc_dvc->start_motor = eep_config->start_motor;
- asc_dvc->dvc_cntl = eep_config->cntl;
- asc_dvc->no_scam = eep_config->no_scam;
- asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
- asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
- asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
- asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
- asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
- asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
- if (!AscTestExternalLram(asc_dvc)) {
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
- ASC_IS_PCI_ULTRA)) {
- eep_config->max_total_qng =
- ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng =
- ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
- } else {
- eep_config->cfg_msw |= 0x0800;
- cfg_msw |= 0x0800;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
- }
- } else {
- }
- if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
- }
- if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
- }
- if (eep_config->max_tag_qng > eep_config->max_total_qng) {
- eep_config->max_tag_qng = eep_config->max_total_qng;
- }
- if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
- eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
- }
- asc_dvc->max_total_qng = eep_config->max_total_qng;
- if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
- eep_config->use_cmd_qng) {
- eep_config->disc_enable = eep_config->use_cmd_qng;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
- asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
- }
- ASC_EEP_SET_CHIP_ID(eep_config,
- ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
- asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
- !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
- asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
- }
+ int retry;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
- asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
- asc_dvc->cfg->sdtr_period_offset[i] =
- (uchar)(ASC_DEF_SDTR_OFFSET |
- (asc_dvc->host_init_sdtr_index << 4));
- }
- eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
- if (write_eep) {
- if ((i =
- AscSetEEPConfig(iop_base, eep_config,
- asc_dvc->bus_type)) != 0) {
- ASC_PRINT1
- ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
- i);
- } else {
- ASC_PRINT
- ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
- }
+ for (retry = 0; retry < ASC_EEP_MAX_RETRY; retry++) {
+ unsigned char read_back;
+ AscSetChipEEPCmd(iop_base, cmd_reg);
+ mdelay(1);
+ read_back = AscGetChipEEPCmd(iop_base);
+ if (read_back == cmd_reg)
+ return 1;
}
- return (warn_code);
+ return 0;
}
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
+static void __devinit AscWaitEEPRead(void)
{
- int i;
- ushort warn_code;
- PortAddr iop_base;
- ASC_PADDR phy_addr;
- ASC_DCNT phy_size;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- AscPutMCodeInitSDTRAtID(iop_base, i,
- asc_dvc->cfg->sdtr_period_offset[i]
- );
- }
+ mdelay(1);
+}
- AscInitQLinkVar(asc_dvc);
- AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
- ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
+{
+ ushort read_wval;
+ uchar cmd_reg;
- /* Align overrun buffer on an 8 byte boundary. */
- phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
- phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
- (uchar *)&phy_addr, 1);
- phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
- (uchar *)&phy_size, 1);
+ AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+ AscWaitEEPRead();
+ cmd_reg = addr | ASC_EEP_CMD_READ;
+ AscWriteEEPCmdReg(iop_base, cmd_reg);
+ AscWaitEEPRead();
+ read_wval = AscGetChipEEPData(iop_base);
+ AscWaitEEPRead();
+ return read_wval;
+}
- asc_dvc->cfg->mcode_date =
- AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
- asc_dvc->cfg->mcode_version =
- AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+static ushort __devinit
+AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+{
+ ushort wval;
+ ushort sum;
+ ushort *wbuf;
+ int cfg_beg;
+ int cfg_end;
+ int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+ int s_addr;
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
+ wbuf = (ushort *)cfg_buf;
+ sum = 0;
+ /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ sum += *wbuf;
}
- if (AscStartChip(iop_base) != 1) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
+ if (bus_type & ASC_IS_VL) {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+ } else {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR;
}
-
- return (warn_code);
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ wval = AscReadEEPWord(iop_base, (uchar)s_addr);
+ if (s_addr <= uchar_end_in_config) {
+ /*
+ * Swap all char fields - must unswap bytes already swapped
+ * by AscReadEEPWord().
+ */
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ /* Don't swap word field at the end - cntl field. */
+ *wbuf = wval;
+ }
+ sum += wval; /* Checksum treats all EEPROM data as words. */
+ }
+ /*
+ * Read the checksum word which will be compared against 'sum'
+ * by the caller. Word field already swapped.
+ */
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ return sum;
}
-static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
+static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
{
PortAddr iop_base;
ushort q_addr;
@@ -11197,7 +11389,7 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
saved_word = AscReadLramWord(iop_base, q_addr);
AscSetChipLramAddr(iop_base, q_addr);
AscSetChipLramData(iop_base, 0x55AA);
- DvcSleepMilliSecond(10);
+ mdelay(10);
AscSetChipLramAddr(iop_base, q_addr);
if (AscGetChipLramData(iop_base) == 0x55AA) {
sta = 1;
@@ -11206,26 +11398,12 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
return (sta);
}
-static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
+static void __devinit AscWaitEEPWrite(void)
{
- uchar read_back;
- int retry;
-
- retry = 0;
- while (TRUE) {
- AscSetChipEEPCmd(iop_base, cmd_reg);
- DvcSleepMilliSecond(1);
- read_back = AscGetChipEEPCmd(iop_base);
- if (read_back == cmd_reg) {
- return (1);
- }
- if (retry++ > ASC_EEP_MAX_RETRY) {
- return (0);
- }
- }
+ mdelay(20);
}
-static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
+static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
{
ushort read_back;
int retry;
@@ -11233,7 +11411,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
retry = 0;
while (TRUE) {
AscSetChipEEPData(iop_base, data_reg);
- DvcSleepMilliSecond(1);
+ mdelay(1);
read_back = AscGetChipEEPData(iop_base);
if (read_back == data_reg) {
return (1);
@@ -11244,34 +11422,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
}
}
-static void __init AscWaitEEPRead(void)
-{
- DvcSleepMilliSecond(1);
- return;
-}
-
-static void __init AscWaitEEPWrite(void)
-{
- DvcSleepMilliSecond(20);
- return;
-}
-
-static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
-{
- ushort read_wval;
- uchar cmd_reg;
-
- AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
- AscWaitEEPRead();
- cmd_reg = addr | ASC_EEP_CMD_READ;
- AscWriteEEPCmdReg(iop_base, cmd_reg);
- AscWaitEEPRead();
- read_wval = AscGetChipEEPData(iop_base);
- AscWaitEEPRead();
- return (read_wval);
-}
-
-static ushort __init
+static ushort __devinit
AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
{
ushort read_wval;
@@ -11292,54 +11443,7 @@ AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
return (read_wval);
}
-static ushort __init
-AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
-{
- ushort wval;
- ushort sum;
- ushort *wbuf;
- int cfg_beg;
- int cfg_end;
- int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
- int s_addr;
-
- wbuf = (ushort *)cfg_buf;
- sum = 0;
- /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
- for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
- *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
- sum += *wbuf;
- }
- if (bus_type & ASC_IS_VL) {
- cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
- cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
- } else {
- cfg_beg = ASC_EEP_DVC_CFG_BEG;
- cfg_end = ASC_EEP_MAX_DVC_ADDR;
- }
- for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
- wval = AscReadEEPWord(iop_base, (uchar)s_addr);
- if (s_addr <= uchar_end_in_config) {
- /*
- * Swap all char fields - must unswap bytes already swapped
- * by AscReadEEPWord().
- */
- *wbuf = le16_to_cpu(wval);
- } else {
- /* Don't swap word field at the end - cntl field. */
- *wbuf = wval;
- }
- sum += wval; /* Checksum treats all EEPROM data as words. */
- }
- /*
- * Read the checksum word which will be compared against 'sum'
- * by the caller. Word field already swapped.
- */
- *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
- return (sum);
-}
-
-static int __init
+static int __devinit
AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
int n_error;
@@ -11432,10 +11536,10 @@ AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
n_error++;
}
- return (n_error);
+ return n_error;
}
-static int __init
+static int __devinit
AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
int retry;
@@ -11451,2386 +11555,326 @@ AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
break;
}
}
- return (n_error);
+ return n_error;
}
-static void
-AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
{
- uchar dvc_type;
- ASC_SCSI_BIT_ID_TYPE tid_bits;
-
- dvc_type = ASC_INQ_DVC_TYPE(inq);
- tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
-
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
- if (!(asc_dvc->init_sdtr & tid_bits)) {
- if ((dvc_type == TYPE_ROM) &&
- (AscCompareString((uchar *)inq->vendor_id,
- (uchar *)"HP ", 3) == 0)) {
- asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
- }
- asc_dvc->pci_fix_asyn_xfer |= tid_bits;
- if ((dvc_type == TYPE_PROCESSOR) ||
- (dvc_type == TYPE_SCANNER) ||
- (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
+ ASCEEP_CONFIG eep_config_buf;
+ ASCEEP_CONFIG *eep_config;
+ PortAddr iop_base;
+ ushort chksum;
+ ushort warn_code;
+ ushort cfg_msw, cfg_lsw;
+ int i;
+ int write_eep = 0;
- if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
- AscSetRunChipSynRegAtID(asc_dvc->iop_base,
- tid_no,
- ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+ AscStopQueueExe(iop_base);
+ if ((AscStopChip(iop_base) == FALSE) ||
+ (AscGetChipScsiCtrl(iop_base) != 0)) {
+ asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+ AscResetChipAndScsiBus(asc_dvc);
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+ }
+ if (AscIsChipHalted(iop_base) == FALSE) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return (warn_code);
+ }
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return (warn_code);
+ }
+ eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ }
+ chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+ ASC_DBG(1, "chksum 0x%x\n", chksum);
+ if (chksum == 0) {
+ chksum = 0xaa55;
+ }
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ if (asc_dvc->cfg->chip_version == 3) {
+ if (eep_config->cfg_lsw != cfg_lsw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_lsw =
+ AscGetChipCfgLsw(iop_base);
+ }
+ if (eep_config->cfg_msw != cfg_msw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_msw =
+ AscGetChipCfgMsw(iop_base);
}
}
}
- return;
-}
-
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
-{
- if ((inq->add_len >= 32) &&
- (AscCompareString((uchar *)inq->vendor_id,
- (uchar *)"QUANTUM XP34301", 15) == 0) &&
- (AscCompareString((uchar *)inq->product_rev_level,
- (uchar *)"1071", 4) == 0)) {
- return 0;
- }
- return 1;
-}
-
-static void
-AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
-{
- ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
- ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
-
- orig_init_sdtr = asc_dvc->init_sdtr;
- orig_use_tagged_qng = asc_dvc->use_tagged_qng;
-
- asc_dvc->init_sdtr &= ~tid_bit;
- asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
- asc_dvc->use_tagged_qng &= ~tid_bit;
-
- if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
- if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
- asc_dvc->init_sdtr |= tid_bit;
+ eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+ ASC_DBG(1, "eep_config->chksum 0x%x\n", eep_config->chksum);
+ if (chksum != eep_config->chksum) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+ ASC_CHIP_VER_PCI_ULTRA_3050) {
+ ASC_DBG(1, "chksum error ignored; EEPROM-less board\n");
+ eep_config->init_sdtr = 0xFF;
+ eep_config->disc_enable = 0xFF;
+ eep_config->start_motor = 0xFF;
+ eep_config->use_cmd_qng = 0;
+ eep_config->max_total_qng = 0xF0;
+ eep_config->max_tag_qng = 0x20;
+ eep_config->cntl = 0xBFFF;
+ ASC_EEP_SET_CHIP_ID(eep_config, 7);
+ eep_config->no_scam = 0;
+ eep_config->adapter_info[0] = 0;
+ eep_config->adapter_info[1] = 0;
+ eep_config->adapter_info[2] = 0;
+ eep_config->adapter_info[3] = 0;
+ eep_config->adapter_info[4] = 0;
+ /* Indicate EEPROM-less board. */
+ eep_config->adapter_info[5] = 0xBB;
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+ write_eep = 1;
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
}
- if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
- ASC_INQ_CMD_QUEUE(inq)) {
- if (AscTagQueuingSafe(inq)) {
- asc_dvc->use_tagged_qng |= tid_bit;
- asc_dvc->cfg->can_tagged_qng |= tid_bit;
- }
+ }
+ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+ asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+ asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+ asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+ asc_dvc->start_motor = eep_config->start_motor;
+ asc_dvc->dvc_cntl = eep_config->cntl;
+ asc_dvc->no_scam = eep_config->no_scam;
+ asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+ asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+ asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+ asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+ asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+ asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+ if (!AscTestExternalLram(asc_dvc)) {
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
+ ASC_IS_PCI_ULTRA)) {
+ eep_config->max_total_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+ } else {
+ eep_config->cfg_msw |= 0x0800;
+ cfg_msw |= 0x0800;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
}
+ } else {
}
- if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
- AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
- asc_dvc->use_tagged_qng);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
- asc_dvc->cfg->can_tagged_qng);
-
- asc_dvc->max_dvc_qng[tid_no] =
- asc_dvc->cfg->max_tag_qng[tid_no];
- AscWriteLramByte(asc_dvc->iop_base,
- (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
- asc_dvc->max_dvc_qng[tid_no]);
+ if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
}
- if (orig_init_sdtr != asc_dvc->init_sdtr) {
- AscAsyncFix(asc_dvc, tid_no, inq);
+ if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
}
- return;
-}
-
-static int AscCompareString(uchar *str1, uchar *str2, int len)
-{
- int i;
- int diff;
-
- for (i = 0; i < len; i++) {
- diff = (int)(str1[i] - str2[i]);
- if (diff != 0)
- return (diff);
+ if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+ eep_config->max_tag_qng = eep_config->max_total_qng;
}
- return (0);
-}
-
-static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
-{
- uchar byte_data;
- ushort word_data;
-
- if (isodd_word(addr)) {
- AscSetChipLramAddr(iop_base, addr - 1);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar)((word_data >> 8) & 0xFF);
- } else {
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar)(word_data & 0xFF);
+ if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+ eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+ }
+ asc_dvc->max_total_qng = eep_config->max_total_qng;
+ if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+ eep_config->use_cmd_qng) {
+ eep_config->disc_enable = eep_config->use_cmd_qng;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+ }
+ ASC_EEP_SET_CHIP_ID(eep_config,
+ ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+ asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+ !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+ asc_dvc->min_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
}
- return (byte_data);
-}
-
-static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
-{
- ushort word_data;
-
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- return (word_data);
-}
-
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
-{
- ushort val_low, val_high;
- ASC_DCNT dword_data;
- AscSetChipLramAddr(iop_base, addr);
- val_low = AscGetChipLramData(iop_base);
- val_high = AscGetChipLramData(iop_base);
- dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
- return (dword_data);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+ asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+ asc_dvc->cfg->sdtr_period_offset[i] =
+ (uchar)(ASC_DEF_SDTR_OFFSET |
+ (asc_dvc->min_sdtr_index << 4));
+ }
+ eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+ if (write_eep) {
+ if ((i = AscSetEEPConfig(iop_base, eep_config,
+ asc_dvc->bus_type)) != 0) {
+ ASC_PRINT1
+ ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
+ i);
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
+ }
+ }
+ return (warn_code);
}
-#endif /* CC_VERY_LONG_SG_LIST */
-static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
+static int __devinit AscInitGetConfig(struct Scsi_Host *shost)
{
- AscSetChipLramAddr(iop_base, addr);
- AscSetChipLramData(iop_base, word_val);
- return;
-}
+ struct asc_board *board = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+ unsigned short warn_code = 0;
-static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
-{
- ushort word_data;
+ asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+ if (asc_dvc->err_code != 0)
+ return asc_dvc->err_code;
- if (isodd_word(addr)) {
- addr--;
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0x00FF;
- word_data |= (((ushort)byte_val << 8) & 0xFF00);
+ if (AscFindSignature(asc_dvc->iop_base)) {
+ warn_code |= AscInitAscDvcVar(asc_dvc);
+ warn_code |= AscInitFromEEP(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+ if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
+ asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
} else {
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0xFF00;
- word_data |= ((ushort)byte_val & 0x00FF);
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
}
- AscWriteLramWord(iop_base, addr, word_data);
- return;
-}
-/*
- * Copy 2 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when written to LRAM.
- */
-static void
-AscMemWordCopyPtrToLram(PortAddr iop_base,
- ushort s_addr, uchar *s_buffer, int words)
-{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- /*
- * On a little-endian system the second argument below
- * produces a little-endian ushort which is written to
- * LRAM in little-endian order. On a big-endian system
- * the second argument produces a big-endian ushort which
- * is "transparently" byte-swapped by outpw() and written
- * in little-endian order to LRAM.
- */
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
+ switch (warn_code) {
+ case 0: /* No error */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ shost_printk(KERN_WARNING, shost, "I/O port address "
+ "modified\n");
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+ "enabled\n");
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ shost_printk(KERN_WARNING, shost, "tag queuing enabled w/o "
+ "disconnects\n");
+ break;
+ default:
+ shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+ warn_code);
+ break;
}
- return;
-}
-/*
- * Copy 4 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when writen to LRAM.
- */
-static void
-AscMemDWordCopyPtrToLram(PortAddr iop_base,
- ushort s_addr, uchar *s_buffer, int dwords)
-{
- int i;
+ if (asc_dvc->err_code != 0)
+ shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+ "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 4 * dwords; i += 4) {
- outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
- outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
- }
- return;
+ return asc_dvc->err_code;
}
-/*
- * Copy 2 bytes from LRAM.
- *
- * The source data is assumed to be in little-endian order in LRAM
- * and is maintained in little-endian order when written to memory.
- */
-static void
-AscMemWordCopyPtrFromLram(PortAddr iop_base,
- ushort s_addr, uchar *d_buffer, int words)
+static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
{
- int i;
- ushort word;
+ struct asc_board *board = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+ PortAddr iop_base = asc_dvc->iop_base;
+ unsigned short cfg_msw;
+ unsigned short warn_code = 0;
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- word = inpw(iop_base + IOP_RAM_DATA);
- d_buffer[i] = word & 0xff;
- d_buffer[i + 1] = (word >> 8) & 0xff;
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+ if (asc_dvc->err_code != 0)
+ return asc_dvc->err_code;
+ if (!AscFindSignature(asc_dvc->iop_base)) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return asc_dvc->err_code;
}
- return;
-}
-
-static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
-{
- ASC_DCNT sum;
- int i;
- sum = 0L;
- for (i = 0; i < words; i++, s_addr += 2) {
- sum += AscReadLramWord(iop_base, s_addr);
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
}
- return (sum);
-}
-
-static void
-AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
-{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < words; i++) {
- AscSetChipLramData(iop_base, set_wval);
+ if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+ asc_dvc->cfg->cmd_qng_enabled) {
+ asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
}
- return;
-}
-
-/*
- * --- Adv Library Functions
- */
-
-/* a_mcode.h */
-
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc3550_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
- 0x01, 0x00, 0x48, 0xe4,
- 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
- 0x28, 0x0e, 0x9e, 0xe7,
- 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
- 0x55, 0xf0, 0x01, 0xf6,
- 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
- 0x00, 0xec, 0x85, 0xf0,
- 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
- 0x86, 0xf0, 0xb4, 0x00,
- 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
- 0xaa, 0x18, 0x02, 0x80,
- 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
- 0x00, 0x57, 0x01, 0xea,
- 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
- 0x03, 0xe6, 0xb6, 0x00,
- 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
- 0x02, 0x4a, 0xb9, 0x54,
- 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
- 0x3e, 0x00, 0x80, 0x00,
- 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
- 0x74, 0x01, 0x76, 0x01,
- 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
- 0x4c, 0x1c, 0xbb, 0x55,
- 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
- 0x03, 0xf7, 0x06, 0xf7,
- 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
- 0x30, 0x13, 0x64, 0x15,
- 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
- 0x04, 0xea, 0x5d, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
- 0xcc, 0x00, 0x20, 0x01,
- 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
- 0x40, 0x13, 0x30, 0x1c,
- 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xa7, 0xf0,
- 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
- 0xa4, 0x00, 0xb5, 0x00,
- 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
- 0x14, 0x0e, 0x02, 0x10,
- 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
- 0x10, 0x15, 0x14, 0x15,
- 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
- 0x91, 0x44, 0x0a, 0x45,
- 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
- 0x83, 0x59, 0x05, 0xe6,
- 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
- 0x02, 0xfa, 0x03, 0xfa,
- 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
- 0x9e, 0x00, 0xa8, 0x00,
- 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
- 0x7a, 0x01, 0xc0, 0x01,
- 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
- 0x69, 0x08, 0xba, 0x08,
- 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
- 0xf1, 0x10, 0x06, 0x12,
- 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
- 0x8a, 0x15, 0xc6, 0x17,
- 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
- 0x0e, 0x47, 0x48, 0x47,
- 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
- 0x14, 0x56, 0x77, 0x57,
- 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
- 0xf0, 0x29, 0x02, 0xfe,
- 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
- 0xfe, 0x80, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x0f,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xcf,
- 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
- 0x0b, 0x3c, 0x2a, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf0, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
- 0x02, 0xfe, 0xd4, 0x0c,
- 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
- 0x1c, 0x05, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
- 0xf0, 0xfe, 0x86, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
- 0xfe, 0x46, 0xf0, 0xfe,
- 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
- 0x44, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
- 0xa0, 0x17, 0x06, 0x18,
- 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
- 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
- 0x0a, 0x6b, 0x01, 0x9e,
- 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
- 0x01, 0x82, 0xfe, 0xbd,
- 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
- 0x58, 0x1c, 0x17, 0x06,
- 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
- 0xfe, 0x94, 0x02, 0xfe,
- 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
- 0x01, 0xfe, 0x54, 0x0f,
- 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
- 0x69, 0x10, 0x17, 0x06,
- 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
- 0xf6, 0xc7, 0x01, 0xfe,
- 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
- 0x02, 0x29, 0x0a, 0x40,
- 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
- 0x58, 0x0a, 0x99, 0x01,
- 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
- 0x2a, 0x46, 0xfe, 0x02,
- 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
- 0x01, 0xfe, 0x07, 0x4b,
- 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
- 0xfe, 0x56, 0x03, 0xfe,
- 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
- 0xfe, 0x9f, 0xf0, 0xfe,
- 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
- 0x1c, 0xeb, 0x09, 0x04,
- 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
- 0x01, 0x0e, 0xac, 0x75,
- 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
- 0xfe, 0x82, 0xf0, 0xfe,
- 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
- 0x32, 0x1f, 0xfe, 0xb4,
- 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
- 0x0a, 0xf0, 0xfe, 0x7a,
- 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
- 0x01, 0x33, 0x8f, 0xfe,
- 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
- 0xf7, 0xfe, 0x48, 0x1c,
- 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
- 0x0a, 0xca, 0x01, 0x0e,
- 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
- 0x2c, 0x01, 0x33, 0x8f,
- 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
- 0xfe, 0x3c, 0x04, 0x1f,
- 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
- 0x12, 0x2b, 0xff, 0x02,
- 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
- 0x22, 0x30, 0x2e, 0xd5,
- 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
- 0xfe, 0x4c, 0x54, 0x64,
- 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
- 0xfe, 0x2a, 0x13, 0x2f,
- 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
- 0xd3, 0xfa, 0xef, 0x86,
- 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
- 0x1d, 0xfe, 0x1c, 0x12,
- 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
- 0x70, 0x0c, 0x02, 0x22,
- 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
- 0x01, 0x33, 0x02, 0x29,
- 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
- 0x80, 0xfe, 0x31, 0xe4,
- 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
- 0xfe, 0x70, 0x12, 0x49,
- 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
- 0x80, 0x05, 0xfe, 0x31,
- 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
- 0x28, 0xfe, 0x42, 0x12,
- 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
- 0x11, 0xfe, 0xe3, 0x00,
- 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
- 0x64, 0x05, 0x83, 0x24,
- 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
- 0x09, 0x48, 0x01, 0x08,
- 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
- 0x86, 0x24, 0x06, 0x12,
- 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
- 0x01, 0xa7, 0x14, 0x92,
- 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
- 0x02, 0x22, 0x05, 0xfe,
- 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
- 0x47, 0x01, 0xa7, 0x26,
- 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
- 0x01, 0xfe, 0xaa, 0x14,
- 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
- 0x05, 0x50, 0xb4, 0x0c,
- 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
- 0x13, 0x01, 0xfe, 0x14,
- 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
- 0xff, 0x02, 0x00, 0x57,
- 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
- 0x72, 0x06, 0x49, 0x04,
- 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
- 0x06, 0x11, 0x9a, 0x01,
- 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
- 0x01, 0xa7, 0xec, 0x72,
- 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
- 0xfe, 0x0a, 0xf0, 0xfe,
- 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
- 0x8d, 0x81, 0x02, 0x22,
- 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
- 0x01, 0x08, 0x15, 0x00,
- 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
- 0x00, 0x02, 0xfe, 0x32,
- 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
- 0xfe, 0x1b, 0x00, 0x01,
- 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
- 0x08, 0x15, 0x06, 0x01,
- 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
- 0x9a, 0x81, 0x4b, 0x1d,
- 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
- 0x45, 0xfe, 0x32, 0x12,
- 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
- 0xfe, 0x32, 0x07, 0x8d,
- 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
- 0x06, 0x15, 0x19, 0x02,
- 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x77, 0xfe, 0xca,
- 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
- 0x10, 0xfe, 0x0e, 0x12,
- 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
- 0x83, 0xe7, 0xc4, 0xa1,
- 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
- 0x40, 0x12, 0x58, 0x01,
- 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
- 0x51, 0x83, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
- 0xfe, 0x40, 0x50, 0xfe,
- 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
- 0xfe, 0x2a, 0x12, 0xfe,
- 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
- 0x85, 0x01, 0xa8, 0xfe,
- 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
- 0x18, 0x57, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
- 0x0c, 0x39, 0x18, 0x3a,
- 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
- 0x11, 0x65, 0xfe, 0x48,
- 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
- 0xdd, 0xb8, 0xfe, 0x80,
- 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
- 0xfe, 0x7a, 0x08, 0x8d,
- 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
- 0x10, 0x61, 0x04, 0x06,
- 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
- 0x12, 0xfe, 0x2e, 0x1c,
- 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
- 0x52, 0x12, 0xfe, 0x2c,
- 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
- 0x08, 0xfe, 0x8a, 0x10,
- 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
- 0x24, 0x0a, 0xab, 0xfe,
- 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
- 0x1c, 0x12, 0xb5, 0xfe,
- 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
- 0x1c, 0x06, 0x16, 0x9d,
- 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
- 0x14, 0x92, 0x01, 0x33,
- 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
- 0xfe, 0x74, 0x18, 0x1c,
- 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
- 0x01, 0xe6, 0x1e, 0x27,
- 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
- 0x09, 0x04, 0x6a, 0xfe,
- 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
- 0xfe, 0x83, 0x80, 0xfe,
- 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
- 0x27, 0xfe, 0x40, 0x59,
- 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
- 0x7c, 0xbe, 0x54, 0xbf,
- 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
- 0x79, 0x56, 0x68, 0x57,
- 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
- 0xa2, 0x23, 0x0c, 0x7b,
- 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
- 0x16, 0xd7, 0x79, 0x39,
- 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
- 0xfe, 0x10, 0x58, 0xfe,
- 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
- 0x19, 0x16, 0xd7, 0x09,
- 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
- 0xfe, 0x10, 0x90, 0xfe,
- 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
- 0x11, 0x9b, 0x09, 0x04,
- 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
- 0xfe, 0x0c, 0x58, 0xfe,
- 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
- 0x0b, 0xfe, 0x1a, 0x12,
- 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
- 0x14, 0x7a, 0x01, 0x33,
- 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
- 0xfe, 0xed, 0x19, 0xbf,
- 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
- 0x34, 0xfe, 0x74, 0x10,
- 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
- 0x84, 0x05, 0xcb, 0x1c,
- 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
- 0xf0, 0xfe, 0xc4, 0x0a,
- 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
- 0xce, 0xf0, 0xfe, 0xca,
- 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
- 0x22, 0x00, 0x02, 0x5a,
- 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
- 0xfe, 0xd0, 0xf0, 0xfe,
- 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
- 0x4c, 0xfe, 0x10, 0x10,
- 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
- 0x2a, 0x13, 0xfe, 0x4e,
- 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
- 0x16, 0x32, 0x2a, 0x73,
- 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
- 0x32, 0x8c, 0xfe, 0x48,
- 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
- 0xdb, 0x10, 0x11, 0xfe,
- 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
- 0x22, 0x30, 0x2e, 0xd8,
- 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
- 0x45, 0x0f, 0xfe, 0x42,
- 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
- 0x09, 0x04, 0x0b, 0xfe,
- 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
- 0x00, 0x21, 0xfe, 0xa6,
- 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
- 0xfe, 0xe2, 0x10, 0x01,
- 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
- 0x01, 0x6f, 0x02, 0x29,
- 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
- 0x01, 0x86, 0x3e, 0x0b,
- 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
- 0x3e, 0x0b, 0x0f, 0xfe,
- 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
- 0xe8, 0x59, 0x11, 0x2d,
- 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
- 0x04, 0x0b, 0x84, 0x3e,
- 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
- 0x09, 0x04, 0x1b, 0xfe,
- 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
- 0x1c, 0x1c, 0xfe, 0x9d,
- 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
- 0xfe, 0x15, 0x00, 0xfe,
- 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
- 0x0f, 0xfe, 0x47, 0x00,
- 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
- 0xab, 0x70, 0x05, 0x6b,
- 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
- 0x1c, 0x42, 0x59, 0x01,
- 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
- 0x00, 0x37, 0x97, 0x01,
- 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
- 0x1d, 0xfe, 0xce, 0x45,
- 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
- 0x57, 0x05, 0x51, 0xfe,
- 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
- 0x46, 0x09, 0x04, 0x1d,
- 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
- 0x99, 0x01, 0x0e, 0xfe,
- 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
- 0xfe, 0xee, 0x14, 0xee,
- 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
- 0x13, 0x02, 0x29, 0x1e,
- 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
- 0xce, 0x1e, 0x2d, 0x47,
- 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
- 0x12, 0x4d, 0x01, 0xfe,
- 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
- 0xf0, 0x0d, 0xfe, 0x02,
- 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
- 0xf6, 0xfe, 0x34, 0x01,
- 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
- 0xaf, 0xfe, 0x02, 0xea,
- 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
- 0x05, 0xfe, 0x38, 0x01,
- 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
- 0x0c, 0xfe, 0x62, 0x01,
- 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
- 0x03, 0x23, 0x03, 0x1e,
- 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
- 0x71, 0x13, 0xfe, 0x24,
- 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
- 0xdc, 0xfe, 0x73, 0x57,
- 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
- 0x80, 0x5d, 0x03, 0xfe,
- 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
- 0x75, 0x03, 0x09, 0x04,
- 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
- 0xfe, 0x1e, 0x80, 0xe1,
- 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
- 0x90, 0xa3, 0xfe, 0x3c,
- 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
- 0x16, 0x2f, 0x07, 0x2d,
- 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
- 0xe8, 0x11, 0xfe, 0xe9,
- 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
- 0x1e, 0x1c, 0xfe, 0x14,
- 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
- 0x09, 0x04, 0x4f, 0xfe,
- 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
- 0x40, 0x12, 0x20, 0x63,
- 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
- 0x1c, 0x05, 0xfe, 0xac,
- 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
- 0xfe, 0xb0, 0x00, 0xfe,
- 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
- 0x24, 0x69, 0x12, 0xc9,
- 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
- 0x90, 0x4d, 0xfe, 0x91,
- 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
- 0xfe, 0x90, 0x4d, 0xfe,
- 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
- 0x46, 0x1e, 0x20, 0xed,
- 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
- 0x70, 0xfe, 0x14, 0x1c,
- 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
- 0xfe, 0x07, 0xe6, 0x1d,
- 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
- 0xfa, 0xef, 0xfe, 0x42,
- 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
- 0xfe, 0x36, 0x12, 0xf0,
- 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
- 0x3d, 0x75, 0x07, 0x10,
- 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
- 0x10, 0x07, 0x7e, 0x45,
- 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
- 0xfe, 0x01, 0xec, 0x97,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
- 0x27, 0x01, 0xda, 0xfe,
- 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
- 0xfe, 0x48, 0x12, 0x07,
- 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
- 0xfe, 0x3e, 0x11, 0x07,
- 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
- 0x11, 0x07, 0x19, 0xfe,
- 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
- 0x01, 0x08, 0x8c, 0x43,
- 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
- 0x7e, 0x02, 0x29, 0x2b,
- 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
- 0xfc, 0x10, 0x09, 0x04,
- 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
- 0xc6, 0x10, 0x1e, 0x58,
- 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
- 0x54, 0x18, 0x55, 0x23,
- 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
- 0xa5, 0xc0, 0x38, 0xc1,
- 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
- 0x05, 0xfa, 0x4e, 0xfe,
- 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
- 0x0c, 0x56, 0x18, 0x57,
- 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
- 0x00, 0x56, 0xfe, 0xa1,
- 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
- 0x58, 0xfe, 0x1f, 0x40,
- 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
- 0x31, 0x57, 0xfe, 0x44,
- 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
- 0x8a, 0x50, 0x05, 0x39,
- 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
- 0x12, 0xcd, 0x02, 0x5b,
- 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
- 0x2f, 0x07, 0x9b, 0x21,
- 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
- 0x39, 0x68, 0x3a, 0xfe,
- 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
- 0x51, 0xfe, 0x8e, 0x51,
- 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
- 0x01, 0x08, 0x25, 0x32,
- 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
- 0x3b, 0x02, 0x44, 0x01,
- 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
- 0x01, 0x08, 0x1f, 0xa2,
- 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
- 0x00, 0x28, 0x84, 0x49,
- 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
- 0x78, 0x3d, 0xfe, 0xda,
- 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
- 0x05, 0xc6, 0x28, 0x84,
- 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
- 0x14, 0xfe, 0x03, 0x17,
- 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
- 0xfe, 0xaa, 0x14, 0x02,
- 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
- 0x21, 0x44, 0x01, 0xfe,
- 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
- 0xfe, 0x4a, 0xf4, 0x0b,
- 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
- 0x85, 0x02, 0x5b, 0x05,
- 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
- 0xd8, 0x14, 0x02, 0x5c,
- 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
- 0x01, 0x08, 0x23, 0x72,
- 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
- 0x12, 0x5e, 0x2b, 0x01,
- 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
- 0x1c, 0xfe, 0xff, 0x7f,
- 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
- 0x57, 0x48, 0x8b, 0x1c,
- 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
- 0x00, 0x57, 0x48, 0x8b,
- 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
- 0x03, 0x0a, 0x50, 0x01,
- 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
- 0x54, 0xfe, 0x00, 0xf4,
- 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
- 0x03, 0x7c, 0x63, 0x27,
- 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
- 0xfe, 0x82, 0x4a, 0xfe,
- 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
- 0x42, 0x48, 0x5f, 0x60,
- 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
- 0x1f, 0xfe, 0xa2, 0x14,
- 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
- 0xcc, 0x12, 0x49, 0x04,
- 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
- 0xe8, 0x13, 0x3b, 0x13,
- 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
- 0xa1, 0xff, 0x02, 0x83,
- 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
- 0x13, 0x06, 0xfe, 0x56,
- 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
- 0x64, 0x00, 0x17, 0x93,
- 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
- 0xc8, 0x00, 0x8e, 0xe4,
- 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
- 0x01, 0xba, 0xfe, 0x4e,
- 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
- 0xfe, 0x60, 0x14, 0xfe,
- 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
- 0xfe, 0x22, 0x13, 0x1c,
- 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
- 0xfe, 0x9c, 0x14, 0xb7,
- 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
- 0xfe, 0x9c, 0x14, 0xb7,
- 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
- 0xfe, 0xb4, 0x56, 0xfe,
- 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
- 0xe5, 0x15, 0x0b, 0x01,
- 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
- 0x49, 0x01, 0x08, 0x03,
- 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
- 0x15, 0x06, 0x01, 0x08,
- 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
- 0x4a, 0x01, 0x08, 0x03,
- 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
- 0xfe, 0x49, 0xf4, 0x00,
- 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
- 0x08, 0x2f, 0x07, 0xfe,
- 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
- 0x01, 0x43, 0x1e, 0xcd,
- 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
- 0xed, 0x88, 0x07, 0x10,
- 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
- 0x80, 0x01, 0x0e, 0x88,
- 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
- 0x88, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
- 0xfe, 0x80, 0x80, 0xf2,
- 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
- 0x01, 0x82, 0x03, 0x17,
- 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
- 0xfe, 0x24, 0x1c, 0xfe,
- 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
- 0x91, 0x1d, 0x66, 0xfe,
- 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
- 0xda, 0x10, 0x17, 0x10,
- 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
- 0x05, 0xfe, 0x66, 0x01,
- 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
- 0xfe, 0x3c, 0x50, 0x66,
- 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
- 0x40, 0x16, 0xfe, 0xb6,
- 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
- 0x10, 0x71, 0xfe, 0x83,
- 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
- 0xfe, 0x62, 0x16, 0xfe,
- 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
- 0xfe, 0x98, 0xe7, 0x00,
- 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
- 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
- 0xc5, 0x90, 0xfe, 0x9a,
- 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
- 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
- 0xfe, 0x1d, 0xf7, 0x4f,
- 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
- 0x47, 0xfe, 0x83, 0x58,
- 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
- 0xfe, 0xdd, 0x00, 0x63,
- 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
- 0x06, 0x37, 0x95, 0xa9,
- 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
- 0x18, 0x1c, 0x1a, 0x5d,
- 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
- 0xe1, 0x10, 0x78, 0x2c,
- 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
- 0x13, 0x3c, 0x8a, 0x0a,
- 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
- 0xe3, 0xfe, 0x00, 0xcc,
- 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
- 0x0e, 0xf2, 0x01, 0x6f,
- 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
- 0xf6, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
- 0x15, 0x00, 0x59, 0x76,
- 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
- 0x11, 0x2d, 0x01, 0x6f,
- 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
- 0xc8, 0xfe, 0x48, 0x55,
- 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
- 0x99, 0x01, 0x0e, 0xf0,
- 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
- 0x75, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
- 0x0e, 0x73, 0x75, 0x03,
- 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
- 0xfe, 0x3a, 0x45, 0x5b,
- 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
- 0xfe, 0x02, 0xe6, 0x1b,
- 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
- 0xfe, 0x94, 0x00, 0xfe,
- 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
- 0xe6, 0x2c, 0xfe, 0x4e,
- 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
- 0x03, 0x07, 0x7a, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
- 0x07, 0x1b, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
- 0x24, 0x2c, 0xdc, 0x07,
- 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
- 0x9f, 0xad, 0x03, 0x14,
- 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
- 0x03, 0x25, 0xfe, 0xca,
- 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
- 0x00, 0x00,
-};
-
-static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
-static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
-
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C0800_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
- 0x01, 0x00, 0x48, 0xe4,
- 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
- 0x1c, 0x0f, 0x00, 0xf6,
- 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
- 0x09, 0xe7, 0x55, 0xf0,
- 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
- 0x18, 0xf4, 0x08, 0x00,
- 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
- 0x86, 0xf0, 0xb1, 0xf0,
- 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
- 0x3c, 0x00, 0xbb, 0x00,
- 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
- 0xba, 0x13, 0x18, 0x40,
- 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
- 0x6e, 0x01, 0x74, 0x01,
- 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
- 0xc0, 0x00, 0x01, 0x01,
- 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
- 0x08, 0x12, 0x02, 0x4a,
- 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
- 0x5d, 0xf0, 0x02, 0xfa,
- 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
- 0x68, 0x01, 0x6a, 0x01,
- 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
- 0x06, 0x13, 0x4c, 0x1c,
- 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
- 0x0f, 0x00, 0x47, 0x00,
- 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
- 0x4e, 0x1c, 0x10, 0x44,
- 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
- 0x05, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
- 0x42, 0x0c, 0x12, 0x0f,
- 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
- 0x00, 0x4e, 0x42, 0x54,
- 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xb8, 0xf0,
- 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
- 0x19, 0x00, 0x33, 0x00,
- 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
- 0xe7, 0x00, 0xe2, 0x03,
- 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
- 0x12, 0x13, 0x24, 0x14,
- 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
- 0x36, 0x1c, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
- 0x3a, 0x55, 0x83, 0x55,
- 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
- 0x0c, 0xf0, 0x04, 0xf8,
- 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
- 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
- 0xc4, 0x01, 0xc6, 0x01,
- 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
- 0x68, 0x08, 0x69, 0x08,
- 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
- 0xed, 0x10, 0xf1, 0x10,
- 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
- 0x1e, 0x13, 0x46, 0x14,
- 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
- 0xca, 0x18, 0xe6, 0x19,
- 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
- 0xf0, 0x2b, 0x02, 0xfe,
- 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
- 0xfe, 0x84, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x11,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xd6,
- 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
- 0x0a, 0x42, 0x2c, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf4, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
- 0x02, 0xfe, 0xc8, 0x0d,
- 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
- 0x1c, 0x03, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
- 0xf0, 0xfe, 0x8a, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
- 0xfe, 0x46, 0xf0, 0xfe,
- 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
- 0x48, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
- 0xaa, 0x18, 0x06, 0x14,
- 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
- 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
- 0x09, 0x70, 0x01, 0xa8,
- 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
- 0x01, 0x87, 0xfe, 0xbd,
- 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
- 0x58, 0x1c, 0x18, 0x06,
- 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
- 0xfe, 0x98, 0x02, 0xfe,
- 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
- 0x01, 0xfe, 0x48, 0x10,
- 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
- 0x69, 0x10, 0x18, 0x06,
- 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
- 0xf6, 0xce, 0x01, 0xfe,
- 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
- 0x82, 0x16, 0x02, 0x2b,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
- 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
- 0x82, 0x16, 0x02, 0x2b,
- 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
- 0xfe, 0x77, 0x57, 0xfe,
- 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
- 0xfe, 0x40, 0x1c, 0x1c,
- 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
- 0x03, 0xfe, 0x11, 0xf0,
- 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
- 0xfe, 0x11, 0x00, 0x02,
- 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
- 0x21, 0x22, 0xa3, 0xb7,
- 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
- 0x12, 0xd1, 0x1c, 0xd9,
- 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
- 0xfe, 0xe4, 0x00, 0x27,
- 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
- 0x06, 0xf0, 0xfe, 0xc8,
- 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
- 0x70, 0x28, 0x17, 0xfe,
- 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
- 0xf9, 0x2c, 0x99, 0x19,
- 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
- 0x74, 0x01, 0xaf, 0x8c,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
- 0x8d, 0x51, 0x64, 0x79,
- 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
- 0xfe, 0x6a, 0x02, 0x02,
- 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
- 0xfe, 0x3c, 0x04, 0x3b,
- 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
- 0x00, 0x10, 0x01, 0x0b,
- 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
- 0xfe, 0x4c, 0x44, 0xfe,
- 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
- 0xda, 0x4f, 0x79, 0x2a,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
- 0xfe, 0x2a, 0x13, 0x32,
- 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
- 0x54, 0x6b, 0xda, 0xfe,
- 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
- 0x08, 0x13, 0x32, 0x07,
- 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
- 0x08, 0x05, 0x06, 0x4d,
- 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
- 0x2d, 0x12, 0xfe, 0xe6,
- 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
- 0x02, 0x2b, 0xfe, 0x42,
- 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
- 0xfe, 0x87, 0x80, 0xfe,
- 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
- 0x07, 0x19, 0xfe, 0x7c,
- 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
- 0x17, 0xfe, 0x90, 0x05,
- 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
- 0xa0, 0x00, 0x28, 0xfe,
- 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
- 0x34, 0xfe, 0x89, 0x48,
- 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
- 0x12, 0xfe, 0xe3, 0x00,
- 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
- 0x70, 0x05, 0x88, 0x25,
- 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
- 0x09, 0x48, 0xff, 0x02,
- 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
- 0x08, 0x53, 0x05, 0xcb,
- 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
- 0x05, 0x1b, 0xfe, 0x22,
- 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
- 0x0d, 0x00, 0x01, 0x36,
- 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
- 0x03, 0x5c, 0x28, 0xfe,
- 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
- 0x05, 0x1f, 0xfe, 0x02,
- 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
- 0x01, 0x4b, 0x12, 0xfe,
- 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
- 0x12, 0x03, 0x45, 0x28,
- 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
- 0x43, 0x48, 0xc4, 0xcc,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
- 0x6e, 0x41, 0x01, 0xb2,
- 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
- 0xfe, 0xcc, 0x15, 0x1d,
- 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
- 0x45, 0xc1, 0x0c, 0x45,
- 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
- 0xe2, 0x00, 0x27, 0xdb,
- 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
- 0xfe, 0x06, 0xf0, 0xfe,
- 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
- 0x16, 0x19, 0x01, 0x0b,
- 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
- 0xfe, 0x99, 0xa4, 0x01,
- 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
- 0x12, 0x08, 0x05, 0x1a,
- 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
- 0x0b, 0x16, 0x00, 0x01,
- 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
- 0xe2, 0x6c, 0x58, 0xbe,
- 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
- 0xfe, 0x09, 0x6f, 0xba,
- 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
- 0xfe, 0x54, 0x07, 0x1c,
- 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
- 0x07, 0x02, 0x24, 0x01,
- 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
- 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
- 0x37, 0x22, 0x20, 0x07,
- 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
- 0xfe, 0x06, 0x10, 0xfe,
- 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
- 0x37, 0x01, 0xb3, 0xb8,
- 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
- 0x50, 0xfe, 0x44, 0x51,
- 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
- 0x14, 0x5f, 0xfe, 0x0c,
- 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
- 0x14, 0x3e, 0xfe, 0x4a,
- 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x0c, 0x60, 0x14,
- 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
- 0xfe, 0x44, 0x90, 0xfe,
- 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
- 0x0c, 0x5e, 0x14, 0x5f,
- 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
- 0x14, 0x3c, 0x21, 0x0c,
- 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
- 0x27, 0xdd, 0xfe, 0x9e,
- 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
- 0x9a, 0x08, 0xc6, 0xfe,
- 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
- 0x95, 0x86, 0x02, 0x24,
- 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
- 0x06, 0xfe, 0x10, 0x12,
- 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
- 0x1c, 0x02, 0xfe, 0x18,
- 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
- 0x2c, 0x1c, 0xfe, 0xaa,
- 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
- 0xde, 0x09, 0xfe, 0xb7,
- 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
- 0xfe, 0xf1, 0x18, 0xfe,
- 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
- 0x14, 0x59, 0xfe, 0x95,
- 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
- 0xfe, 0xf0, 0x08, 0xb5,
- 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
- 0x0b, 0xb6, 0xfe, 0xbf,
- 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
- 0x12, 0xc2, 0xfe, 0xd2,
- 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
- 0x06, 0x17, 0x85, 0xc5,
- 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
- 0x9d, 0x01, 0x36, 0x10,
- 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
- 0x98, 0x80, 0xfe, 0x19,
- 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
- 0xfe, 0x44, 0x54, 0xbe,
- 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
- 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
- 0x9c, 0x3c, 0xfe, 0x6c,
- 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
- 0x3b, 0x40, 0x03, 0x49,
- 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
- 0x8f, 0xfe, 0xe3, 0x54,
- 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
- 0xda, 0x09, 0xfe, 0x8b,
- 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
- 0x0a, 0x3a, 0x49, 0x3b,
- 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
- 0xad, 0xfe, 0x01, 0x59,
- 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
- 0x49, 0x8f, 0xfe, 0xe3,
- 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
- 0x4a, 0x3a, 0x49, 0x3b,
- 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
- 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
- 0xb7, 0xfe, 0x03, 0xa1,
- 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
- 0xfe, 0x86, 0x91, 0x6a,
- 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
- 0x61, 0x0c, 0x7f, 0x14,
- 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
- 0x9b, 0x2e, 0x9c, 0x3c,
- 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
- 0xfa, 0x3c, 0x01, 0xef,
- 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
- 0xe4, 0x08, 0x05, 0x1f,
- 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
- 0x03, 0x5e, 0x29, 0x5f,
- 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
- 0xf4, 0x09, 0x08, 0x05,
- 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
- 0x81, 0x50, 0xfe, 0x10,
- 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
- 0x08, 0x09, 0x12, 0xa6,
- 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
- 0x08, 0x09, 0xfe, 0x0c,
- 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
- 0x08, 0x05, 0x0a, 0xfe,
- 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
- 0xf0, 0xe2, 0x15, 0x7e,
- 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
- 0x57, 0x3d, 0xfe, 0xed,
- 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
- 0x00, 0xff, 0x35, 0xfe,
- 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
- 0x1e, 0x19, 0x8a, 0x03,
- 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
- 0xfe, 0xd1, 0xf0, 0xfe,
- 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
- 0x10, 0xfe, 0xce, 0xf0,
- 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
- 0x10, 0xfe, 0x22, 0x00,
- 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
- 0x02, 0x65, 0xfe, 0xd0,
- 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
- 0x0b, 0x10, 0x58, 0xfe,
- 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
- 0x12, 0x00, 0x2c, 0x0f,
- 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
- 0x0c, 0xbc, 0x17, 0x34,
- 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
- 0x0c, 0x1c, 0x34, 0x94,
- 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
- 0x4b, 0xfe, 0xdb, 0x10,
- 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
- 0x89, 0xf0, 0x24, 0x33,
- 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
- 0x33, 0x31, 0xdf, 0xbc,
- 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
- 0x17, 0xfe, 0x2c, 0x0d,
- 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
- 0x12, 0x55, 0xfe, 0x28,
- 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
- 0x44, 0xfe, 0x28, 0x00,
- 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
- 0x0f, 0x64, 0x12, 0x2f,
- 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
- 0x0a, 0xfe, 0xb4, 0x10,
- 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
- 0xfe, 0x34, 0x46, 0xac,
- 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
- 0x37, 0x01, 0xf5, 0x01,
- 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
- 0xfe, 0x2e, 0x03, 0x08,
- 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
- 0x1a, 0xfe, 0x58, 0x12,
- 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
- 0xfe, 0x50, 0x0d, 0xfe,
- 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
- 0xfe, 0xa9, 0x10, 0x10,
- 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
- 0xfe, 0x13, 0x00, 0xfe,
- 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
- 0x24, 0x00, 0x8c, 0xb5,
- 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
- 0xfe, 0x9d, 0x41, 0xfe,
- 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
- 0xb4, 0x15, 0xfe, 0x31,
- 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
- 0xec, 0xd0, 0xfc, 0x44,
- 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
- 0x4b, 0x91, 0xfe, 0x75,
- 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
- 0x0e, 0xfe, 0x44, 0x48,
- 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
- 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
- 0x2e, 0x03, 0x09, 0x5d,
- 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
- 0xce, 0x47, 0xfe, 0xad,
- 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
- 0x59, 0x13, 0x9f, 0x13,
- 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
- 0xe0, 0x0e, 0x0f, 0x06,
- 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
- 0x3a, 0x01, 0x56, 0xfe,
- 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
- 0x20, 0x4f, 0xfe, 0x05,
- 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
- 0x48, 0xf4, 0x0d, 0xfe,
- 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
- 0x15, 0x1a, 0x39, 0xa0,
- 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
- 0x0c, 0xfe, 0x60, 0x01,
- 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
- 0x06, 0x13, 0x2f, 0x12,
- 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
- 0x22, 0x9f, 0xb7, 0x13,
- 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
- 0xa0, 0xb4, 0xfe, 0xd9,
- 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
- 0xc3, 0xfe, 0x03, 0xdc,
- 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
- 0xfe, 0x00, 0xcc, 0x04,
- 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
- 0xfe, 0x1c, 0x80, 0x07,
- 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
- 0xfe, 0x0c, 0x90, 0xfe,
- 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
- 0x0a, 0xfe, 0x3c, 0x50,
- 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
- 0x16, 0x08, 0x05, 0x1b,
- 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
- 0xfe, 0x2c, 0x13, 0x01,
- 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
- 0x0c, 0xfe, 0x64, 0x01,
- 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
- 0x80, 0x8d, 0xfe, 0x01,
- 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
- 0x22, 0x20, 0xfb, 0x79,
- 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
- 0x03, 0xfe, 0xae, 0x00,
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ }
+#ifdef CONFIG_PCI
+ if (asc_dvc->bus_type & ASC_IS_PCI) {
+ cfg_msw &= 0xFFC0;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+ } else {
+ if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+ (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+ asc_dvc->bug_fix_cntl |=
+ ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ } else
+#endif /* CONFIG_PCI */
+ if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+ == ASC_CHIP_VER_ASYN_BUG) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+ asc_dvc->cfg->chip_scsi_id) {
+ asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+ }
+#ifdef CONFIG_ISA
+ if (asc_dvc->bus_type & ASC_IS_ISA) {
+ AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+ AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+ }
+#endif /* CONFIG_ISA */
- 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
- 0xb2, 0x00, 0xfe, 0x09,
- 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
- 0x45, 0x0f, 0x46, 0x52,
- 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
- 0x0f, 0x44, 0x11, 0x0f,
- 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
- 0x25, 0x11, 0x13, 0x20,
- 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
- 0x18, 0x1c, 0x04, 0x42,
- 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
- 0xf5, 0x13, 0x04, 0x01,
- 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
- 0x13, 0x32, 0x07, 0x2f,
- 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
- 0x41, 0x48, 0xfe, 0x45,
- 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
- 0x07, 0x11, 0xac, 0x09,
- 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
- 0x82, 0x4e, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
- 0xfe, 0x01, 0xec, 0xa2,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
- 0x2a, 0x01, 0xe3, 0xfe,
- 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
- 0xfe, 0x48, 0x12, 0x07,
- 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
- 0xfe, 0x32, 0x12, 0x07,
- 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
- 0x1f, 0xfe, 0x12, 0x12,
- 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
- 0x94, 0x4b, 0x04, 0x2d,
- 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
- 0x32, 0x07, 0xa6, 0xfe,
- 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
- 0x5a, 0xfe, 0x72, 0x12,
- 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
- 0xfe, 0x26, 0x13, 0x03,
- 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
- 0x0c, 0x7f, 0x0c, 0x80,
- 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
- 0x3c, 0xfe, 0x04, 0x55,
- 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
- 0x91, 0x10, 0x03, 0x3f,
- 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
- 0x88, 0x9b, 0x2e, 0x9c,
- 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
- 0x56, 0x0c, 0x5e, 0x14,
- 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
- 0x03, 0x60, 0x29, 0x61,
- 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
- 0x50, 0xfe, 0xc6, 0x50,
- 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
- 0x29, 0x3e, 0xfe, 0x40,
- 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
- 0x2d, 0x01, 0x0b, 0x1d,
- 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
- 0x72, 0x01, 0xaf, 0x1e,
- 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
- 0x0a, 0x55, 0x35, 0xfe,
- 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
- 0x02, 0x72, 0xfe, 0x19,
- 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
- 0x1d, 0xe8, 0x33, 0x31,
- 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
- 0x0b, 0x1c, 0x34, 0x1d,
- 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
- 0x33, 0x31, 0xfe, 0xe8,
- 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
- 0x05, 0x1f, 0x35, 0xa9,
- 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
- 0x14, 0x01, 0xaf, 0x8c,
- 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
- 0x03, 0x45, 0x28, 0x35,
- 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
- 0x03, 0x5c, 0xc1, 0x0c,
- 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
- 0x89, 0x01, 0x0b, 0x1c,
- 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
- 0xfe, 0x42, 0x58, 0xf1,
- 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
- 0xf4, 0x06, 0xea, 0x32,
- 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
- 0x01, 0x0b, 0x26, 0x89,
- 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
- 0x26, 0xfe, 0xd4, 0x13,
- 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
- 0x13, 0x1c, 0xfe, 0xd0,
- 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
- 0x0f, 0x71, 0xff, 0x02,
- 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
- 0x00, 0x5c, 0x04, 0x0f,
- 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
- 0xfe, 0x00, 0x5c, 0x04,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
- 0x02, 0x00, 0x57, 0x52,
- 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
- 0x87, 0x04, 0xfe, 0x03,
- 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
- 0xfe, 0x00, 0x7d, 0xfe,
- 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
- 0x14, 0x5f, 0x57, 0x3f,
- 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
- 0x5a, 0x8d, 0x04, 0x01,
- 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
- 0xfe, 0x96, 0x15, 0x33,
- 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
- 0x0a, 0xfe, 0xc1, 0x59,
- 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
- 0x21, 0x69, 0x1a, 0xee,
- 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
- 0x30, 0xfe, 0x78, 0x10,
- 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
- 0x98, 0xfe, 0x30, 0x00,
- 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
- 0x98, 0xfe, 0x64, 0x00,
- 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
- 0x10, 0x69, 0x06, 0xfe,
- 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
- 0x18, 0x59, 0x0f, 0x06,
- 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
- 0x43, 0xf4, 0x9f, 0xfe,
- 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
- 0x9e, 0xfe, 0xf3, 0x10,
- 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
- 0x17, 0xfe, 0x4d, 0xe4,
- 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
- 0x17, 0xfe, 0x4d, 0xe4,
- 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
- 0xf4, 0x00, 0xe9, 0x91,
- 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
- 0x04, 0x16, 0x06, 0x01,
- 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
- 0x0b, 0x26, 0xf3, 0x76,
- 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
- 0x16, 0x19, 0x01, 0x0b,
- 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
- 0x0b, 0x26, 0xb1, 0x76,
- 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
- 0xfe, 0x48, 0x13, 0xb8,
- 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
- 0xec, 0xfe, 0x27, 0x01,
- 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
- 0x07, 0xfe, 0xe3, 0x00,
- 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
- 0x22, 0xd4, 0x07, 0x06,
- 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
- 0x07, 0x11, 0xae, 0x09,
- 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
- 0x0e, 0x8e, 0xfe, 0x80,
- 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
- 0x09, 0x48, 0x01, 0x0e,
- 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
- 0x80, 0xfe, 0x80, 0x4c,
- 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
- 0x09, 0x5d, 0x01, 0x87,
- 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
- 0x19, 0xde, 0xfe, 0x24,
- 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
- 0x17, 0xad, 0x9a, 0x1b,
- 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
- 0x16, 0xfe, 0xda, 0x10,
- 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
- 0x18, 0x58, 0x03, 0xfe,
- 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
- 0xf4, 0x06, 0xfe, 0x3c,
- 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
- 0x97, 0xfe, 0x38, 0x17,
- 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
- 0x10, 0x18, 0x11, 0x75,
- 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
- 0x2e, 0x97, 0xfe, 0x5a,
- 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
- 0xfe, 0x98, 0xe7, 0x00,
- 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
- 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
- 0xcb, 0x97, 0xfe, 0x92,
- 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
- 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
- 0x03, 0xa1, 0xfe, 0x1d,
- 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
- 0x9a, 0x5b, 0x41, 0xfe,
- 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
- 0x11, 0x12, 0xfe, 0xdd,
- 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
- 0x17, 0x15, 0x06, 0x39,
- 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
- 0xfe, 0x7e, 0x18, 0x1e,
- 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
- 0x12, 0xfe, 0xe1, 0x10,
- 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
- 0x13, 0x42, 0x92, 0x09,
- 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
- 0xf0, 0xfe, 0x00, 0xcc,
- 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
- 0x0e, 0xfe, 0x80, 0x4c,
- 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
- 0x24, 0x12, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
- 0xe7, 0x0a, 0x10, 0xfe,
- 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
- 0x08, 0x54, 0x1b, 0x37,
- 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
- 0x90, 0x3a, 0xce, 0x3b,
- 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
- 0x13, 0xa3, 0x04, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
- 0x44, 0x17, 0xfe, 0xe8,
- 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
- 0x5d, 0x01, 0xa8, 0x09,
- 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
- 0x1c, 0x19, 0x03, 0xfe,
- 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
- 0x6b, 0xfe, 0x2e, 0x19,
- 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
- 0xfe, 0x0b, 0x00, 0x6b,
- 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
- 0x08, 0x10, 0x03, 0xfe,
- 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
- 0x04, 0x68, 0x54, 0xe7,
- 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
- 0x1a, 0xf4, 0xfe, 0x00,
- 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
- 0x04, 0x07, 0x7e, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
- 0x07, 0x1a, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
- 0x25, 0x6d, 0xe5, 0x07,
- 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
- 0xa9, 0xb8, 0x04, 0x15,
- 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
- 0x40, 0x5c, 0x04, 0x1c,
- 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
- 0xf7, 0xfe, 0x82, 0xf0,
- 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
-};
+ asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
-static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
-static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
+ switch (warn_code) {
+ case 0: /* No error. */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ shost_printk(KERN_WARNING, shost, "I/O port address "
+ "modified\n");
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+ "enabled\n");
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ shost_printk(KERN_WARNING, shost, "tag queuing w/o "
+ "disconnects\n");
+ break;
+ default:
+ shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+ warn_code);
+ break;
+ }
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C1600_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
- 0x18, 0xe4, 0x01, 0x00,
- 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
- 0x07, 0x17, 0xc0, 0x5f,
- 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
- 0x85, 0xf0, 0x86, 0xf0,
- 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
- 0x98, 0x57, 0x01, 0xe6,
- 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
- 0x38, 0x54, 0x32, 0xf0,
- 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
- 0x00, 0xe6, 0xb1, 0xf0,
- 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
- 0x06, 0x13, 0x0c, 0x1c,
- 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
- 0xb9, 0x54, 0x00, 0x80,
- 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
- 0x03, 0xe6, 0x01, 0xea,
- 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
- 0x04, 0x13, 0xbb, 0x55,
- 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
- 0xbb, 0x00, 0xc0, 0x00,
- 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
- 0x4c, 0x1c, 0x4e, 0x1c,
- 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
- 0x24, 0x01, 0x3c, 0x01,
- 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
- 0x78, 0x01, 0x7c, 0x01,
- 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
- 0x6e, 0x1e, 0x02, 0x48,
- 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
- 0x03, 0xfc, 0x06, 0x00,
- 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
- 0x30, 0x1c, 0x38, 0x1c,
- 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
- 0x5d, 0xf0, 0xa7, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
- 0x33, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
- 0x79, 0x01, 0x3c, 0x09,
- 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
- 0x40, 0x16, 0x50, 0x16,
- 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
- 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
- 0x9c, 0x00, 0xa4, 0x00,
- 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
- 0xe9, 0x09, 0x5c, 0x0c,
- 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
- 0x42, 0x1d, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
- 0x83, 0x55, 0x83, 0x59,
- 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
- 0x4b, 0xf4, 0x04, 0xf8,
- 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
- 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
- 0x7a, 0x01, 0x82, 0x01,
- 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
- 0x68, 0x08, 0x10, 0x0d,
- 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
- 0xf3, 0x10, 0x06, 0x12,
- 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
- 0xf0, 0x35, 0x05, 0xfe,
- 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
- 0xfe, 0x88, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x13,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xe8,
- 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
- 0x0d, 0x51, 0x37, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf8, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
- 0x05, 0xfe, 0x08, 0x0f,
- 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
- 0x28, 0x1c, 0x03, 0xfe,
- 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
- 0x48, 0xf0, 0xfe, 0x90,
- 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
- 0x02, 0xfe, 0x46, 0xf0,
- 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
- 0xfe, 0x4e, 0x02, 0xfe,
- 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
- 0x0d, 0xa2, 0x1c, 0x07,
- 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
- 0x1c, 0xf5, 0xfe, 0x1e,
- 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
- 0xde, 0x0a, 0x81, 0x01,
- 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
- 0x81, 0x01, 0x5c, 0xfe,
- 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
- 0xfe, 0x58, 0x1c, 0x1c,
- 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
- 0x2b, 0xfe, 0x9e, 0x02,
- 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
- 0x00, 0x47, 0xb8, 0x01,
- 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
- 0x1a, 0x31, 0xfe, 0x69,
- 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
- 0x1e, 0x1e, 0x20, 0x2c,
- 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
- 0x44, 0x15, 0x56, 0x51,
- 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
- 0x01, 0x18, 0x09, 0x00,
- 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
- 0x18, 0xfe, 0xc8, 0x54,
- 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
- 0xfe, 0x02, 0xe8, 0x30,
- 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
- 0xfe, 0xe4, 0x01, 0xfe,
- 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
- 0x26, 0xf0, 0xfe, 0x66,
- 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
- 0xef, 0x10, 0xfe, 0x9f,
- 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
- 0x70, 0x37, 0xfe, 0x48,
- 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
- 0x21, 0xb9, 0xc7, 0x20,
- 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
- 0xe1, 0x2a, 0xeb, 0xfe,
- 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
- 0x15, 0xfe, 0xe4, 0x00,
- 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
- 0xfe, 0x06, 0xf0, 0xfe,
- 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
- 0x03, 0x81, 0x1e, 0x1b,
- 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
- 0xea, 0xfe, 0x46, 0x1c,
- 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
- 0xfe, 0x48, 0x1c, 0x75,
- 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
- 0xe1, 0x01, 0x18, 0x77,
- 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
- 0x8f, 0xfe, 0x70, 0x02,
- 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
- 0x16, 0xfe, 0x4a, 0x04,
- 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
- 0x02, 0x00, 0x10, 0x01,
- 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
- 0xee, 0xfe, 0x4c, 0x44,
- 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
- 0x7b, 0xec, 0x60, 0x8d,
- 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
- 0x0c, 0x06, 0x28, 0xfe,
- 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
- 0x13, 0x34, 0xfe, 0x4c,
- 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
- 0x13, 0x01, 0x0c, 0x06,
- 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
- 0x28, 0xf9, 0x1f, 0x7f,
- 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
- 0xfe, 0xa4, 0x0e, 0x05,
- 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
- 0x9c, 0x93, 0x3a, 0x0b,
- 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
- 0x7d, 0x1d, 0xfe, 0x46,
- 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
- 0xfe, 0x87, 0x83, 0xfe,
- 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
- 0x13, 0x0f, 0xfe, 0x20,
- 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
- 0x12, 0x01, 0x38, 0x06,
- 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
- 0x05, 0xd0, 0x54, 0x01,
- 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
- 0x50, 0x12, 0x5e, 0xff,
- 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
- 0x00, 0x10, 0x2f, 0xfe,
- 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
- 0x38, 0xfe, 0x4a, 0xf0,
- 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
- 0x21, 0x00, 0xf1, 0x2e,
- 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
- 0x10, 0x2f, 0xfe, 0xd0,
- 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
- 0x1c, 0x00, 0x4d, 0x01,
- 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
- 0x28, 0xfe, 0x24, 0x12,
- 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
- 0x0d, 0x00, 0x01, 0x42,
- 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
- 0x03, 0xb6, 0x1e, 0xfe,
- 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
- 0xfe, 0x72, 0x06, 0x0a,
- 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
- 0x19, 0x16, 0xfe, 0x68,
- 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
- 0x03, 0x9a, 0x1e, 0xfe,
- 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
- 0x48, 0xfe, 0x92, 0x06,
- 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
- 0x58, 0xff, 0x02, 0x00,
- 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
- 0xfe, 0xea, 0x06, 0x01,
- 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
- 0xfe, 0xe0, 0x06, 0x15,
- 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
- 0x01, 0x84, 0xfe, 0xae,
- 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
- 0x1e, 0xfe, 0x1a, 0x12,
- 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
- 0x43, 0x48, 0x62, 0x80,
- 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
- 0x36, 0xfe, 0x02, 0xf6,
- 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
- 0xd0, 0x0d, 0x17, 0xfe,
- 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
- 0x9e, 0x15, 0x82, 0x01,
- 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
- 0x57, 0x10, 0xe6, 0x05,
- 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
- 0xfe, 0x9c, 0x32, 0x5f,
- 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
- 0xfe, 0x0a, 0xf0, 0xfe,
- 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
- 0xaf, 0xa0, 0x05, 0x29,
- 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
- 0x00, 0x01, 0x08, 0x14,
- 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
- 0x14, 0x00, 0x05, 0xfe,
- 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
- 0x12, 0xfe, 0x30, 0x13,
- 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
- 0x01, 0x08, 0x14, 0x00,
- 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
- 0x78, 0x4f, 0x0f, 0xfe,
- 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
- 0x28, 0x48, 0xfe, 0x6c,
- 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
- 0x12, 0x53, 0x63, 0x4e,
- 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
- 0x6c, 0x08, 0xaf, 0xa0,
- 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
- 0x05, 0xed, 0xfe, 0x9c,
- 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
- 0x1e, 0xfe, 0x99, 0x58,
- 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
- 0x22, 0x6b, 0x01, 0x0c,
- 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
- 0x1e, 0x47, 0x2c, 0x7a,
- 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
- 0x01, 0x0c, 0x61, 0x65,
- 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
- 0x16, 0xfe, 0x08, 0x50,
- 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
- 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
- 0x01, 0xfe, 0xfe, 0x1e,
- 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
- 0x10, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
- 0x10, 0x6a, 0x22, 0x6b,
- 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
- 0xfe, 0x9f, 0x83, 0x33,
- 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
- 0x3a, 0x0b, 0xfe, 0xc6,
- 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
- 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
- 0x04, 0xfe, 0xc0, 0x93,
- 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
- 0x10, 0x4b, 0x22, 0x4c,
- 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
- 0x4e, 0x11, 0x2f, 0xfe,
- 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
- 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
- 0xd3, 0xfe, 0x42, 0x0a,
- 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
- 0x05, 0x29, 0x01, 0x41,
- 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
- 0xfe, 0x14, 0x12, 0x01,
- 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
- 0x2e, 0x1c, 0x05, 0xfe,
- 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
- 0xfe, 0x2c, 0x1c, 0xfe,
- 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
- 0x92, 0x10, 0xc4, 0xf6,
- 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
- 0xe7, 0x10, 0xfe, 0x2b,
- 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
- 0xac, 0xfe, 0xd2, 0xf0,
- 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
- 0x1b, 0xbf, 0xd4, 0x5b,
- 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
- 0x5e, 0x32, 0x1f, 0x7f,
- 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
- 0x05, 0x70, 0xfe, 0x74,
- 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
- 0x0f, 0x4d, 0x01, 0xfe,
- 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
- 0x0d, 0x2b, 0xfe, 0xe2,
- 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
- 0xfe, 0x88, 0x13, 0x21,
- 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
- 0x83, 0x83, 0xfe, 0xc9,
- 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
- 0x91, 0x04, 0xfe, 0x84,
- 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
- 0xfe, 0xcb, 0x57, 0x0b,
- 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
- 0x6a, 0x3b, 0x6b, 0x10,
- 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
- 0x20, 0x6e, 0xdb, 0x64,
- 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
- 0xfe, 0x04, 0xfa, 0x64,
- 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
- 0x10, 0x98, 0x91, 0x6c,
- 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
- 0x4b, 0x7e, 0x4c, 0x01,
- 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
- 0x58, 0xfe, 0x91, 0x58,
- 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
- 0x1b, 0x40, 0x01, 0x0c,
- 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
- 0xfe, 0x10, 0x90, 0x04,
- 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
- 0x79, 0x0b, 0x0e, 0xfe,
- 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
- 0x01, 0x0c, 0x06, 0x0d,
- 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
- 0x0c, 0x58, 0xfe, 0x8d,
- 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
- 0x83, 0x33, 0x0b, 0x0e,
- 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
- 0x19, 0xfe, 0x19, 0x41,
- 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
- 0x19, 0xfe, 0x44, 0x00,
- 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
- 0x4c, 0xfe, 0x0c, 0x51,
- 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
- 0x76, 0x10, 0xac, 0xfe,
- 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
- 0xe3, 0x23, 0x07, 0xfe,
- 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
- 0xcc, 0x0c, 0x1f, 0x92,
- 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
- 0x0c, 0xfe, 0x3e, 0x10,
- 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
- 0xfe, 0xcb, 0xf0, 0xfe,
- 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
- 0xf4, 0x0c, 0x19, 0x94,
- 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
- 0xfe, 0xcc, 0xf0, 0xef,
- 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
- 0x4e, 0x11, 0x2f, 0xfe,
- 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
- 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
- 0x2f, 0xfe, 0x3e, 0x0d,
- 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
- 0xd2, 0x9f, 0xd3, 0x9f,
- 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
- 0xc5, 0x75, 0xd7, 0x99,
- 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
- 0x9c, 0x2f, 0xfe, 0x8c,
- 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
- 0x42, 0x00, 0x05, 0x70,
- 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
- 0x0d, 0xfe, 0x44, 0x13,
- 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
- 0xfe, 0xda, 0x0e, 0x0a,
- 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
- 0x10, 0x01, 0xfe, 0xf4,
- 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
- 0x15, 0x56, 0x01, 0x85,
- 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
- 0xcc, 0x10, 0x01, 0xa7,
- 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
- 0xfe, 0x99, 0x83, 0xfe,
- 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
- 0x43, 0x00, 0xfe, 0xa2,
- 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
- 0x00, 0x1d, 0x40, 0x15,
- 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
- 0xfe, 0x3a, 0x03, 0x01,
- 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
- 0x76, 0x06, 0x12, 0xfe,
- 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
- 0xfe, 0x9d, 0xf0, 0xfe,
- 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
- 0x0c, 0x61, 0x12, 0x44,
- 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
- 0xfe, 0x2e, 0x10, 0x19,
- 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
- 0xfe, 0x41, 0x00, 0xa2,
- 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
- 0xea, 0x4f, 0xfe, 0x04,
- 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
- 0x35, 0xfe, 0x12, 0x1c,
- 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
- 0xfe, 0xd4, 0x11, 0x05,
- 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
- 0xce, 0x45, 0x31, 0x51,
- 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
- 0x67, 0xfe, 0x98, 0x56,
- 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
- 0x0c, 0x06, 0x28, 0xfe,
- 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
- 0xfe, 0xfa, 0x14, 0xfe,
- 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
- 0xfe, 0xe0, 0x14, 0xfe,
- 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
- 0xfe, 0xad, 0x13, 0x05,
- 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
- 0xe7, 0xfe, 0x08, 0x1c,
- 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
- 0x48, 0x55, 0xa5, 0x3b,
- 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
- 0xf0, 0x1a, 0x03, 0xfe,
- 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
- 0xec, 0xe7, 0x53, 0x00,
- 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
- 0x01, 0xfe, 0x62, 0x1b,
- 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
- 0xea, 0xe7, 0x53, 0x92,
- 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
- 0xfe, 0x38, 0x01, 0x23,
- 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
- 0x01, 0x01, 0xfe, 0x1e,
- 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
- 0x26, 0x02, 0x21, 0x96,
- 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
- 0xc3, 0xfe, 0xe1, 0x10,
- 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
- 0xfe, 0x03, 0xdc, 0xfe,
- 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
- 0x00, 0xcc, 0x02, 0xfe,
- 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
- 0x0f, 0xfe, 0x1c, 0x80,
- 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
- 0x0f, 0xfe, 0x1e, 0x80,
- 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
- 0x1d, 0x80, 0x04, 0xfe,
- 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
- 0x1e, 0xac, 0xfe, 0x14,
- 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
- 0x1f, 0xfe, 0x30, 0xf4,
- 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
- 0x56, 0xfb, 0x01, 0xfe,
- 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
- 0xfe, 0x00, 0x1d, 0x15,
- 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
- 0x22, 0x1b, 0xfe, 0x1e,
- 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
- 0x96, 0x90, 0x04, 0xfe,
- 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
- 0x01, 0x01, 0x0c, 0x06,
- 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
- 0x0e, 0x77, 0xfe, 0x01,
- 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
- 0x21, 0x2c, 0xfe, 0x00,
- 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
- 0x06, 0x58, 0x03, 0xfe,
- 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
- 0x03, 0xfe, 0xb2, 0x00,
- 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
- 0x66, 0x10, 0x55, 0x10,
- 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
- 0x54, 0x2b, 0xfe, 0x88,
- 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
- 0x91, 0x54, 0x2b, 0xfe,
- 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
- 0x00, 0x40, 0x8d, 0x2c,
- 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
- 0x12, 0x1c, 0x75, 0xfe,
- 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
- 0x14, 0xfe, 0x0e, 0x47,
- 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
- 0xa7, 0x90, 0x34, 0x60,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
- 0x09, 0x56, 0xfe, 0x34,
- 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
- 0xfe, 0x45, 0x48, 0x01,
- 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
- 0x09, 0x1a, 0xa5, 0x0a,
- 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
- 0xfe, 0x14, 0x56, 0xfe,
- 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
- 0xec, 0xb8, 0xfe, 0x9e,
- 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
- 0xf4, 0xfe, 0xdd, 0x10,
- 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
- 0x12, 0x09, 0x0d, 0xfe,
- 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
- 0x13, 0x09, 0xfe, 0x23,
- 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
- 0x24, 0xfe, 0x12, 0x12,
- 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
- 0xae, 0x41, 0x02, 0x32,
- 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
- 0x35, 0x32, 0x01, 0x43,
- 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
- 0x13, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
- 0xe5, 0x55, 0xb0, 0xfe,
- 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
- 0xfe, 0xb6, 0x0e, 0x10,
- 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
- 0x88, 0x20, 0x6e, 0x01,
- 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
- 0x55, 0xfe, 0x04, 0xfa,
- 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
- 0xfe, 0x40, 0x56, 0xfe,
- 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
- 0x44, 0x55, 0xfe, 0xe5,
- 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
- 0x68, 0x22, 0x69, 0x01,
- 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
- 0x6b, 0xfe, 0x2c, 0x50,
- 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
- 0x50, 0x03, 0x68, 0x3b,
- 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
- 0x40, 0x50, 0xfe, 0xc2,
- 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
- 0x16, 0x3d, 0x27, 0x25,
- 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
- 0xa6, 0x23, 0x3f, 0x1b,
- 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
- 0xfe, 0x0a, 0x55, 0x31,
- 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
- 0x51, 0x05, 0x72, 0x01,
- 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
- 0x2a, 0x3c, 0x16, 0xc0,
- 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
- 0xfe, 0x66, 0x15, 0x05,
- 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
- 0x2b, 0x3d, 0x01, 0x08,
- 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
- 0xb6, 0x1e, 0x83, 0x01,
- 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
- 0x07, 0x90, 0x3f, 0x01,
- 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
- 0x01, 0x43, 0x09, 0x82,
- 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
- 0x05, 0x72, 0xfe, 0xc0,
- 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
- 0x32, 0x01, 0x08, 0x17,
- 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
- 0x3d, 0x27, 0x25, 0xbd,
- 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
- 0xe8, 0x14, 0x01, 0xa6,
- 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
- 0x0e, 0x12, 0x01, 0x43,
- 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
- 0x01, 0x08, 0x17, 0x73,
- 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
- 0x27, 0x25, 0xbd, 0x09,
- 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
- 0xb6, 0x14, 0x86, 0xa8,
- 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
- 0x82, 0x4e, 0x05, 0x72,
- 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
- 0xfe, 0xc0, 0x19, 0x05,
- 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
- 0xcc, 0x01, 0x08, 0x26,
- 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
- 0xcc, 0x15, 0x5e, 0x32,
- 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
- 0xad, 0x23, 0xfe, 0xff,
- 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
- 0x00, 0x57, 0x52, 0xad,
- 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
- 0x02, 0x00, 0x57, 0x52,
- 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
- 0x02, 0x13, 0x58, 0xff,
- 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
- 0x5c, 0x0a, 0x55, 0x01,
- 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
- 0xff, 0x03, 0x00, 0x54,
- 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
- 0x7c, 0x3a, 0x0b, 0x0e,
- 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
- 0xfe, 0x1a, 0xf7, 0x00,
- 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
- 0xda, 0x6d, 0x02, 0xfe,
- 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
- 0x02, 0x01, 0xc6, 0xfe,
- 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
- 0x25, 0xbe, 0x01, 0x08,
- 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
- 0x03, 0x9a, 0x1e, 0xfe,
- 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
- 0x48, 0xfe, 0x08, 0x17,
- 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
- 0x17, 0x4d, 0x13, 0x07,
- 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
- 0xff, 0x02, 0x83, 0x55,
- 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
- 0x17, 0x1c, 0x63, 0x13,
- 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
- 0x00, 0xb0, 0xfe, 0x80,
- 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
- 0x53, 0x07, 0xfe, 0x60,
- 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
- 0x00, 0x1c, 0x95, 0x13,
- 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
- 0xfe, 0x43, 0xf4, 0x96,
- 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
- 0xf4, 0x94, 0xf6, 0x8b,
- 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
- 0xda, 0x17, 0x62, 0x49,
- 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
- 0x71, 0x50, 0x26, 0xfe,
- 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
- 0x58, 0x02, 0x50, 0x13,
- 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
- 0x25, 0xbe, 0xfe, 0x03,
- 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
- 0x0a, 0x01, 0x08, 0x16,
- 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
- 0x01, 0x08, 0x16, 0xa9,
- 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
- 0x08, 0x16, 0xa9, 0x27,
- 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
- 0x01, 0x38, 0x06, 0x24,
- 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
- 0x78, 0x03, 0x9a, 0x1e,
- 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
- 0xfe, 0x40, 0x5a, 0x23,
- 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
- 0x80, 0x48, 0xfe, 0xaa,
- 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
- 0xfe, 0xac, 0x1d, 0xfe,
- 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
- 0x43, 0x48, 0x2d, 0x93,
- 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
- 0x36, 0xfe, 0x34, 0xf4,
- 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
- 0x28, 0x10, 0xfe, 0xc0,
- 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
- 0x18, 0x45, 0xfe, 0x1c,
- 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
- 0x19, 0xfe, 0x04, 0xf4,
- 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
- 0x21, 0xfe, 0x7f, 0x01,
- 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
- 0x7e, 0x01, 0xfe, 0xc8,
- 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
- 0x21, 0xfe, 0x81, 0x01,
- 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
- 0x13, 0x0d, 0x02, 0x14,
- 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
- 0xfe, 0x82, 0x19, 0x14,
- 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
- 0x08, 0x02, 0x14, 0x07,
- 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
- 0x01, 0x08, 0x17, 0xc1,
- 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
- 0x08, 0x02, 0x50, 0x02,
- 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
- 0x14, 0x12, 0x01, 0x08,
- 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
- 0x08, 0x17, 0x74, 0xfe,
- 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
- 0x74, 0x5f, 0xcc, 0x01,
- 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
- 0xfe, 0x49, 0xf4, 0x00,
- 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
- 0x02, 0x00, 0x10, 0x2f,
- 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
- 0x16, 0xfe, 0x64, 0x1a,
- 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
- 0x61, 0x07, 0x44, 0x02,
- 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
- 0x13, 0x0a, 0x9d, 0x01,
- 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
- 0xfe, 0x80, 0xe7, 0x1a,
- 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
- 0x0a, 0x5a, 0x01, 0x18,
- 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
- 0x7e, 0x1e, 0xfe, 0x80,
- 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
- 0xfe, 0x80, 0x4c, 0x0a,
- 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
- 0xfe, 0x19, 0xde, 0xfe,
- 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
- 0x2a, 0x1c, 0xfa, 0xb3,
- 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
- 0xf4, 0x1a, 0xfe, 0xfa,
- 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
- 0xfe, 0x18, 0x58, 0x03,
- 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
- 0xfe, 0x30, 0xf4, 0x07,
- 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
- 0xf7, 0x24, 0xb1, 0xfe,
- 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
- 0xfe, 0xba, 0x10, 0x1c,
- 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
- 0x1d, 0xf7, 0x54, 0xb1,
- 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
- 0xaf, 0x19, 0xfe, 0x98,
- 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
- 0x1a, 0x87, 0x8b, 0x0f,
- 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
- 0xfe, 0x32, 0x90, 0x04,
- 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
- 0x7c, 0x12, 0xfe, 0x0f,
- 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
- 0x31, 0x02, 0xc9, 0x2b,
- 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
- 0x6a, 0xfe, 0x19, 0xfe,
- 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
- 0x1b, 0xfe, 0x36, 0x14,
- 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
- 0xfe, 0x80, 0xe7, 0x1a,
- 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
- 0x30, 0xfe, 0x12, 0x45,
- 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
- 0x39, 0xf0, 0x75, 0x26,
- 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
- 0xe3, 0x23, 0x07, 0xfe,
- 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
- 0x56, 0xfe, 0x3c, 0x13,
- 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
- 0x01, 0x18, 0xcb, 0xfe,
- 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
- 0xfe, 0x00, 0xcc, 0xcb,
- 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
- 0xfe, 0x80, 0x4c, 0x01,
- 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
- 0x12, 0xfe, 0x14, 0x56,
- 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
- 0x0d, 0x19, 0xfe, 0x15,
- 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
- 0x83, 0xfe, 0x18, 0x80,
- 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
- 0x90, 0xfe, 0xba, 0x90,
- 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
- 0x21, 0xb9, 0x88, 0x20,
- 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
- 0x18, 0xfe, 0x49, 0x44,
- 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
- 0x1a, 0xa4, 0x0a, 0x67,
- 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
- 0x1d, 0x7b, 0xfe, 0x52,
- 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
- 0x4e, 0xe4, 0xdd, 0x7b,
- 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
- 0xfe, 0x4e, 0xe4, 0xfe,
- 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
- 0xfe, 0x08, 0x10, 0x03,
- 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
- 0x68, 0x54, 0xfe, 0xf1,
- 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
- 0xfe, 0x1a, 0xf4, 0xfe,
- 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
- 0x09, 0x92, 0xfe, 0x5a,
- 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
- 0x5a, 0xf0, 0xfe, 0xc8,
- 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
- 0x1a, 0x10, 0x09, 0x0d,
- 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
- 0x1f, 0x93, 0x01, 0x42,
- 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
- 0xfe, 0x14, 0xf0, 0x08,
- 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
- 0xfe, 0x82, 0xf0, 0xfe,
- 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x18,
- 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
- 0x80, 0x04, 0xfe, 0x82,
- 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
- 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x04,
- 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
- 0x80, 0x04, 0xfe, 0x80,
- 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
- 0xfe, 0x99, 0x83, 0xfe,
- 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
- 0x83, 0xfe, 0xce, 0x47,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
- 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x08, 0x90, 0x04,
- 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
- 0xfe, 0x8a, 0x93, 0x79,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
- 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x3c, 0x90, 0x04,
- 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
- 0x04, 0xfe, 0x83, 0x83,
- 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
-};
+ if (asc_dvc->err_code != 0)
+ shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+ "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
-static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
-static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
+ return asc_dvc->err_code;
+}
-/* a_init.c */
/*
* EEPROM Configuration.
*
@@ -13847,7 +11891,7 @@ static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian
* on big-endian platforms so char fields read as words are actually being
* unswapped on big-endian platforms.
*/
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
0x0000, /* cfg_msw */
0xFFFF, /* disc_enable */
@@ -13885,7 +11929,7 @@ static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
0 /* num_of_err */
};
-static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
0, /* cfg_lsw */
0, /* cfg_msw */
0, /* -disc_enable */
@@ -13923,7 +11967,7 @@ static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
0 /* num_of_err */
};
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
0x0000, /* 01 cfg_msw */
0xFFFF, /* 02 disc_enable */
@@ -13988,7 +12032,7 @@ static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
0, /* 00 cfg_lsw */
0, /* 01 cfg_msw */
0, /* 02 disc_enable */
@@ -14053,7 +12097,7 @@ static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
0x0000, /* 01 cfg_msw */
0xFFFF, /* 02 disc_enable */
@@ -14118,7 +12162,7 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
0, /* 00 cfg_lsw */
0, /* 01 cfg_msw */
0, /* 02 disc_enable */
@@ -14183,1944 +12227,365 @@ static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
0 /* 63 reserved */
};
+#ifdef CONFIG_PCI
/*
- * Initialize the ADV_DVC_VAR structure.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * Wait for EEPROM command to complete
*/
-static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
{
- ushort warn_code;
- AdvPortAddr iop_base;
- uchar pci_cmd_reg;
- int status;
-
- warn_code = 0;
- asc_dvc->err_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * PCI Command Register
- *
- * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
- * I/O Space Control, Memory Space Control and Bus Master Control bits.
- */
-
- if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering) {
- pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
-
- DvcAdvWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister,
- pci_cmd_reg);
-
- if (((DvcAdvReadPCIConfigByte
- (asc_dvc, AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * PCI Latency Timer
- *
- * If the "latency timer" register is 0x20 or above, then we don't need
- * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
- * comes up less than 0x20).
- */
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
- DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
- 0x20);
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
- 0x20) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * Save the state of the PCI Configuration Command Register
- * "Parity Error Response Control" Bit. If the bit is clear (0),
- * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
- * DMA parity errors.
- */
- asc_dvc->cfg->control_flag = 0;
- if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
- asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
- }
-
- asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
- ADV_LIB_VERSION_MINOR;
- asc_dvc->cfg->chip_version =
- AdvGetChipVersion(iop_base, asc_dvc->bus_type);
-
- ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
- (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
- (ushort)ADV_CHIP_ID_BYTE);
-
- ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
- (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
- (ushort)ADV_CHIP_ID_WORD);
-
- /*
- * Reset the chip to start and allow register writes.
- */
- if (AdvFindSignature(iop_base) == 0) {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return ADV_ERROR;
- } else {
- /*
- * The caller must set 'chip_type' to a valid setting.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- /*
- * Reset Chip.
- */
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_WR_IO_REG);
+ int eep_delay_ms;
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- if ((status =
- AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- if ((status =
- AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
- } else {
- if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
+ for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
+ if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
+ ASC_EEP_CMD_DONE) {
+ break;
}
- warn_code |= status;
+ mdelay(1);
}
-
- return warn_code;
+ if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
+ 0)
+ BUG();
}
/*
- * Initialize the ASC-3550.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Needed after initialization for error recovery.
+ * Read the EEPROM from specified location
*/
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc3550_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able = 0, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_READ | eep_word_addr);
+ AdvWaitEEPCmd(iop_base);
+ return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+}
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void __devinit
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+ ushort *wbuf;
+ ushort addr, chksum;
+ ushort *charfields;
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ chksum = 0;
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Save current per TID negotiated values.
+ * Write EEPROM from word 0 to word 20.
*/
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
- ushort bios_version, major, minor;
-
- bios_version =
- bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
- major = (bios_version >> 12) & 0xF;
- minor = (bios_version >> 8) & 0xF;
- if (major < 3 || (major == 3 && minor == 1)) {
- /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
- AdvReadWordLram(iop_base, 0x120, wdtr_able);
- } else {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- }
- }
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc3550_size; i++) {
- if (_adv_asc3550_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf
- [i +
- 3] << 8) |
- _adv_asc3550_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc3550_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[i +
- 2]
- << 8) |
- _adv_asc3550_buf[i +
- 1]));
- i += 2;
- word++;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
- word++;
+ word = *wbuf;
}
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
/*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc3550_expanded_size = word;
-
- /*
- * Clear the rest of ASC-3550 Internal RAM (8KB).
- */
- for (; word < ADV_3550_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc3550_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read and save microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC3550.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
- * threshold of 128 bytes. This register is only accessible to the host.
+ * Write EEPROM checksum at word 21.
*/
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- START_CTL_EMFU | READ_CMD_MRM);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
+ * Write EEPROM OEM name at words 22 to 29.
*/
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
- * bitmask. These values determine the maximum SDTR speed negotiated
- * with a device.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- *
- * 4-bit speed SDTR speed name
- * =========== ===============
- * 0000b (0x0) SDTR disabled
- * 0001b (0x1) 5 Mhz
- * 0010b (0x2) 10 Mhz
- * 0011b (0x3) 20 Mhz (Ultra)
- * 0100b (0x4) 40 Mhz (LVD/Ultra2)
- * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
- * 0110b (0x6) Undefined
- * .
- * 1111b (0xF) Undefined
- */
- word = 0;
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
- /* Set Ultra speed for TID 'tid'. */
- word |= (0x3 << (4 * (tid % 4)));
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- /* Set Fast speed for TID 'tid'. */
- word |= (0x2 << (4 * (tid % 4)));
- }
- if (tid == 3) { /* Check if done with sdtr_speed1. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
- word = 0;
- } else if (tid == 7) { /* Check if done with sdtr_speed2. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
- word = 0;
- } else if (tid == 11) { /* Check if done with sdtr_speed3. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
- word = 0;
- } else if (tid == 15) { /* Check if done with sdtr_speed4. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
- /* End of loop. */
- }
- }
-
- /*
- * Set microcode operating variable for the disconnect per TID bitmask.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
-
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If all three connectors are in use, return an error.
- */
- if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
- (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
- asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
- return ADV_ERROR;
- }
-
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * If this is a differential board and a single-ended device
- * is attached to one of the connectors, return an error.
- */
- if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
- asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * If automatic termination control is enabled, then set the
- * termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting
- * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
- * is ready to be 'ored' into SCSI_CFG1.
- */
- if (asc_dvc->cfg->termination == 0) {
- /*
- * The software always controls termination by setting TERM_CTL_SEL.
- * If TERM_CTL_SEL were set to 0, the hardware would set termination.
- */
- asc_dvc->cfg->termination |= TERM_CTL_SEL;
-
- switch (scsi_cfg1 & CABLE_DETECT) {
- /* TERM_CTL_H: on, TERM_CTL_L: on */
- case 0x3:
- case 0x7:
- case 0xB:
- case 0xD:
- case 0xE:
- case 0xF:
- asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
- break;
-
- /* TERM_CTL_H: on, TERM_CTL_L: off */
- case 0x1:
- case 0x5:
- case 0x9:
- case 0xA:
- case 0xC:
- asc_dvc->cfg->termination |= TERM_CTL_H;
- break;
-
- /* TERM_CTL_H: off, TERM_CTL_L: off */
- case 0x2:
- case 0x6:
- break;
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+}
- /*
- * Clear any set TERM_CTL_H and TERM_CTL_L bits.
- */
- scsi_cfg1 &= ~TERM_CTL;
-
- /*
- * Invert the TERM_CTL_H and TERM_CTL_L bits and then
- * set 'scsi_cfg1'. The TERM_POL bit does not need to be
- * referenced, because the hardware internally inverts
- * the Termination High and Low bits if TERM_POL is set.
- */
- scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set filter value and possibly modified termination control
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
- FLTR_DISABLE | scsi_cfg1);
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void __devinit
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-3550 has 8KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_8KB);
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ chksum = 0;
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Build carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
+ * Write EEPROM from word 0 to word 20.
*/
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address of the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
-
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
/*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
+ * Write EEPROM checksum at word 21.
*/
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Set RISC IRQ physical address start value.
+ * Write EEPROM OEM name at words 22 to 29.
*/
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
-
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
-
- return warn_code;
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
}
/*
- * Initialize the ASC-38C0800.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Needed after initialization for error recovery.
+ * Write the EEPROM from 'cfg_buf'.
*/
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+void __devinit
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc38C0800_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (RAM Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
-
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++) {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0
- || (byte & 0x0F) != PRE_TEST_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
-
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
- }
-
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
- }
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ chksum = 0;
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
+ * Write EEPROM from word 0 to word 20.
*/
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
- if (_adv_asc38C0800_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf
- [i +
- 3] << 8) |
- _adv_asc38C0800_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C0800_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf
- [i +
- 2] << 8) |
- _adv_asc38C0800_buf[i
- +
- 1]));
- i += 2;
- word++;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
- word++;
- }
- }
-
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C0800_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C0800 Internal RAM (16KB).
- */
- for (; word < ADV_38C0800_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
- ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
-
- ASC_DBG2(1,
- "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
- (ulong)sum, (ulong)_adv_asc38C0800_chksum);
-
- if (sum != _adv_asc38C0800_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C0800.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
- scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
- * bits for the default FIFO threshold.
- *
- * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
- *
- * For DMA Errata #4 set the BC_THRESH_ENB bit.
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
- READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
-
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * All kind of combinations of devices attached to one of four connectors
- * are acceptable except HVD device attached. For example, LVD device can
- * be attached to SE connector while SE device attached to LVD connector.
- * If LVD device attached to SE connector, it only runs up to Ultra speed.
- *
- * If an HVD device is attached to one of LVD connectors, return an error.
- * However, there is no way to detect HVD device attached to SE connectors.
- */
- if (scsi_cfg1 & HVD) {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * If either SE or LVD automatic termination control is enabled, then
- * set the termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting then
- * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
- * be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
- /* SE automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_SE) {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1:
- case 0x2:
- case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- /* TERM_SE_HI: on, TERM_SE_LO: off */
- case 0x0:
- asc_dvc->cfg->termination |= TERM_SE_HI;
- break;
- }
- }
-
- if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
- /* LVD automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_LVD) {
- /* TERM_LVD_HI: on, TERM_LVD_LO: on */
- case 0x4:
- case 0x8:
- case 0xC:
- asc_dvc->cfg->termination |= TERM_LVD;
- break;
-
- /* TERM_LVD_HI: off, TERM_LVD_LO: off */
- case 0x0:
- break;
- }
- }
-
- /*
- * Clear any set TERM_SE and TERM_LVD bits.
- */
- scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
-
- /*
- * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
-
- /*
- * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
- * and set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control and reset DIS_TERM_DRV
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
-
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C0800 has 16KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_16KB);
-
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
-
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
-
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ word = *wbuf;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
-
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value.
- * carr_pa is LE, must be native before write
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
/*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
+ * Write EEPROM checksum at word 21.
*/
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Set RISC IRQ physical address start value.
- *
- * carr_pa is LE, must be native before write *
+ * Write EEPROM OEM name at words 22 to 29.
*/
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
-
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
-
- return warn_code;
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
}
/*
- * Initialize the ASC-38C1600.
- *
- * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * Read EEPROM configuration into the specified buffer.
*
- * Needed after initialization for error recovery.
+ * Return a checksum based on the EEPROM configuration read.
*/
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
+static ushort __devinit
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- long word;
- int j;
- int adv_asc38C1600_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
- uchar max_cmd[ASC_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++) {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0
- || (byte & 0x0F) != PRE_TEST_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
}
}
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
-
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
+ }
}
+ return chksum;
+}
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- /*
- * Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
- if (_adv_asc38C1600_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf
- [i +
- 3] << 8) |
- _adv_asc38C1600_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C1600_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf
- [i +
- 2] << 8) |
- _adv_asc38C1600_buf[i
- +
- 1]));
- i += 2;
- word++;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
- word++;
+ *wbuf = wval;
}
}
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C1600_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C1600 Internal RAM (32KB).
- */
- for (; word < ADV_38C1600_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc38C1600_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C1600.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
- scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * If the BIOS control flag AIPP (Asynchronous Information
- * Phase Protection) disable bit is not set, then set the firmware
- * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
- * AIPP checking and encoding.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_ENABLE_AIPP;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
- * and START_CTL_TH [3:2].
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Calculate SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- *
- * Each ASC-38C1600 function has only two cable detect bits.
- * The bus mode override bits are in IOPB_SOFT_OVER_WR.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If the cable is reversed all of the SCSI_CTRL register signals
- * will be set. Check for and return an error if this condition is
- * found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * Each ASC-38C1600 function has two connectors. Only an HVD device
- * can not be connected to either connector. An LVD device or SE device
- * may be connected to either connecor. If an SE device is connected,
- * then at most Ultra speed (20 Mhz) can be used on both connectors.
- *
- * If an HVD device is attached, return an error.
- */
- if (scsi_cfg1 & HVD) {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * Each function in the ASC-38C1600 uses only the SE cable detect and
- * termination because there are two connectors for each function. Each
- * function may use either LVD or SE mode. Corresponding the SE automatic
- * termination control EEPROM bits are used for each function. Each
- * function has its own EEPROM. If SE automatic control is enabled for
- * the function, then set the termination value based on a table listed
- * in a_condor.h.
- *
- * If manual termination is specified in the EEPROM for the function,
- * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
- * ready to be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
- /* SE automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_SE) {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1:
- case 0x2:
- case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- case 0x0:
- if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
- /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
- } else {
- /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
- asc_dvc->cfg->termination |= TERM_SE_HI;
- }
- break;
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
}
}
+ return chksum;
+}
- /*
- * Clear any set TERM_SE bits.
- */
- scsi_cfg1 &= ~TERM_SE;
-
- /*
- * Invert the TERM_SE bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
-
- /*
- * Clear Big Endian and Terminator Polarity bits and set possibly
- * modified termination control bits in the Microcode SCSI_CFG1
- * Register Value.
- *
- * Big Endian bit is not used even on big endian machines.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
-
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C1600 has 32KB internal memory.
- *
- * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
- * out a special 16K Adv Library and Microcode version. After the issue
- * resolved, we should turn back to the 32K support. Both a_condor.h and
- * mcode.sas files also need to be updated.
- *
- * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- * BIOS_EN | RAM_SZ_32KB);
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_16KB);
-
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
-
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
-
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- buf_size -= sizeof(ADV_CARR_T);
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value. Initialize the
- * COMMA register to the same value otherwise the RISC will
- * prematurely detect a command is available.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(asc_dvc->icq_sp->carr_pa));
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
-
- /*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
- */
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC IRQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * per TID microcode operating variables.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
- } else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
}
}
-
- return warn_code;
+ return chksum;
}
/*
@@ -16135,12 +12600,11 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_3550_CONFIG eep_config;
- int i;
iop_base = asc_dvc->iop_base;
@@ -16157,15 +12621,12 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_3550_EEPROM_Config + i);
- }
+ memcpy(&eep_config, &Default_3550_EEPROM_Config,
+ sizeof(ADVEEP_3550_CONFIG));
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
@@ -16289,12 +12750,11 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C0800_CONFIG eep_config;
- int i;
uchar tid, termination;
ushort sdtr_speed = 0;
@@ -16314,15 +12774,12 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_38C0800_EEPROM_Config + i);
- }
+ memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
+ sizeof(ADVEEP_38C0800_CONFIG));
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
@@ -16492,12 +12949,11 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C1600_CONFIG eep_config;
- int i;
uchar tid, termination;
ushort sdtr_speed = 0;
@@ -16512,75 +12968,52 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
*/
if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
eep_config.check_sum) {
+ struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
- if (i == 1
- && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
- 0) {
- /*
- * Set Function 1 EEPROM Word 0 MSB
- *
- * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
- * EEPROM bits.
- *
- * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
- * old Mac system booting problem. The Expansion ROM must
- * be disabled in Function 1 for these systems.
- *
- */
- *((uchar *)&eep_config + i) =
- ((*
- ((uchar *)&Default_38C1600_EEPROM_Config
- +
- i)) &
- (~
- (((ADV_EEPROM_BIOS_ENABLE |
- ADV_EEPROM_INTAB) >> 8) & 0xFF)));
+ memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
+ sizeof(ADVEEP_38C1600_CONFIG));
- /*
- * Set the INTAB (bit 11) if the GPIO 0 input indicates
- * the Function 1 interrupt line is wired to INTA.
- *
- * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
- * 1 - Function 1 interrupt line wired to INT A.
- * 0 - Function 1 interrupt line wired to INT B.
- *
- * Note: Adapter boards always have Function 0 wired to INTA.
- * Put all 5 GPIO bits in input mode and then read
- * their input values.
- */
- AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
- 0);
- if (AdvReadByteRegister
- (iop_base, IOPB_GPIO_DATA) & 0x01) {
- /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
- *((uchar *)&eep_config + i) |=
- ((ADV_EEPROM_INTAB >> 8) & 0xFF);
- }
- } else {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_38C1600_EEPROM_Config
- + i);
- }
+ if (PCI_FUNC(pdev->devfn) != 0) {
+ u8 ints;
+ /*
+ * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
+ * and old Mac system booting problem. The Expansion
+ * ROM must be disabled in Function 1 for these systems
+ */
+ eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
+ /*
+ * Clear the INTAB (bit 11) if the GPIO 0 input
+ * indicates the Function 1 interrupt line is wired
+ * to INTB.
+ *
+ * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+ * 1 - Function 1 interrupt line wired to INT A.
+ * 0 - Function 1 interrupt line wired to INT B.
+ *
+ * Note: Function 0 is always wired to INTA.
+ * Put all 5 GPIO bits in input mode and then read
+ * their input values.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
+ ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
+ if ((ints & 0x01) == 0)
+ eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
}
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
eep_config.serial_number_word2 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
eep_config.serial_number_word1 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
AdvSet38C1600EEPConfig(iop_base, &eep_config);
}
@@ -16729,1176 +13162,281 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
}
/*
- * Read EEPROM configuration into the specified buffer.
- *
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read EEPROM configuration into the specified buffer.
+ * Initialize the ADV_DVC_VAR structure.
*
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read EEPROM configuration into the specified buffer.
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read the EEPROM from specified location
- */
-static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
-{
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_READ | eep_word_addr);
- AdvWaitEEPCmd(iop_base);
- return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
-}
-
-/*
- * Wait for EEPROM command to complete
- */
-static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
-{
- int eep_delay_ms;
-
- for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
- if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
- ASC_EEP_CMD_DONE) {
- break;
- }
- DvcSleepMilliSecond(1);
- }
- if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
- 0) {
- ASC_ASSERT(0);
- }
- return;
-}
-
-/*
- * Write the EEPROM from 'cfg_buf'.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
*/
-void __init
-AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+static int __devinit
+AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
{
- ushort *wbuf;
- ushort addr, chksum;
- ushort *charfields;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
+ struct asc_board *board = shost_priv(shost);
+ ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var;
+ unsigned short warn_code = 0;
+ AdvPortAddr iop_base = asc_dvc->iop_base;
+ u16 cmd;
+ int status;
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ asc_dvc->err_code = 0;
/*
- * Write EEPROM OEM name at words 22 to 29.
+ * Save the state of the PCI Configuration Command Register
+ * "Parity Error Response Control" Bit. If the bit is clear (0),
+ * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+ * DMA parity errors.
*/
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
-}
-
-/*
- * Write the EEPROM from 'cfg_buf'.
- */
-void __init
-AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
-{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
+ asc_dvc->cfg->control_flag = 0;
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if ((cmd & PCI_COMMAND_PARITY) == 0)
+ asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
+ asc_dvc->cfg->chip_version =
+ AdvGetChipVersion(iop_base, asc_dvc->bus_type);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
+ ASC_DBG(1, "iopb_chip_id_1: 0x%x 0x%x\n",
+ (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+ (ushort)ADV_CHIP_ID_BYTE);
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ ASC_DBG(1, "iopw_chip_id_0: 0x%x 0x%x\n",
+ (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+ (ushort)ADV_CHIP_ID_WORD);
/*
- * Write EEPROM OEM name at words 22 to 29.
+ * Reset the chip to start and allow register writes.
*/
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
+ if (AdvFindSignature(iop_base) == 0) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return ADV_ERROR;
+ } else {
+ /*
+ * The caller must set 'chip_type' to a valid setting.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
}
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
-}
-/*
- * Write the EEPROM from 'cfg_buf'.
- */
-void __init
-AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
-{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
+ /*
+ * Reset Chip.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_RESET);
+ mdelay(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ status = AdvInitFrom38C1600EEP(asc_dvc);
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ status = AdvInitFrom38C0800EEP(asc_dvc);
} else {
- word = *wbuf;
+ status = AdvInitFrom3550EEP(asc_dvc);
}
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+ warn_code |= status;
}
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ if (warn_code != 0)
+ shost_printk(KERN_WARNING, shost, "warning: 0x%x\n", warn_code);
- /*
- * Write EEPROM OEM name at words 22 to 29.
- */
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
+ if (asc_dvc->err_code)
+ shost_printk(KERN_ERR, shost, "error code 0x%x\n",
+ asc_dvc->err_code);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
+ return asc_dvc->err_code;
}
+#endif
-/* a_advlib.c */
-/*
- * AdvExeScsiQueue() - Send a request to the RISC microcode program.
- *
- * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
- * add the carrier to the ICQ (Initiator Command Queue), and tickle the
- * RISC to notify it a new command is ready to be executed.
- *
- * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
- * set to SCSI_MAX_RETRY.
- *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
- * for DMA addresses or math operations are byte swapped to little-endian
- * order.
- *
- * Return:
- * ADV_SUCCESS(1) - The request was successfully queued.
- * ADV_BUSY(0) - Resource unavailable; Retry again after pending
- * request completes.
- * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
- * host IC error.
- */
-static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
-{
- ulong last_int_level;
- AdvPortAddr iop_base;
- ADV_DCNT req_size;
- ADV_PADDR req_paddr;
- ADV_CARR_T *new_carrp;
-
- ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
-
- /*
- * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
- */
- if (scsiq->target_id > ADV_MAX_TID) {
- scsiq->host_status = QHSTA_M_INVALID_DEVICE;
- scsiq->done_status = QD_WITH_ERROR;
- return ADV_ERROR;
- }
-
- iop_base = asc_dvc->iop_base;
-
- last_int_level = DvcEnterCritical();
-
- /*
- * Allocate a carrier ensuring at least one carrier always
- * remains on the freelist and initialize fields.
- */
- if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
- DvcLeaveCritical(last_int_level);
- return ADV_BUSY;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
- asc_dvc->carr_pending_cnt++;
-
- /*
- * Set the carrier to be a stopper by setting 'next_vpa'
- * to the stopper value. The current stopper will be changed
- * below to point to the new stopper.
- */
- new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Clear the ADV_SCSI_REQ_Q done flag.
- */
- scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
- req_size = sizeof(ADV_SCSI_REQ_Q);
- req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
- (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
-
- ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
- ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
- /* Wait for assertion before making little-endian */
- req_paddr = cpu_to_le32(req_paddr);
-
- /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
- scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
- scsiq->scsiq_rptr = req_paddr;
-
- scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
- /*
- * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
- * order during initialization.
- */
- scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
-
- /*
- * Use the current stopper to send the ADV_SCSI_REQ_Q command to
- * the microcode. The newly allocated stopper will become the new
- * stopper.
- */
- asc_dvc->icq_sp->areq_vpa = req_paddr;
-
+static struct scsi_host_template advansys_template = {
+ .proc_name = DRV_NAME,
+#ifdef CONFIG_PROC_FS
+ .proc_info = advansys_proc_info,
+#endif
+ .name = DRV_NAME,
+ .info = advansys_info,
+ .queuecommand = advansys_queuecommand,
+ .eh_bus_reset_handler = advansys_reset,
+ .bios_param = advansys_biosparam,
+ .slave_configure = advansys_slave_configure,
/*
- * Set the 'next_vpa' pointer for the old stopper to be the
- * physical address of the new stopper. The RISC can only
- * follow physical addresses.
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+ * must be set. The flag will be cleared in advansys_board_found
+ * for non-ISA adapters.
*/
- asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
-
+ .unchecked_isa_dma = 1,
/*
- * Set the host adapter stopper pointer to point to the new carrier.
+ * All adapters controlled by this driver are capable of large
+ * scatter-gather lists. According to the mid-level SCSI documentation
+ * this obviates any performance gain provided by setting
+ * 'use_clustering'. But empirically while CPU utilization is increased
+ * by enabling clustering, I/O throughput increases as well.
*/
- asc_dvc->icq_sp = new_carrp;
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- /*
- * Tickle the RISC to tell it to read its Command Queue Head pointer.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_a' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE,
- ADV_TICKLE_NOP);
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- /*
- * Notify the RISC a carrier is ready by writing the physical
- * address of the new carrier stopper to the COMMA register.
- */
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(new_carrp->carr_pa));
- }
-
- DvcLeaveCritical(last_int_level);
-
- return ADV_SUCCESS;
-}
+ .use_clustering = ENABLE_CLUSTERING,
+};
-/*
- * Reset SCSI Bus and purge all outstanding requests.
- *
- * Return Value:
- * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
- * ADV_FALSE(0) - Microcode command failed.
- * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
- * may be hung which requires driver recovery.
- */
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
+static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost)
{
- int status;
+ struct asc_board *board = shost_priv(shost);
+ struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+ int req_cnt = 0;
+ adv_req_t *reqp = NULL;
+ int sg_cnt = 0;
+ adv_sgblk_t *sgp;
+ int warn_code, err_code;
/*
- * Send the SCSI Bus Reset idle start idle command which asserts
- * the SCSI Bus Reset signal.
+ * Allocate buffer carrier structures. The total size
+ * is about 4 KB, so allocate all at once.
*/
- status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
- if (status != ADV_TRUE) {
- return status;
- }
+ adv_dvc->carrier_buf = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
+ ASC_DBG(1, "carrier_buf 0x%p\n", adv_dvc->carrier_buf);
- /*
- * Delay for the specified SCSI Bus Reset hold time.
- *
- * The hold time delay is done on the host because the RISC has no
- * microsecond accurate timer.
- */
- DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
+ if (!adv_dvc->carrier_buf)
+ goto kmalloc_failed;
/*
- * Send the SCSI Bus Reset end idle command which de-asserts
- * the SCSI Bus Reset signal and purges any pending requests.
+ * Allocate up to 'max_host_qng' request structures for the Wide
+ * board. The total size is about 16 KB, so allocate all at once.
+ * If the allocation fails decrement and try again.
*/
- status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
- if (status != ADV_TRUE) {
- return status;
- }
-
- DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
-
- return status;
-}
-
-/*
- * Reset chip and SCSI Bus.
- *
- * Return Value:
- * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
- * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
- */
-static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
-{
- int status;
- ushort wdtr_able, sdtr_able, tagqng_able;
- ushort ppr_able = 0;
- uchar tid, max_cmd[ADV_MAX_TID + 1];
- AdvPortAddr iop_base;
- ushort bios_sig;
+ for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) {
+ reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
- iop_base = asc_dvc->iop_base;
+ ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt,
+ (ulong)sizeof(adv_req_t) * req_cnt);
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- }
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
+ if (reqp)
+ break;
}
- /*
- * Force the AdvInitAsc3550/38C0800Driver() function to
- * perform a SCSI Bus Reset by clearing the BIOS signature word.
- * The initialization functions assumes a SCSI Bus Reset is not
- * needed if the BIOS signature word is present.
- */
- AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+ if (!reqp)
+ goto kmalloc_failed;
- /*
- * Stop chip and reset it.
- */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_WR_IO_REG);
+ adv_dvc->orig_reqp = reqp;
/*
- * Reset Adv Library error code, if any, and try
- * re-initializing the chip.
+ * Allocate up to ADV_TOT_SG_BLOCK request structures for
+ * the Wide board. Each structure is about 136 bytes.
*/
- asc_dvc->err_code = 0;
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- status = AdvInitAsc38C1600Driver(asc_dvc);
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- status = AdvInitAsc38C0800Driver(asc_dvc);
- } else {
- status = AdvInitAsc3550Driver(asc_dvc);
- }
+ board->adv_sgblkp = NULL;
+ for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+ sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
- /* Translate initialization return value to status value. */
- if (status == 0) {
- status = ADV_TRUE;
- } else {
- status = ADV_FALSE;
- }
+ if (!sgp)
+ break;
- /*
- * Restore the BIOS signature word.
- */
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ sgp->next_sgblkp = board->adv_sgblkp;
+ board->adv_sgblkp = sgp;
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- return status;
-}
-
-/*
- * Adv Library Interrupt Service Routine
- *
- * This function is called by a driver's interrupt service routine.
- * The function disables and re-enables interrupts.
- *
- * When a microcode idle command is completed, the ADV_DVC_VAR
- * 'idle_cmd_done' field is set to ADV_TRUE.
- *
- * Note: AdvISR() can be called when interrupts are disabled or even
- * when there is no hardware interrupt condition present. It will
- * always check for completed idle commands and microcode requests.
- * This is an important feature that shouldn't be changed because it
- * allows commands to be completed from polling mode loops.
- *
- * Return:
- * ADV_TRUE(1) - interrupt was pending
- * ADV_FALSE(0) - no interrupt was pending
- */
-static int AdvISR(ADV_DVC_VAR *asc_dvc)
-{
- AdvPortAddr iop_base;
- uchar int_stat;
- ushort target_bit;
- ADV_CARR_T *free_carrp;
- ADV_VADDR irq_next_vpa;
- int flags;
- ADV_SCSI_REQ_Q *scsiq;
-
- flags = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
- /* Reading the register clears the interrupt. */
- int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+ ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t),
+ sizeof(adv_sgblk_t) * sg_cnt);
- if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
- ADV_INTR_STATUS_INTRC)) == 0) {
- DvcLeaveCritical(flags);
- return ADV_FALSE;
- }
+ if (!board->adv_sgblkp)
+ goto kmalloc_failed;
/*
- * Notify the driver of an asynchronous microcode condition by
- * calling the ADV_DVC_VAR.async_callback function. The function
- * is passed the microcode ASC_MC_INTRB_CODE byte value.
+ * Point 'adv_reqp' to the request structures and
+ * link them together.
*/
- if (int_stat & ADV_INTR_STATUS_INTRB) {
- uchar intrb_code;
-
- AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
- asc_dvc->carr_pending_cnt != 0) {
- AdvWriteByteRegister(iop_base, IOPB_TICKLE,
- ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- AdvWriteByteRegister(iop_base,
- IOPB_TICKLE,
- ADV_TICKLE_NOP);
- }
- }
- }
-
- if (asc_dvc->async_callback != 0) {
- (*asc_dvc->async_callback) (asc_dvc, intrb_code);
- }
+ req_cnt--;
+ reqp[req_cnt].next_reqp = NULL;
+ for (; req_cnt > 0; req_cnt--) {
+ reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
}
+ board->adv_reqp = &reqp[0];
- /*
- * Check if the IRQ stopper carrier contains a completed request.
- */
- while (((irq_next_vpa =
- le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
- /*
- * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
- * The RISC will have set 'areq_vpa' to a virtual address.
- *
- * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
- * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
- * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
- * in AdvExeScsiQueue().
- */
- scsiq = (ADV_SCSI_REQ_Q *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
-
- /*
- * Request finished with good status and the queue was not
- * DMAed to host memory by the firmware. Set all status fields
- * to indicate good status.
- */
- if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
- scsiq->done_status = QD_NO_ERROR;
- scsiq->host_status = scsiq->scsi_status = 0;
- scsiq->data_cnt = 0L;
- }
-
- /*
- * Advance the stopper pointer to the next carrier
- * ignoring the lower four bits. Free the previous
- * stopper carrier.
- */
- free_carrp = asc_dvc->irq_sp;
- asc_dvc->irq_sp = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
-
- free_carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = free_carrp;
- asc_dvc->carr_pending_cnt--;
-
- ASC_ASSERT(scsiq != NULL);
- target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
-
- /*
- * Clear request microcode control flag.
- */
- scsiq->cntl = 0;
-
- /*
- * If the command that completed was a SCSI INQUIRY and
- * LUN 0 was sent the command, then process the INQUIRY
- * command information for the device.
- *
- * Note: If data returned were either VPD or CmdDt data,
- * don't process the INQUIRY command information for
- * the device, otherwise may erroneously set *_able bits.
- */
- if (scsiq->done_status == QD_NO_ERROR &&
- scsiq->cdb[0] == INQUIRY &&
- scsiq->target_lun == 0 &&
- (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
- == ADV_INQ_RTN_STD_INQUIRY_DATA) {
- AdvInquiryHandling(asc_dvc, scsiq);
- }
-
- /*
- * Notify the driver of the completed request by passing
- * the ADV_SCSI_REQ_Q pointer to its callback function.
- */
- scsiq->a_flag |= ADV_SCSIQ_DONE;
- (*asc_dvc->isr_callback) (asc_dvc, scsiq);
- /*
- * Note: After the driver callback function is called, 'scsiq'
- * can no longer be referenced.
- *
- * Fall through and continue processing other completed
- * requests...
- */
-
- /*
- * Disable interrupts again in case the driver inadvertently
- * enabled interrupts in its callback function.
- *
- * The DvcEnterCritical() return value is ignored, because
- * the 'flags' saved when AdvISR() was first entered will be
- * used to restore the interrupt flag on exit.
- */
- (void)DvcEnterCritical();
+ if (adv_dvc->chip_type == ADV_CHIP_ASC3550) {
+ ASC_DBG(2, "AdvInitAsc3550Driver()\n");
+ warn_code = AdvInitAsc3550Driver(adv_dvc);
+ } else if (adv_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ ASC_DBG(2, "AdvInitAsc38C0800Driver()\n");
+ warn_code = AdvInitAsc38C0800Driver(adv_dvc);
+ } else {
+ ASC_DBG(2, "AdvInitAsc38C1600Driver()\n");
+ warn_code = AdvInitAsc38C1600Driver(adv_dvc);
}
- DvcLeaveCritical(flags);
- return ADV_TRUE;
-}
+ err_code = adv_dvc->err_code;
-/*
- * Send an idle command to the chip and wait for completion.
- *
- * Command completion is polled for once per microsecond.
- *
- * The function can be called from anywhere including an interrupt handler.
- * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
- * functions to prevent reentrancy.
- *
- * Return Values:
- * ADV_TRUE - command completed successfully
- * ADV_FALSE - command failed
- * ADV_ERROR - command timed out
- */
-static int
-AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
- ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
-{
- ulong last_int_level;
- int result;
- ADV_DCNT i, j;
- AdvPortAddr iop_base;
-
- last_int_level = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
-
- /*
- * Clear the idle command status which is set by the microcode
- * to a non-zero value to indicate when the command is completed.
- * The non-zero result is one of the IDLE_CMD_STATUS_* values
- * defined in a_advlib.h.
- */
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
-
- /*
- * Write the idle command value after the idle command parameter
- * has been written to avoid a race condition. If the order is not
- * followed, the microcode may process the idle command before the
- * parameters have been written to LRAM.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
- cpu_to_le32(idle_cmd_parameter));
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
-
- /*
- * Tickle the RISC to tell it to process the idle command.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_b' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ if (warn_code || err_code) {
+ shost_printk(KERN_WARNING, shost, "error: warn 0x%x, error "
+ "0x%x\n", warn_code, err_code);
}
- /* Wait for up to 100 millisecond for the idle command to timeout. */
- for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
- /* Poll once each microsecond for command completion. */
- for (j = 0; j < SCSI_US_PER_MSEC; j++) {
- AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
- result);
- if (result != 0) {
- DvcLeaveCritical(last_int_level);
- return result;
- }
- DvcDelayMicroSecond(asc_dvc, (ushort)1);
- }
- }
+ goto exit;
- ASC_ASSERT(0); /* The idle command should never timeout. */
- DvcLeaveCritical(last_int_level);
- return ADV_ERROR;
+ kmalloc_failed:
+ shost_printk(KERN_ERR, shost, "error: kmalloc() failed\n");
+ err_code = ADV_ERROR;
+ exit:
+ return err_code;
}
-/*
- * Inquiry Information Byte 7 Handling
- *
- * Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag
- * Queuing.
- */
-static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
+static void advansys_wide_free_mem(struct asc_board *board)
{
- AdvPortAddr iop_base;
- uchar tid;
- ADV_SCSI_INQUIRY *inq;
- ushort tidmask;
- ushort cfg_word;
-
- /*
- * AdvInquiryHandling() requires up to INQUIRY information Byte 7
- * to be available.
- *
- * If less than 8 bytes of INQUIRY information were requested or less
- * than 8 bytes were transferred, then return. cdb[4] is the request
- * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
- * microcode to the transfer residual count.
- */
-
- if (scsiq->cdb[4] < 8 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
- return;
- }
-
- iop_base = asc_dvc->iop_base;
- tid = scsiq->target_id;
-
- inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
-
- /*
- * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
- */
- if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
- return;
- } else {
- /*
- * INQUIRY Byte 7 Handling
- *
- * Use a device's INQUIRY byte 7 to determine whether it
- * supports WDTR, SDTR, and Tag Queuing. If the feature
- * is enabled in the EEPROM and the device supports the
- * feature, then enable it in the microcode.
- */
-
- tidmask = ADV_TID_TO_TIDMASK(tid);
-
- /*
- * Wide Transfers
- *
- * If the EEPROM enabled WDTR for the device and the device
- * supports wide bus (16 bit) transfers, then turn on the
- * device's 'wdtr_able' bit and write the new value to the
- * microcode.
- */
- if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0) {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" and "WDTR
- * negotiation" done indicators for the target to cause
- * it to negotiate with the new setting set above.
- * WDTR when accepted causes the target to enter
- * asynchronous mode, so SDTR must be negotiated.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
- cfg_word);
- }
- }
-
- /*
- * Synchronous Transfers
- *
- * If the EEPROM enabled SDTR for the device and the device
- * supports synchronous transfers, then turn on the device's
- * 'sdtr_able' bit. Write the new value to the microcode.
- */
- if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0) {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" done indicator
- * for the target to cause it to negotiate with the new
- * setting set above.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- }
- }
- /*
- * If the Inquiry data included enough space for the SPI-3
- * Clocking field, then check if DT mode is supported.
- */
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
- (scsiq->cdb[4] >= 57 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
- /*
- * PPR (Parallel Protocol Request) Capable
- *
- * If the device supports DT mode, then it must be PPR capable.
- * The PPR message will be used in place of the SDTR and WDTR
- * messages to negotiate synchronous speed and offset, transfer
- * width, and protocol options.
- */
- if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
- asc_dvc->ppr_able);
- asc_dvc->ppr_able |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
- asc_dvc->ppr_able);
- }
- }
-
- /*
- * If the EEPROM enabled Tag Queuing for the device and the
- * device supports Tag Queueing, then turn on the device's
- * 'tagqng_enable' bit in the microcode and set the microcode
- * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
- * value.
- *
- * Tag Queuing is disabled for the BIOS which runs in polled
- * mode and would see no benefit from Tag Queuing. Also by
- * disabling Tag Queuing in the BIOS devices with Tag Queuing
- * bugs will at least work with the BIOS.
- */
- if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- cfg_word);
-
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- asc_dvc->max_dvc_qng);
- }
+ struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+ kfree(adv_dvc->carrier_buf);
+ adv_dvc->carrier_buf = NULL;
+ kfree(adv_dvc->orig_reqp);
+ adv_dvc->orig_reqp = board->adv_reqp = NULL;
+ while (board->adv_sgblkp) {
+ adv_sgblk_t *sgp = board->adv_sgblkp;
+ board->adv_sgblkp = sgp->next_sgblkp;
+ kfree(sgp);
}
}
-MODULE_LICENSE("Dual BSD/GPL");
-
-static struct Scsi_Host *__devinit
-advansys_board_found(int iop, struct device *dev, int bus_type)
+static int __devinit advansys_board_found(struct Scsi_Host *shost,
+ unsigned int iop, int bus_type)
{
- struct Scsi_Host *shost;
- struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
- asc_board_t *boardp;
+ struct pci_dev *pdev;
+ struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp = NULL;
ADV_DVC_VAR *adv_dvc_varp = NULL;
- adv_sgblk_t *sgp = NULL;
- int share_irq = FALSE;
- int iolen = 0;
- ADV_PADDR pci_memory_address;
- int warn_code, err_code;
- int ret;
+ int share_irq, warn_code, ret;
- /*
- * Adapter found.
- *
- * Register the adapter, get its configuration, and
- * initialize it.
- */
- ASC_DBG(2, "advansys_board_found: scsi_register()\n");
- shost = scsi_register(&driver_template, sizeof(asc_board_t));
-
- if (!shost)
- return NULL;
-
- /* Save a pointer to the Scsi_Host of each board found. */
- asc_host[asc_board_count++] = shost;
-
- /* Initialize private per board data */
- boardp = ASC_BOARDP(shost);
- memset(boardp, 0, sizeof(asc_board_t));
- boardp->id = asc_board_count - 1;
-
- /* Initialize spinlock. */
- spin_lock_init(&boardp->lock);
-
- /*
- * Handle both narrow and wide boards.
- *
- * If a Wide board was detected, set the board structure
- * wide board flag. Set-up the board structure based on
- * the board type.
- */
-#ifdef CONFIG_PCI
- if (bus_type == ASC_IS_PCI &&
- (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
- pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
- pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
- boardp->flags |= ASC_IS_WIDE_BOARD;
- }
-#endif /* CONFIG_PCI */
+ pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL;
if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(1, "advansys_board_found: narrow board\n");
+ ASC_DBG(1, "narrow board\n");
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
asc_dvc_varp->bus_type = bus_type;
asc_dvc_varp->drv_ptr = boardp;
asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
- asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
asc_dvc_varp->iop_base = iop;
- asc_dvc_varp->isr_callback = asc_isr_callback;
} else {
- ASC_DBG(1, "advansys_board_found: wide board\n");
+#ifdef CONFIG_PCI
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
adv_dvc_varp->drv_ptr = boardp;
adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
- adv_dvc_varp->isr_callback = adv_isr_callback;
- adv_dvc_varp->async_callback = adv_async_callback;
-#ifdef CONFIG_PCI
if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
- ASC_DBG(1, "advansys_board_found: ASC-3550\n");
+ ASC_DBG(1, "wide board ASC-3550\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
} else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
- ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
+ ASC_DBG(1, "wide board ASC-38C0800\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
} else {
- ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
+ ASC_DBG(1, "wide board ASC-38C1600\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
}
-#endif /* CONFIG_PCI */
- /*
- * Map the board's registers into virtual memory for
- * PCI slave access. Only memory accesses are used to
- * access the board's registers.
- *
- * Note: The PCI register base address is not always
- * page aligned, but the address passed to ioremap()
- * must be page aligned. It is guaranteed that the
- * PCI register base address will not cross a page
- * boundary.
- */
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- iolen = ADV_3550_IOLEN;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- iolen = ADV_38C0800_IOLEN;
- } else {
- iolen = ADV_38C1600_IOLEN;
- }
-#ifdef CONFIG_PCI
- pci_memory_address = pci_resource_start(pdev, 1);
- ASC_DBG1(1,
- "advansys_board_found: pci_memory_address: 0x%lx\n",
- (ulong)pci_memory_address);
- if ((boardp->ioremap_addr =
- ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
- ASC_PRINT3
- ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
- boardp->id, pci_memory_address, iolen);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ boardp->asc_n_io_port = pci_resource_len(pdev, 1);
+ boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
+ boardp->asc_n_io_port);
+ if (!boardp->ioremap_addr) {
+ shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) "
+ "returned NULL\n",
+ (long)pci_resource_start(pdev, 1),
+ boardp->asc_n_io_port);
+ ret = -ENODEV;
+ goto err_shost;
}
- ASC_DBG1(1,
- "advansys_board_found: ioremap_addr: 0x%lx\n",
- (ulong)boardp->ioremap_addr);
- adv_dvc_varp->iop_base = (AdvPortAddr)
- (boardp->ioremap_addr +
- (pci_memory_address - (pci_memory_address & PAGE_MASK)));
- ASC_DBG1(1,
- "advansys_board_found: iop_base: 0x%lx\n",
- adv_dvc_varp->iop_base);
-#endif /* CONFIG_PCI */
+ adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr;
+ ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base);
/*
* Even though it isn't used to access wide boards, other
@@ -17907,9 +13445,9 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
*/
boardp->ioport = iop;
- ASC_DBG2(1,
- "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
- (ushort)inp(iop + 1), (ushort)inpw(iop));
+ ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+ (ushort)inp(iop + 1), (ushort)inpw(iop));
+#endif /* CONFIG_PCI */
}
#ifdef CONFIG_PROC_FS
@@ -17917,18 +13455,16 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* Allocate buffer for printing information from
* /proc/scsi/advansys/[0...].
*/
- if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
- ASC_PRINT3
- ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
- boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
+ if (!boardp->prtbuf) {
+ shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n",
+ ASC_PRTBUF_SIZE);
+ ret = -ENOMEM;
+ goto err_unmap;
}
#endif /* CONFIG_PROC_FS */
if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp->cfg->dev = dev;
/*
* Set the board bus type and PCI IRQ before
* calling AscInitGetConfig().
@@ -17937,127 +13473,56 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#ifdef CONFIG_ISA
case ASC_IS_ISA:
shost->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
+ share_irq = 0;
break;
case ASC_IS_VL:
shost->unchecked_isa_dma = FALSE;
- share_irq = FALSE;
+ share_irq = 0;
break;
case ASC_IS_EISA:
shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
+ share_irq = IRQF_SHARED;
break;
#endif /* CONFIG_ISA */
#ifdef CONFIG_PCI
case ASC_IS_PCI:
- shost->irq = asc_dvc_varp->irq_no = pdev->irq;
- asc_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
+ share_irq = IRQF_SHARED;
break;
#endif /* CONFIG_PCI */
default:
- ASC_PRINT2
- ("advansys_board_found: board %d: unknown adapter type: %d\n",
- boardp->id, asc_dvc_varp->bus_type);
+ shost_printk(KERN_ERR, shost, "unknown adapter type: "
+ "%d\n", asc_dvc_varp->bus_type);
shost->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
+ share_irq = 0;
break;
}
- } else {
- adv_dvc_varp->cfg->dev = dev;
- /*
- * For Wide boards set PCI information before calling
- * AdvInitGetConfig().
- */
-#ifdef CONFIG_PCI
- shost->irq = adv_dvc_varp->irq_no = pdev->irq;
- adv_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
- shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
-#endif /* CONFIG_PCI */
- }
- /*
- * Read the board configuration.
- */
- if (ASC_NARROW_BOARD(boardp)) {
/*
* NOTE: AscInitGetConfig() may change the board's
* bus_type value. The bus_type value should no
* longer be used. If the bus_type field must be
* referenced only use the bit-wise AND operator "&".
*/
- ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
- switch (ret = AscInitGetConfig(asc_dvc_varp)) {
- case 0: /* No error */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2
- ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if ((err_code = asc_dvc_varp->err_code) != 0) {
- ASC_PRINT3
- ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, asc_dvc_varp->err_code);
- }
+ ASC_DBG(2, "AscInitGetConfig()\n");
+ ret = AscInitGetConfig(shost) ? -ENODEV : 0;
} else {
- ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
- if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
- ASC_PRINT2
- ("AdvInitGetConfig: board %d: warning: 0x%x\n",
- boardp->id, ret);
- }
- if ((err_code = adv_dvc_varp->err_code) != 0) {
- ASC_PRINT2
- ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- }
- }
+#ifdef CONFIG_PCI
+ /*
+ * For Wide boards set PCI information before calling
+ * AdvInitGetConfig().
+ */
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = IRQF_SHARED;
+ ASC_DBG(2, "AdvInitGetConfig()\n");
- if (err_code != 0) {
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#endif /* CONFIG_PCI */
}
+ if (ret)
+ goto err_free_proc;
+
/*
* Save the EEPROM configuration so that it can be displayed
* from /proc/scsi/advansys/[0...].
@@ -18098,61 +13563,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
/*
* Modify board configuration.
*/
- ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
- switch (ret = AscInitSetConfig(asc_dvc_varp)) {
- case 0: /* No error. */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2
- ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if (asc_dvc_varp->err_code != 0) {
- ASC_PRINT3
- ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, asc_dvc_varp->err_code);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
- shost->irq = asc_dvc_varp->irq_no;
- }
+ ASC_DBG(2, "AscInitSetConfig()\n");
+ ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0;
+ if (ret)
+ goto err_free_proc;
} else {
ADVEEP_3550_CONFIG *ep_3550;
ADVEEP_38C0800_CONFIG *ep_38C0800;
@@ -18246,11 +13660,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
*/
boardp->init_tidmask |=
ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- shost->irq = adv_dvc_varp->irq_no;
}
/*
@@ -18262,6 +13671,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
if (ASC_NARROW_BOARD(boardp)) {
shost->max_id = ASC_MAX_TID + 1;
shost->max_lun = ASC_MAX_LUN + 1;
+ shost->max_cmd_len = ASC_MAX_CDB_LEN;
shost->io_port = asc_dvc_varp->iop_base;
boardp->asc_n_io_port = ASC_IOADR_GAP;
@@ -18272,6 +13682,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
} else {
shost->max_id = ADV_MAX_TID + 1;
shost->max_lun = ADV_MAX_LUN + 1;
+ shost->max_cmd_len = ADV_MAX_CDB_LEN;
/*
* Save the I/O Port address and length even though
@@ -18280,7 +13691,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* PCI Memory Mapped I/O.
*/
shost->io_port = iop;
- boardp->asc_n_io_port = iolen;
shost->this_id = adv_dvc_varp->chip_scsi_id;
@@ -18289,15 +13699,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
}
/*
- * 'n_io_port' currently is one byte.
- *
- * Set a value to 'n_io_port', but never referenced it because
- * it may be truncated.
- */
- shost->n_io_port = boardp->asc_n_io_port <= 255 ?
- boardp->asc_n_io_port : 255;
-
- /*
* Following v1.3.89, 'cmd_per_lun' is no longer needed
* and should be set to zero.
*
@@ -18343,14 +13744,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
shost->sg_tablesize = SG_ALL;
}
- ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
+ ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize);
/* BIOS start address. */
if (ASC_NARROW_BOARD(boardp)) {
- shost->base = ((ulong)
- AscGetChipBiosAddress(asc_dvc_varp->
- iop_base,
- asc_dvc_varp->bus_type));
+ shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
+ asc_dvc_varp->bus_type);
} else {
/*
* Fill-in BIOS board variables. The Wide BIOS saves
@@ -18365,12 +13764,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
AdvReadWordLram(adv_dvc_varp->iop_base,
BIOS_CODELEN, boardp->bios_codelen);
- ASC_DBG2(1,
- "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
+ ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n",
boardp->bios_signature, boardp->bios_version);
- ASC_DBG2(1,
- "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+ ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n",
boardp->bios_codeseg, boardp->bios_codelen);
/*
@@ -18392,30 +13789,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* Register Board Resources - I/O Port, DMA, IRQ
*/
- /*
- * Register I/O port range.
- *
- * For Wide boards the I/O ports are not used to access
- * the board, but request the region anyway.
- *
- * 'shost->n_io_port' is not referenced, because it may be truncated.
- */
- ASC_DBG2(2,
- "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
- (ulong)shost->io_port, boardp->asc_n_io_port);
- if (request_region(shost->io_port, boardp->asc_n_io_port,
- "advansys") == NULL) {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
- boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
-
/* Register DMA Channel for Narrow boards. */
shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
#ifdef CONFIG_ISA
@@ -18423,19 +13796,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
/* Register DMA channel for ISA bus. */
if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
- if ((ret =
- request_dma(shost->dma_channel, "advansys")) != 0) {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_dma() %d failed %d\n",
- boardp->id, shost->dma_channel, ret);
- release_region(shost->io_port,
- boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ ret = request_dma(shost->dma_channel, DRV_NAME);
+ if (ret) {
+ shost_printk(KERN_ERR, shost, "request_dma() "
+ "%d failed %d\n",
+ shost->dma_channel, ret);
+ goto err_free_proc;
}
AscEnableIsaDma(shost->dma_channel);
}
@@ -18443,573 +13809,392 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#endif /* CONFIG_ISA */
/* Register IRQ Number. */
- ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
- /*
- * If request_irq() fails with the IRQF_DISABLED flag set,
- * then try again without the IRQF_DISABLED flag set. This
- * allows IRQ sharing to work even with other drivers that
- * do not set the IRQF_DISABLED flag.
- *
- * If IRQF_DISABLED is not set, then interrupts are enabled
- * before the driver interrupt function is called.
- */
- if (((ret = request_irq(shost->irq, advansys_interrupt,
- IRQF_DISABLED | (share_irq ==
- TRUE ?
- IRQF_SHARED :
- 0), "advansys", boardp)) != 0)
- &&
- ((ret =
- request_irq(shost->irq, advansys_interrupt,
- (share_irq == TRUE ? IRQF_SHARED : 0),
- "advansys", boardp)) != 0)) {
+ ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost);
+
+ ret = request_irq(boardp->irq, advansys_interrupt, share_irq,
+ DRV_NAME, shost);
+
+ if (ret) {
if (ret == -EBUSY) {
- ASC_PRINT2
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
- boardp->id, shost->irq);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "already in use\n", boardp->irq);
} else if (ret == -EINVAL) {
- ASC_PRINT2
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
- boardp->id, shost->irq);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "not valid\n", boardp->irq);
} else {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
- boardp->id, shost->irq, ret);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "failed with %d\n", boardp->irq, ret);
}
- release_region(shost->io_port, boardp->asc_n_io_port);
- iounmap(boardp->ioremap_addr);
- if (shost->dma_channel != NO_ISA_DMA) {
- free_dma(shost->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ goto err_free_dma;
}
/*
* Initialize board RISC chip and enable interrupts.
*/
if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
+ ASC_DBG(2, "AscInitAsc1000Driver()\n");
warn_code = AscInitAsc1000Driver(asc_dvc_varp);
- err_code = asc_dvc_varp->err_code;
- if (warn_code || err_code) {
- ASC_PRINT4
- ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, warn_code, err_code);
+ if (warn_code || asc_dvc_varp->err_code) {
+ shost_printk(KERN_ERR, shost, "error: init_state 0x%x, "
+ "warn 0x%x, error 0x%x\n",
+ asc_dvc_varp->init_state, warn_code,
+ asc_dvc_varp->err_code);
+ if (asc_dvc_varp->err_code)
+ ret = -ENODEV;
}
} else {
- ADV_CARR_T *carrp;
- int req_cnt = 0;
- adv_req_t *reqp = NULL;
- int sg_cnt = 0;
-
- /*
- * Allocate buffer carrier structures. The total size
- * is about 4 KB, so allocate all at once.
- */
- carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
- ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
-
- if (carrp == NULL) {
- goto kmalloc_error;
- }
+ if (advansys_wide_init_chip(shost))
+ ret = -ENODEV;
+ }
- /*
- * Allocate up to 'max_host_qng' request structures for
- * the Wide board. The total size is about 16 KB, so
- * allocate all at once. If the allocation fails decrement
- * and try again.
- */
- for (req_cnt = adv_dvc_varp->max_host_qng;
- req_cnt > 0; req_cnt--) {
+ if (ret)
+ goto err_free_wide_mem;
- reqp = (adv_req_t *)
- kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+ ASC_DBG_PRT_SCSI_HOST(2, shost);
- ASC_DBG3(1,
- "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
- (ulong)reqp, req_cnt,
- (ulong)sizeof(adv_req_t) * req_cnt);
+ ret = scsi_add_host(shost, boardp->dev);
+ if (ret)
+ goto err_free_wide_mem;
- if (reqp != NULL) {
- break;
- }
- }
- if (reqp == NULL) {
- goto kmalloc_error;
- }
+ scsi_scan_host(shost);
+ return 0;
- /*
- * Allocate up to ADV_TOT_SG_BLOCK request structures for
- * the Wide board. Each structure is about 136 bytes.
- */
- boardp->adv_sgblkp = NULL;
- for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+ err_free_wide_mem:
+ advansys_wide_free_mem(boardp);
+ free_irq(boardp->irq, shost);
+ err_free_dma:
+ if (shost->dma_channel != NO_ISA_DMA)
+ free_dma(shost->dma_channel);
+ err_free_proc:
+ kfree(boardp->prtbuf);
+ err_unmap:
+ if (boardp->ioremap_addr)
+ iounmap(boardp->ioremap_addr);
+ err_shost:
+ return ret;
+}
- sgp = (adv_sgblk_t *)
- kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+static int advansys_release(struct Scsi_Host *shost)
+{
+ struct asc_board *board = shost_priv(shost);
+ ASC_DBG(1, "begin\n");
+ scsi_remove_host(shost);
+ free_irq(board->irq, shost);
+ if (shost->dma_channel != NO_ISA_DMA) {
+ ASC_DBG(1, "free_dma()\n");
+ free_dma(shost->dma_channel);
+ }
+ if (ASC_NARROW_BOARD(board)) {
+ dma_unmap_single(board->dev,
+ board->dvc_var.asc_dvc_var.overrun_dma,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ } else {
+ iounmap(board->ioremap_addr);
+ advansys_wide_free_mem(board);
+ }
+ kfree(board->prtbuf);
+ scsi_host_put(shost);
+ ASC_DBG(1, "end\n");
+ return 0;
+}
- if (sgp == NULL) {
- break;
- }
+#define ASC_IOADR_TABLE_MAX_IX 11
- sgp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgp;
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
+ 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
+ 0x0210, 0x0230, 0x0250, 0x0330
+};
- }
- ASC_DBG3(1,
- "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
- sg_cnt, sizeof(adv_sgblk_t),
- (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+/*
+ * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw. It decodes as:
+ * 00: 10
+ * 01: 11
+ * 10: 12
+ * 11: 15
+ */
+static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
+{
+ unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+ unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10;
+ if (chip_irq == 13)
+ chip_irq = 15;
+ return chip_irq;
+}
- /*
- * If no request structures or scatter-gather structures could
- * be allocated, then return an error. Otherwise continue with
- * initialization.
- */
- kmalloc_error:
- if (carrp == NULL) {
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (reqp == NULL) {
- kfree(carrp);
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (boardp->adv_sgblkp == NULL) {
- kfree(carrp);
- kfree(reqp);
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else {
+static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
+{
+ int err = -ENODEV;
+ PortAddr iop_base = _asc_def_iop_base[id];
+ struct Scsi_Host *shost;
+ struct asc_board *board;
- /* Save carrier buffer pointer. */
- boardp->orig_carrp = carrp;
+ if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+ ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+ return -ENODEV;
+ }
+ ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+ if (!AscFindSignature(iop_base))
+ goto release_region;
+ if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
+ goto release_region;
- /*
- * Save original pointer for kfree() in case the
- * driver is built as a module and can be unloaded.
- */
- boardp->orig_reqp = reqp;
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
- adv_dvc_varp->carrier_buf = carrp;
+ board = shost_priv(shost);
+ board->irq = advansys_isa_irq_no(iop_base);
+ board->dev = dev;
- /*
- * Point 'adv_reqp' to the request structures and
- * link them together.
- */
- req_cnt--;
- reqp[req_cnt].next_reqp = NULL;
- for (; req_cnt > 0; req_cnt--) {
- reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
- }
- boardp->adv_reqp = &reqp[0];
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc3550Driver()\n");
- warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
- } else if (adv_dvc_varp->chip_type ==
- ADV_CHIP_ASC38C0800) {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc38C0800Driver()\n");
- warn_code =
- AdvInitAsc38C0800Driver(adv_dvc_varp);
- } else {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc38C1600Driver()\n");
- warn_code =
- AdvInitAsc38C1600Driver(adv_dvc_varp);
- }
- err_code = adv_dvc_varp->err_code;
+ err = advansys_board_found(shost, iop_base, ASC_IS_ISA);
+ if (err)
+ goto free_host;
- if (warn_code || err_code) {
- ASC_PRINT3
- ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
- boardp->id, warn_code, err_code);
- }
- }
- }
+ dev_set_drvdata(dev, shost);
+ return 0;
- if (err_code != 0) {
- release_region(shost->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL) {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
- if (shost->dma_channel != NO_ISA_DMA) {
- free_dma(shost->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- free_irq(shost->irq, boardp);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
- ASC_DBG_PRT_SCSI_HOST(2, shost);
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ release_region(iop_base, ASC_IOADR_GAP);
+ return err;
+}
- return shost;
+static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
+{
+ int ioport = _asc_def_iop_base[id];
+ advansys_release(dev_get_drvdata(dev));
+ release_region(ioport, ASC_IOADR_GAP);
+ return 0;
}
+static struct isa_driver advansys_isa_driver = {
+ .probe = advansys_isa_probe,
+ .remove = __devexit_p(advansys_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
/*
- * advansys_detect()
- *
- * Detect function for AdvanSys adapters.
- *
- * Argument is a pointer to the host driver's scsi_hosts entry.
- *
- * Return number of adapters found.
- *
- * Note: Because this function is called during system initialization
- * it must not call SCSI mid-level functions including scsi_malloc()
- * and scsi_free().
+ * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw. It decodes as:
+ * 000: invalid
+ * 001: 10
+ * 010: 11
+ * 011: 12
+ * 100: invalid
+ * 101: 14
+ * 110: 15
+ * 111: invalid
*/
-static int __init advansys_detect(struct scsi_host_template *tpnt)
+static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
{
- static int detect_called = ASC_FALSE;
- int iop;
- int bus;
- int ioport = 0;
- struct device *dev = NULL;
-#ifdef CONFIG_PCI
- int pci_init_search = 0;
- struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
- int pci_card_cnt_max = 0;
- int pci_card_cnt = 0;
- struct pci_dev *pdev = NULL;
- int pci_device_id_cnt = 0;
- unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
- PCI_DEVICE_ID_ASP_1200A,
- PCI_DEVICE_ID_ASP_ABP940,
- PCI_DEVICE_ID_ASP_ABP940U,
- PCI_DEVICE_ID_ASP_ABP940UW,
- PCI_DEVICE_ID_38C0800_REV1,
- PCI_DEVICE_ID_38C1600_REV1
- };
-#endif /* CONFIG_PCI */
-
- if (detect_called == ASC_FALSE) {
- detect_called = ASC_TRUE;
- } else {
- printk
- ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+ unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+ unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9;
+ if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15))
return 0;
- }
-
- ASC_DBG(1, "advansys_detect: begin\n");
+ return chip_irq;
+}
- asc_board_count = 0;
+static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
+{
+ int err = -ENODEV;
+ PortAddr iop_base = _asc_def_iop_base[id];
+ struct Scsi_Host *shost;
+ struct asc_board *board;
+ if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+ ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+ return -ENODEV;
+ }
+ ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+ if (!AscFindSignature(iop_base))
+ goto release_region;
/*
- * If I/O port probing has been modified, then verify and
- * clean-up the 'asc_ioport' list.
+ * I don't think this condition can actually happen, but the old
+ * driver did it, and the chances of finding a VLB setup in 2007
+ * to do testing with is slight to none.
*/
- if (asc_iopflag == ASC_TRUE) {
- for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
- ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
- ioport, asc_ioport[ioport]);
- if (asc_ioport[ioport] != 0) {
- for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
- iop++) {
- if (_asc_def_iop_base[iop] ==
- asc_ioport[ioport]) {
- break;
- }
- }
- if (iop == ASC_IOADR_TABLE_MAX_IX) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
- asc_ioport[ioport]);
- asc_ioport[ioport] = 0;
- }
- }
- }
- ioport = 0;
- }
+ if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
+ goto release_region;
- for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
- ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
- bus, asc_bus_name[bus]);
- iop = 0;
+ board = shost_priv(shost);
+ board->irq = advansys_vlb_irq_no(iop_base);
+ board->dev = dev;
- while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+ err = advansys_board_found(shost, iop_base, ASC_IS_VL);
+ if (err)
+ goto free_host;
- ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
- asc_board_count);
+ dev_set_drvdata(dev, shost);
+ return 0;
- switch (asc_bus[bus]) {
- case ASC_IS_ISA:
- case ASC_IS_VL:
-#ifdef CONFIG_ISA
- if (asc_iopflag == ASC_FALSE) {
- iop =
- AscSearchIOPortAddr(iop,
- asc_bus[bus]);
- } else {
- /*
- * ISA and VL I/O port scanning has either been
- * eliminated or limited to selected ports on
- * the LILO command line, /etc/lilo.conf, or
- * by setting variables when the module was loaded.
- */
- ASC_DBG(1,
- "advansys_detect: I/O port scanning modified\n");
- ioport_try_again:
- iop = 0;
- for (; ioport < ASC_NUM_IOPORT_PROBE;
- ioport++) {
- if ((iop =
- asc_ioport[ioport]) != 0) {
- break;
- }
- }
- if (iop) {
- ASC_DBG1(1,
- "advansys_detect: probing I/O port 0x%x...\n",
- iop);
- if (!request_region
- (iop, ASC_IOADR_GAP,
- "advansys")) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
- iop);
- /* Don't try this I/O port twice. */
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else if (AscFindSignature(iop)
- == ASC_FALSE) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
- iop);
- /* Don't try this I/O port twice. */
- release_region(iop,
- ASC_IOADR_GAP);
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else {
- /*
- * If this isn't an ISA board, then it must be
- * a VL board. If currently looking an ISA
- * board is being looked for then try for
- * another ISA board in 'asc_ioport'.
- */
- if (asc_bus[bus] ==
- ASC_IS_ISA
- &&
- (AscGetChipVersion
- (iop,
- ASC_IS_ISA) &
- ASC_CHIP_VER_ISA_BIT)
- == 0) {
- /*
- * Don't clear 'asc_ioport[ioport]'. Try
- * this board again for VL. Increment
- * 'ioport' past this board.
- */
- ioport++;
- release_region
- (iop,
- ASC_IOADR_GAP);
- goto ioport_try_again;
- }
- }
- /*
- * This board appears good, don't try the I/O port
- * again by clearing its value. Increment 'ioport'
- * for the next iteration.
- */
- asc_ioport[ioport++] = 0;
- }
- }
-#endif /* CONFIG_ISA */
- break;
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ release_region(iop_base, ASC_IOADR_GAP);
+ return -ENODEV;
+}
- case ASC_IS_EISA:
-#ifdef CONFIG_ISA
- iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-#endif /* CONFIG_ISA */
- break;
+static struct isa_driver advansys_vlb_driver = {
+ .probe = advansys_vlb_probe,
+ .remove = __devexit_p(advansys_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "advansys_vlb",
+ },
+};
- case ASC_IS_PCI:
-#ifdef CONFIG_PCI
- if (pci_init_search == 0) {
- int i, j;
-
- pci_init_search = 1;
-
- /* Find all PCI cards. */
- while (pci_device_id_cnt <
- ASC_PCI_DEVICE_ID_CNT) {
- if ((pdev =
- pci_find_device
- (PCI_VENDOR_ID_ASP,
- pci_device_id
- [pci_device_id_cnt],
- pdev)) == NULL) {
- pci_device_id_cnt++;
- } else {
- if (pci_enable_device
- (pdev) == 0) {
- pci_devicep
- [pci_card_cnt_max++]
- = pdev;
- }
- }
- }
+static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
+ { "ABP7401" },
+ { "ABP7501" },
+ { "" }
+};
- /*
- * Sort PCI cards in ascending order by PCI Bus, Slot,
- * and Device Number.
- */
- for (i = 0; i < pci_card_cnt_max - 1;
- i++) {
- for (j = i + 1;
- j < pci_card_cnt_max;
- j++) {
- if ((pci_devicep[j]->
- bus->number <
- pci_devicep[i]->
- bus->number)
- ||
- ((pci_devicep[j]->
- bus->number ==
- pci_devicep[i]->
- bus->number)
- &&
- (pci_devicep[j]->
- devfn <
- pci_devicep[i]->
- devfn))) {
- pdev =
- pci_devicep
- [i];
- pci_devicep[i] =
- pci_devicep
- [j];
- pci_devicep[j] =
- pdev;
- }
- }
- }
+MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
- pci_card_cnt = 0;
- } else {
- pci_card_cnt++;
- }
+/*
+ * EISA is a little more tricky than PCI; each EISA device may have two
+ * channels, and this driver is written to make each channel its own Scsi_Host
+ */
+struct eisa_scsi_data {
+ struct Scsi_Host *host[2];
+};
- if (pci_card_cnt == pci_card_cnt_max) {
- iop = 0;
- } else {
- pdev = pci_devicep[pci_card_cnt];
-
- ASC_DBG2(2,
- "advansys_detect: devfn %d, bus number %d\n",
- pdev->devfn,
- pdev->bus->number);
- iop = pci_resource_start(pdev, 0);
- ASC_DBG2(1,
- "advansys_detect: vendorID %X, deviceID %X\n",
- pdev->vendor,
- pdev->device);
- ASC_DBG2(2,
- "advansys_detect: iop %X, irqLine %d\n",
- iop, pdev->irq);
- }
- if (pdev)
- dev = &pdev->dev;
+/*
+ * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw. It decodes as:
+ * 000: 10
+ * 001: 11
+ * 010: 12
+ * 011: invalid
+ * 100: 14
+ * 101: 15
+ * 110: invalid
+ * 111: invalid
+ */
+static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
+{
+ unsigned short cfg_lsw = inw(edev->base_addr + 0xc86);
+ unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10;
+ if ((chip_irq == 13) || (chip_irq > 15))
+ return 0;
+ return chip_irq;
+}
-#endif /* CONFIG_PCI */
- break;
+static int __devinit advansys_eisa_probe(struct device *dev)
+{
+ int i, ioport, irq = 0;
+ int err;
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct eisa_scsi_data *data;
- default:
- ASC_PRINT1
- ("advansys_detect: unknown bus type: %d\n",
- asc_bus[bus]);
- break;
- }
- ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+ err = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto fail;
+ ioport = edev->base_addr + 0xc30;
- /*
- * Adapter not found, try next bus type.
- */
- if (iop == 0) {
- break;
- }
+ err = -ENODEV;
+ for (i = 0; i < 2; i++, ioport += 0x20) {
+ struct asc_board *board;
+ struct Scsi_Host *shost;
+ if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
+ printk(KERN_WARNING "Region %x-%x busy\n", ioport,
+ ioport + ASC_IOADR_GAP - 1);
+ continue;
+ }
+ if (!AscFindSignature(ioport)) {
+ release_region(ioport, ASC_IOADR_GAP);
+ continue;
+ }
- advansys_board_found(iop, dev, asc_bus[bus]);
+ /*
+ * I don't know why we need to do this for EISA chips, but
+ * not for any others. It looks to be equivalent to
+ * AscGetChipCfgMsw, but I may have overlooked something,
+ * so I'm not converting it until I get an EISA board to
+ * test with.
+ */
+ inw(ioport + 4);
+
+ if (!irq)
+ irq = advansys_eisa_irq_no(edev);
+
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
+
+ board = shost_priv(shost);
+ board->irq = irq;
+ board->dev = dev;
+
+ err = advansys_board_found(shost, ioport, ASC_IS_EISA);
+ if (!err) {
+ data->host[i] = shost;
+ continue;
}
+
+ scsi_host_put(shost);
+ release_region:
+ release_region(ioport, ASC_IOADR_GAP);
+ break;
}
- ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
- asc_board_count);
- return asc_board_count;
+ if (err)
+ goto free_data;
+ dev_set_drvdata(dev, data);
+ return 0;
+
+ free_data:
+ kfree(data->host[0]);
+ kfree(data->host[1]);
+ kfree(data);
+ fail:
+ return err;
}
-/*
- * advansys_release()
- *
- * Release resources allocated for a single AdvanSys adapter.
- */
-static int advansys_release(struct Scsi_Host *shost)
+static __devexit int advansys_eisa_remove(struct device *dev)
{
- asc_board_t *boardp;
+ int i;
+ struct eisa_scsi_data *data = dev_get_drvdata(dev);
- ASC_DBG(1, "advansys_release: begin\n");
- boardp = ASC_BOARDP(shost);
- free_irq(shost->irq, boardp);
- if (shost->dma_channel != NO_ISA_DMA) {
- ASC_DBG(1, "advansys_release: free_dma()\n");
- free_dma(shost->dma_channel);
+ for (i = 0; i < 2; i++) {
+ int ioport;
+ struct Scsi_Host *shost = data->host[i];
+ if (!shost)
+ continue;
+ ioport = shost->io_port;
+ advansys_release(shost);
+ release_region(ioport, ASC_IOADR_GAP);
}
- release_region(shost->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- adv_sgblk_t *sgp = NULL;
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL) {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
-#ifdef CONFIG_PROC_FS
- ASC_ASSERT(boardp->prtbuf != NULL);
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- ASC_DBG(1, "advansys_release: end\n");
+ kfree(data);
return 0;
}
-#ifdef CONFIG_PCI
+static struct eisa_driver advansys_eisa_driver = {
+ .id_table = advansys_eisa_table,
+ .driver = {
+ .name = DRV_NAME,
+ .probe = advansys_eisa_probe,
+ .remove = __devexit_p(advansys_eisa_remove),
+ }
+};
+
/* PCI Devices supported by this driver */
static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
@@ -19028,4 +14213,131 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
};
MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
-#endif /* CONFIG_PCI */
+
+static void __devinit advansys_set_latency(struct pci_dev *pdev)
+{
+ if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+ (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
+ } else {
+ u8 latency;
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+ if (latency < 0x20)
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
+ }
+}
+
+static int __devinit
+advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err, ioport;
+ struct Scsi_Host *shost;
+ struct asc_board *board;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+ advansys_set_latency(pdev);
+
+ err = -ENODEV;
+ if (pci_resource_len(pdev, 0) == 0)
+ goto release_region;
+
+ ioport = pci_resource_start(pdev, 0);
+
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
+
+ board = shost_priv(shost);
+ board->irq = pdev->irq;
+ board->dev = &pdev->dev;
+
+ if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+ pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+ pdev->device == PCI_DEVICE_ID_38C1600_REV1) {
+ board->flags |= ASC_IS_WIDE_BOARD;
+ }
+
+ err = advansys_board_found(shost, ioport, ASC_IS_PCI);
+ if (err)
+ goto free_host;
+
+ pci_set_drvdata(pdev, shost);
+ return 0;
+
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ pci_release_regions(pdev);
+ disable_device:
+ pci_disable_device(pdev);
+ fail:
+ return err;
+}
+
+static void __devexit advansys_pci_remove(struct pci_dev *pdev)
+{
+ advansys_release(pci_get_drvdata(pdev));
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver advansys_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = advansys_pci_tbl,
+ .probe = advansys_pci_probe,
+ .remove = __devexit_p(advansys_pci_remove),
+};
+
+static int __init advansys_init(void)
+{
+ int error;
+
+ error = isa_register_driver(&advansys_isa_driver,
+ ASC_IOADR_TABLE_MAX_IX);
+ if (error)
+ goto fail;
+
+ error = isa_register_driver(&advansys_vlb_driver,
+ ASC_IOADR_TABLE_MAX_IX);
+ if (error)
+ goto unregister_isa;
+
+ error = eisa_driver_register(&advansys_eisa_driver);
+ if (error)
+ goto unregister_vlb;
+
+ error = pci_register_driver(&advansys_pci_driver);
+ if (error)
+ goto unregister_eisa;
+
+ return 0;
+
+ unregister_eisa:
+ eisa_driver_unregister(&advansys_eisa_driver);
+ unregister_vlb:
+ isa_unregister_driver(&advansys_vlb_driver);
+ unregister_isa:
+ isa_unregister_driver(&advansys_isa_driver);
+ fail:
+ return error;
+}
+
+static void __exit advansys_exit(void)
+{
+ pci_unregister_driver(&advansys_pci_driver);
+ eisa_driver_unregister(&advansys_eisa_driver);
+ isa_unregister_driver(&advansys_vlb_driver);
+ isa_unregister_driver(&advansys_isa_driver);
+}
+
+module_init(advansys_init);
+module_exit(advansys_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index d30a30786dd..f08e71e0205 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -907,9 +907,10 @@ out_host_put:
void aha152x_release(struct Scsi_Host *shpnt)
{
- if(!shpnt)
+ if (!shpnt)
return;
+ scsi_remove_host(shpnt);
if (shpnt->irq)
free_irq(shpnt->irq, shpnt);
@@ -923,7 +924,6 @@ void aha152x_release(struct Scsi_Host *shpnt)
pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
#endif
- scsi_remove_host(shpnt);
list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
}
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 4998bb850c4..1a71b0236c9 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -8416,10 +8416,9 @@ aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp)
*p = *temp;
p->host = host;
- p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
- if (p->scb_data != NULL)
+ p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (!p->scb_data)
{
- memset(p->scb_data, 0, sizeof(scb_data_type));
scbq_init (&p->scb_data->free_scbs);
}
else
@@ -9196,10 +9195,9 @@ aic7xxx_detect(struct scsi_host_template *template)
printk(KERN_INFO " this driver, we are ignoring it.\n");
}
}
- else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+ else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host),
GFP_ATOMIC)) != NULL )
{
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
temp_p->flags = aic_pdevs[i].flags;
temp_p->features = aic_pdevs[i].features;
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index c6c3d18222f..491e5d8a98b 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -40,18 +40,6 @@
#define ASD_MAX_PHYS 8
#define ASD_PCBA_SN_SIZE 12
-/* Those are to be further named properly, the "RAZORx" part, and
- * subsequently included in include/linux/pci_ids.h.
- */
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
-
struct asd_ha_addrspace {
void __iomem *addr;
unsigned long start; /* pci resource start */
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 63bcde24644..b70d6e7f96e 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -583,7 +583,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
if (!asd_ha) {
asd_printk("out of memory\n");
- goto Err;
+ goto Err_put;
}
asd_ha->pcidev = dev;
asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
@@ -600,14 +600,12 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
shost->max_cmd_len = 16;
err = scsi_add_host(shost, &dev->dev);
- if (err) {
- scsi_host_put(shost);
+ if (err)
goto Err_free;
- }
err = asd_dev->setup(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = -ENODEV;
if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
@@ -618,14 +616,14 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
;
else {
asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
- goto Err_free;
+ goto Err_remove;
}
pci_set_drvdata(dev, asd_ha);
err = asd_map_ha(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = asd_create_ha_caches(asd_ha);
if (err)
@@ -692,9 +690,12 @@ Err_free_cache:
asd_destroy_ha_caches(asd_ha);
Err_unmap:
asd_unmap_ha(asd_ha);
+Err_remove:
+ scsi_remove_host(shost);
Err_free:
kfree(asd_ha);
- scsi_remove_host(shost);
+Err_put:
+ scsi_host_put(shost);
Err:
pci_disable_device(dev);
return err;
@@ -829,22 +830,15 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
};
static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
- 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2},
{}
};
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index ab13824df85..f2b23e01401 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -207,7 +207,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
"stat(0x%x) is not CHECK_CONDITION"
"\n",
SAS_ADDR(task->dev->sas_addr),
- ts->stat);
+ iu->status);
}
}
} else {
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index f0b8bf4534f..ace7a15b413 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -45,19 +45,26 @@
#include <linux/interrupt.h>
struct class_device_attribute;
-
-#define ARCMSR_MAX_OUTSTANDING_CMD 256
-#define ARCMSR_MAX_FREECCB_NUM 288
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14"
+/*The limit of outstanding scsi command that firmware can handle*/
+#define ARCMSR_MAX_OUTSTANDING_CMD 256
+#define ARCMSR_MAX_FREECCB_NUM 320
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
-#define ARCMSR_MAX_XFER_SECTORS_B 4096
-#define ARCMSR_MAX_TARGETID 17
-#define ARCMSR_MAX_TARGETLUN 8
-#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
-#define ARCMSR_MAX_QBUFFER 4096
-#define ARCMSR_MAX_SG_ENTRIES 38
-
+#define ARCMSR_MAX_XFER_SECTORS_B 4096
+#define ARCMSR_MAX_TARGETID 17
+#define ARCMSR_MAX_TARGETLUN 8
+#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER 4096
+#define ARCMSR_MAX_SG_ENTRIES 38
+#define ARCMSR_MAX_HBB_POSTQUEUE 264
+/*
+**********************************************************************************
+**
+**********************************************************************************
+*/
+#define ARC_SUCCESS 0
+#define ARC_FAILURE 1
/*
*******************************************************************************
** split 64bits dma addressing
@@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD
uint8_t messagedatabuffer[1032];
};
/* IOP message transfer */
-#define ARCMSR_MESSAGE_FAIL 0x0001
+#define ARCMSR_MESSAGE_FAIL 0x0001
/* DeviceType */
#define ARECA_SATA_RAID 0x90000000
/* FunctionCode */
@@ -163,27 +170,27 @@ struct QBUFFER
};
/*
*******************************************************************************
-** FIRMWARE INFO
+** FIRMWARE INFO for Intel IOP R 80331 processor (Type A)
*******************************************************************************
*/
struct FIRMWARE_INFO
{
- uint32_t signature; /*0, 00-03*/
- uint32_t request_len; /*1, 04-07*/
- uint32_t numbers_queue; /*2, 08-11*/
+ uint32_t signature; /*0, 00-03*/
+ uint32_t request_len; /*1, 04-07*/
+ uint32_t numbers_queue; /*2, 08-11*/
uint32_t sdram_size; /*3, 12-15*/
- uint32_t ide_channels; /*4, 16-19*/
- char vendor[40]; /*5, 20-59*/
- char model[8]; /*15, 60-67*/
- char firmware_ver[16]; /*17, 68-83*/
- char device_map[16]; /*21, 84-99*/
+ uint32_t ide_channels; /*4, 16-19*/
+ char vendor[40]; /*5, 20-59*/
+ char model[8]; /*15, 60-67*/
+ char firmware_ver[16]; /*17, 68-83*/
+ char device_map[16]; /*21, 84-99*/
};
/* signature of set and get firmware config */
-#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
-#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
+#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
/* message code of inbound message register */
-#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
-#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
+#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
@@ -203,6 +210,60 @@ struct FIRMWARE_INFO
#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
/* outbound firmware ok */
#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+
+/*
+************************************************************************
+** SPEC. for Areca Type B adapter
+************************************************************************
+*/
+/* ARECA HBB COMMAND for its FIRMWARE */
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL 0x00020400
+#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
+#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* ARECA FLAG LANGUAGE */
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002
+#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004
+#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+
+#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F
+#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0
+#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7
+/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008
+/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008
+/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008
+/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008
+/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008
+/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_START_BGRB 0x00060008
+#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008
+#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008
+/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
+#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002
+#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004
+#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008
+
+/* data tunnel buffer between user space program and its firmware */
+/* user space data to iop 128bytes */
+#define ARCMSR_IOCTL_WBUFFER 0x0000fe00
+/* iop data to user space 128bytes */
+#define ARCMSR_IOCTL_RBUFFER 0x0000ff00
+/* iop message_rwbuffer for message command */
+#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -214,7 +275,6 @@ struct ARCMSR_CDB
uint8_t TargetID;
uint8_t LUN;
uint8_t Function;
-
uint8_t CdbLength;
uint8_t sgcount;
uint8_t Flags;
@@ -224,20 +284,18 @@ struct ARCMSR_CDB
#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
#define ARCMSR_CDB_FLAG_HEADQ 0x08
#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
- uint8_t Reserved1;
+ uint8_t Reserved1;
uint32_t Context;
uint32_t DataLength;
-
uint8_t Cdb[16];
-
uint8_t DeviceStatus;
-#define ARCMSR_DEV_CHECK_CONDITION 0x02
-#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
-#define ARCMSR_DEV_ABORTED 0xF1
-#define ARCMSR_DEV_INIT_FAIL 0xF2
- uint8_t SenseData[15];
+#define ARCMSR_DEV_CHECK_CONDITION 0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
+#define ARCMSR_DEV_ABORTED 0xF1
+#define ARCMSR_DEV_INIT_FAIL 0xF2
+ uint8_t SenseData[15];
union
{
struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
@@ -246,10 +304,10 @@ struct ARCMSR_CDB
};
/*
*******************************************************************************
-** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor
*******************************************************************************
*/
-struct MessageUnit
+struct MessageUnit_A
{
uint32_t resrved0[4]; /*0000 000F*/
uint32_t inbound_msgaddr0; /*0010 0013*/
@@ -274,6 +332,30 @@ struct MessageUnit
uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
uint32_t reserved6[32]; /*0F80 0FFF 32*/
};
+
+struct MessageUnit_B
+{
+ uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t postq_index;
+ uint32_t doneq_index;
+ uint32_t *drv2iop_doorbell_reg;
+ uint32_t *drv2iop_doorbell_mask_reg;
+ uint32_t *iop2drv_doorbell_reg;
+ uint32_t *iop2drv_doorbell_mask_reg;
+ uint32_t *msgcode_rwbuffer_reg;
+ uint32_t *ioctl_wbuffer_reg;
+ uint32_t *ioctl_rbuffer_reg;
+};
+
+struct MessageUnit
+{
+ union
+ {
+ struct MessageUnit_A pmu_A;
+ struct MessageUnit_B pmu_B;
+ } u;
+};
/*
*******************************************************************************
** Adapter Control Block
@@ -281,37 +363,45 @@ struct MessageUnit
*/
struct AdapterControlBlock
{
+ uint32_t adapter_type; /* adapter A,B..... */
+ #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */
+ #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */
+ #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */
+ #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */
struct pci_dev * pdev;
struct Scsi_Host * host;
unsigned long vir2phy_offset;
/* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable;
- struct MessageUnit __iomem * pmu;
+ struct MessageUnit * pmu;
/* message unit ATU inbound base address0 */
uint32_t acb_flags;
-#define ACB_F_SCSISTOPADAPTER 0x0001
-#define ACB_F_MSG_STOP_BGRB 0x0002
+ #define ACB_F_SCSISTOPADAPTER 0x0001
+ #define ACB_F_MSG_STOP_BGRB 0x0002
/* stop RAID background rebuild */
-#define ACB_F_MSG_START_BGRB 0x0004
+ #define ACB_F_MSG_START_BGRB 0x0004
/* stop RAID background rebuild */
-#define ACB_F_IOPDATA_OVERFLOW 0x0008
+ #define ACB_F_IOPDATA_OVERFLOW 0x0008
/* iop message data rqbuffer overflow */
-#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
+ #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
/* message clear wqbuffer */
-#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
+ #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
/* message clear rqbuffer */
-#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
-#define ACB_F_BUS_RESET 0x0080
-#define ACB_F_IOP_INITED 0x0100
+ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
+ #define ACB_F_BUS_RESET 0x0080
+ #define ACB_F_IOP_INITED 0x0100
/* iop init */
struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */
struct list_head ccb_free_list;
/* head of free ccb list */
+
atomic_t ccboutstandingcount;
+ /*The present outstanding command number that in the IOP that
+ waiting for being handled by FW*/
void * dma_coherent;
/* dma_coherent used for memory free */
@@ -353,7 +443,7 @@ struct CommandControlBlock
{
struct ARCMSR_CDB arcmsr_cdb;
/*
- ** 0-503 (size of CDB=504):
+ ** 0-503 (size of CDB = 504):
** arcmsr messenger scsi command descriptor size 504 bytes
*/
uint32_t cdb_shifted_phyaddr;
@@ -466,7 +556,9 @@ struct SENSE_DATA
#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
-extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
+extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
+extern struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *);
extern struct class_device_attribute *arcmsr_host_attrs[];
-extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *);
void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 06c0dce3b83..d04d1aa28fa 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -8,7 +8,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -49,6 +49,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/pci.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -58,15 +59,14 @@
struct class_device_attribute *arcmsr_host_attrs[];
-static ssize_t
-arcmsr_sysfs_iop_message_read(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer,*ptmpQbuffer;
int32_t allxfer_len = 0;
@@ -85,12 +85,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
allxfer_len++;
}
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
- &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ struct QBUFFER *prbuffer;
+ uint8_t *iop_data;
int32_t iop_len;
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = (uint8_t *)prbuffer->data;
iop_len = readl(&prbuffer->data_len);
while (iop_len > 0) {
acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
@@ -99,16 +100,15 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
iop_data++;
iop_len--;
}
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
return (allxfer_len);
}
-static ssize_t
-arcmsr_sysfs_iop_message_write(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -126,7 +126,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
wqbuf_lastindex = acb->wqbuf_lastindex;
wqbuf_firstindex = acb->wqbuf_firstindex;
if (wqbuf_lastindex != wqbuf_firstindex) {
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
return 0; /*need retry*/
} else {
my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
@@ -144,7 +144,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
acb->acb_flags &=
~ACB_F_MESSAGE_WQBUFFER_CLEARED;
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
}
return count;
} else {
@@ -153,15 +153,14 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
}
}
-static ssize_t
-arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer;
if (!capable(CAP_SYS_ADMIN))
@@ -169,8 +168,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
acb->acb_flags |=
(ACB_F_MESSAGE_WQBUFFER_CLEARED
@@ -191,6 +189,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
.attr = {
.name = "mu_read",
.mode = S_IRUSR ,
+ .owner = THIS_MODULE,
},
.size = 1032,
.read = arcmsr_sysfs_iop_message_read,
@@ -200,6 +199,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
.attr = {
.name = "mu_write",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1032,
.write = arcmsr_sysfs_iop_message_write,
@@ -209,6 +209,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
.attr = {
.name = "mu_clear",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1,
.write = arcmsr_sysfs_iop_message_clear,
@@ -219,31 +220,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
struct Scsi_Host *host = acb->host;
int error;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
goto error_bin_file_message_read;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
goto error_bin_file_message_write;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
goto error_bin_file_message_clear;
}
return 0;
error_bin_file_message_clear:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
error_bin_file_message_write:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
error_bin_file_message_read:
return error;
}
@@ -252,12 +248,9 @@ void
arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
struct Scsi_Host *host = acb->host;
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
}
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 0ddfc21e9f7..cfcf40159ea 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -71,33 +71,34 @@
#include <scsi/scsicam.h>
#include "arcmsr.h"
-MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+ struct scsi_cmnd *cmd);
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
static int arcmsr_abort(struct scsi_cmnd *);
static int arcmsr_bus_reset(struct scsi_cmnd *);
static int arcmsr_bios_param(struct scsi_device *sdev,
- struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd * cmd,
- void (*done) (struct scsi_cmnd *));
+ struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+ void (*done) (struct scsi_cmnd *));
static int arcmsr_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void arcmsr_remove(struct pci_dev *pdev);
static void arcmsr_shutdown(struct pci_dev *pdev);
static void arcmsr_iop_init(struct AdapterControlBlock *acb);
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state);
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
+ int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
queue_depth = ARCMSR_MAX_CMD_PERLUN;
@@ -123,17 +124,25 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
};
+#ifdef CONFIG_SCSI_ARCMSR_AER
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+
static struct pci_error_handlers arcmsr_pci_error_handlers = {
.error_detected = arcmsr_pci_error_detected,
.slot_reset = arcmsr_pci_slot_reset,
};
-
+#endif
static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
@@ -153,20 +162,20 @@ static struct pci_driver arcmsr_pci_driver = {
.probe = arcmsr_probe,
.remove = arcmsr_remove,
.shutdown = arcmsr_shutdown,
+ #ifdef CONFIG_SCSI_ARCMSR_AER
.err_handler = &arcmsr_pci_error_handlers,
+ #endif
};
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
- struct AdapterControlBlock *acb;
- unsigned long flags;
+ struct AdapterControlBlock *acb = dev_id;
- acb = (struct AdapterControlBlock *)dev_id;
-
- spin_lock_irqsave(acb->host->host_lock, flags);
+ spin_lock(acb->host->host_lock);
handle_state = arcmsr_interrupt(acb);
- spin_unlock_irqrestore(acb->host->host_lock, flags);
+ spin_unlock(acb->host->host_lock);
+
return handle_state;
}
@@ -198,68 +207,159 @@ static int arcmsr_bios_param(struct scsi_device *sdev,
return 0;
}
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- struct MessageUnit __iomem *reg = acb->pmu;
- u32 ccb_phyaddr_hi32;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
+ u16 dev_id;
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+ switch (dev_id) {
+ case 0x1201 : {
+ acb->adapter_type = ACB_ADAPTER_TYPE_B;
+ }
+ break;
+
+ default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+ }
+}
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ struct CommandControlBlock *ccb_tmp;
+ uint32_t intmask_org;
+ int i, j;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
+ acb->host->host_no);
+ }
- dma_coherent = dma_alloc_coherent(&pdev->dev,
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
ARCMSR_MAX_FREECCB_NUM *
sizeof (struct CommandControlBlock) + 0x20,
&dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent)
- return -ENOMEM;
+ if (!dma_coherent)
+ return -ENOMEM;
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
- }
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
- dma_addr = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
- acb->pccb_pool[i] = ccb_tmp;
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof (struct CommandControlBlock);
- ccb_tmp++;
- }
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+ ccb_tmp++;
+ }
- acb->vir2phy_offset = (unsigned long)ccb_tmp -
- (unsigned long)dma_addr;
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GOOD;
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
- /*
- ** here we need to tell iop 331 our ccb_tmp.HighPart
- ** if ccb_tmp.HighPart is not zero
- */
- ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
- if (ccb_phyaddr_hi32 != 0) {
- writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
- writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
- writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE "arcmsr%d: "
- "'set ccb high part physical address' timeout\n",
- acb->host->host_no);
- }
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+
+ struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_B *reg;
+ void *mem_base0, *mem_base1;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ uint32_t intmask_org;
+ struct CommandControlBlock *ccb_tmp;
+ int i, j;
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
+ ((ARCMSR_MAX_FREECCB_NUM *
+ sizeof(struct CommandControlBlock) + 0x20) +
+ sizeof(struct MessageUnit_B)),
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent)
+ return -ENOMEM;
- writel(readl(&reg->outbound_intmask) |
- ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
+
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
+
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+ ccb_tmp++;
+ }
+
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+ acb->pmu = (struct MessageUnit *)reg;
+ mem_base0 = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ mem_base1 = ioremap(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ reg->drv2iop_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_IOP2DRV_DOORBELL_MASK);
+ reg->ioctl_wbuffer_reg = (uint32_t *)((char *)mem_base1 +
+ ARCMSR_IOCTL_WBUFFER);
+ reg->ioctl_rbuffer_reg = (uint32_t *)((char *)mem_base1 +
+ ARCMSR_IOCTL_RBUFFER);
+ reg->msgcode_rwbuffer_reg = (uint32_t *)((char *)mem_base1 +
+ ARCMSR_MSGCODE_RWBUFFER);
+
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GOOD;
+
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+ }
return 0;
}
@@ -310,16 +410,11 @@ static int arcmsr_probe(struct pci_dev *pdev,
host->unique_id = (bus << 8) | dev_fun;
host->irq = pdev->irq;
error = pci_request_regions(pdev, "arcmsr");
- if (error)
+ if (error) {
goto out_host_put;
-
- acb->pmu = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!acb->pmu) {
- printk(KERN_NOTICE "arcmsr%d: memory"
- " mapping region fail \n", acb->host->host_no);
- goto out_release_regions;
}
+ arcmsr_define_adapter_type(acb);
+
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
@@ -328,10 +423,10 @@ static int arcmsr_probe(struct pci_dev *pdev,
error = arcmsr_alloc_ccb_pool(acb);
if (error)
- goto out_iounmap;
+ goto out_release_regions;
error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+ IRQF_SHARED, "arcmsr", acb);
if (error)
goto out_free_ccb_pool;
@@ -349,14 +444,15 @@ static int arcmsr_probe(struct pci_dev *pdev,
goto out_free_sysfs;
scsi_scan_host(host);
+ #ifdef CONFIG_SCSI_ARCMSR_AER
pci_enable_pcie_error_reporting(pdev);
+ #endif
return 0;
out_free_sysfs:
out_free_irq:
free_irq(pdev->irq, acb);
out_free_ccb_pool:
arcmsr_free_ccb_pool(acb);
- out_iounmap:
iounmap(acb->pmu);
out_release_regions:
pci_release_regions(pdev);
@@ -368,17 +464,84 @@ static int arcmsr_probe(struct pci_dev *pdev,
return error;
}
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->outbound_intstatus);
+ return 0x00;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(reg->iop2drv_doorbell_reg)
+ & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+ , reg->iop2drv_doorbell_reg);
+ return 0x00;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
+ if (arcmsr_hba_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+ writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb))
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
}
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_abort_hba_allcmd(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_abort_hbb_allcmd(acb);
+ }
+ }
+}
+
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -400,28 +563,239 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
pcmd->scsi_done(pcmd);
}
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ int retry_count = 30;
+
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ do {
+ if (!arcmsr_hba_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ int retry_count = 30;
+
+ writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
+ do {
+ if (!arcmsr_hbb_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_flush_hba_cache(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_flush_hbb_cache(acb);
+ }
+ }
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+{
+
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+ pcmd->result = DID_OK << 16;
+ if (sensebuffer) {
+ int sense_data_length =
+ sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
+ ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
+ memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
+ memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+ sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+ sensebuffer->Valid = 1;
+ }
+}
+
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+{
+ u32 orig_mask = 0;
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A : {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ orig_mask = readl(&reg->outbound_intmask)|\
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+ writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
+ &reg->outbound_intmask);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B : {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \
+ (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
+ writel(0, reg->iop2drv_doorbell_mask_reg);
+ }
+ break;
+ }
+ return orig_mask;
+}
+
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *ccb, uint32_t flag_ccb)
+{
+
+ uint8_t id, lun;
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch (ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id = %d lun = %d"
+ " isr get command error done, "
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+}
+
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+
+{
+ struct CommandControlBlock *ccb;
+
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = ccb->pcmd;
+ if (abortcmd) {
+ abortcmd->result |= DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
+ isr got aborted command \n", acb->host->host_no, ccb);
+ }
+ }
+ printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
+ done acb = '0x%p'"
+ "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
+ " ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , acb
+ , ccb
+ , ccb->acb
+ , ccb->startdone
+ , atomic_read(&acb->ccboutstandingcount));
+ }
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+}
+
+static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
+{
+ int i = 0;
+ uint32_t flag_ccb;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = \
+ (struct MessageUnit_A *)acb->pmu;
+ uint32_t outbound_intstatus;
+ outbound_intstatus = readl(&reg->outbound_intstatus) & \
+ acb->outbound_int_enable;
+ /*clear and abort all outbound posted Q*/
+ writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+ while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) \
+ && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ /*clear all outbound posted Q*/
+ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
+ if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
+ writel(0, &reg->done_qbuffer[i]);
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+ writel(0, &reg->post_qbuffer[i]);
+ }
+ reg->doneq_index = 0;
+ reg->postq_index = 0;
+ }
+ break;
+ }
+}
static void arcmsr_remove(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
- writel(readl(&reg->outbound_intmask) |
- ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
+ arcmsr_disable_outbound_ints(acb);
acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
acb->acb_flags &= ~ACB_F_IOP_INITED;
- for (poll_count = 0; poll_count < 256; poll_count++) {
+ for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
if (!atomic_read(&acb->ccboutstandingcount))
break;
- arcmsr_interrupt(acb);
+ arcmsr_interrupt(acb);/* FIXME: need spinlock */
msleep(25);
}
@@ -429,8 +803,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
int i;
arcmsr_abort_allcmd(acb);
- for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
- readl(&reg->outbound_queueport);
+ arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
struct CommandControlBlock *ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
@@ -477,75 +850,32 @@ static void arcmsr_module_exit(void)
module_init(arcmsr_module_init);
module_exit(arcmsr_module_exit);
-static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
- u32 orig_mask = readl(&reg->outbound_intmask);
-
- writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
- return orig_mask;
-}
-
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
- u32 orig_mask)
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
+ u32 intmask_org)
{
- struct MessageUnit __iomem *reg = acb->pmu;
u32 mask;
- mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
- ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
- writel(mask, &reg->outbound_intmask);
-}
+ switch (acb->adapter_type) {
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
-
- writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE
- "arcmsr%d: wait 'flush adapter cache' timeout \n"
- , acb->host->host_no);
-}
-
-static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
-{
- struct scsi_cmnd *pcmd = ccb->pcmd;
- struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+ case ACB_ADAPTER_TYPE_A : {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+ ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(mask, &reg->outbound_intmask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+ }
+ break;
- pcmd->result = DID_OK << 16;
- if (sensebuffer) {
- int sense_data_length =
- sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
- ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
- memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
- memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
- sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
- sensebuffer->Valid = 1;
+ case ACB_ADAPTER_TYPE_B : {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \
+ ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE);
+ writel(mask, reg->iop2drv_doorbell_mask_reg);
+ acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
+ }
}
}
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(&reg->outbound_intstatus)
- & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
- writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
- , &reg->outbound_intstatus);
- return 0x00;
- }
- msleep_interruptible(10);
- }/*max 1 seconds*/
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
-}
-
static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
{
@@ -556,7 +886,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
int nseg;
ccb->pcmd = pcmd;
- memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
+ memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
@@ -609,52 +939,85 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
-
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
- if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu;
+
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
&reg->inbound_queueport);
- else
- writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
-}
+ else {
+ writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+ }
+ }
+ break;
-void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
- struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
- uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
- int32_t allxfer_len = 0;
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ uint32_t ending_index, index = reg->postq_index;
- if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
- acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
- while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
- && (allxfer_len < 124)) {
- writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
- acb->wqbuf_firstindex++;
- acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- allxfer_len++;
+ ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
+ writel(0, &reg->post_qbuffer[ending_index]);
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+ &reg->post_qbuffer[index]);
+ }
+ else {
+ writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
}
- writel(allxfer_len, &pwbuffer->data_len);
- writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
- , &reg->inbound_doorbell);
+ index++;
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
+ reg->postq_index = index;
+ writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+ }
+ break;
}
}
-static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
-
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
+
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
+ }
+}
+
+static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+ , acb->host->host_no);
+ }
+}
+
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_stop_hba_bgrb(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_stop_hbb_bgrb(acb);
+ }
+ break;
+ }
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
@@ -665,151 +1028,260 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
acb->dma_coherent_handle);
}
-static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ }
+ break;
- outbound_intstatus = readl(&reg->outbound_intstatus)
- & acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
- outbound_doorbell = readl(&reg->outbound_doorbell);
- writel(outbound_doorbell, &reg->outbound_doorbell);
- if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
- struct QBUFFER __iomem * prbuffer =
- (struct QBUFFER __iomem *) &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
- int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
- rqbuf_lastindex = acb->rqbuf_lastindex;
- rqbuf_firstindex = acb->rqbuf_firstindex;
- iop_len = readl(&prbuffer->data_len);
- my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
- &(ARCMSR_MAX_QBUFFER - 1);
- if (my_empty_len >= iop_len) {
- while (iop_len > 0) {
- acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
- acb->rqbuf_lastindex++;
- acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- iop_len--;
- }
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- } else
- acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
- }
- if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
- acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
- if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
- struct QBUFFER __iomem * pwbuffer =
- (struct QBUFFER __iomem *) &reg->message_wbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
- int32_t allxfer_len = 0;
-
- acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
- while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
- && (allxfer_len < 124)) {
- writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
- acb->wqbuf_firstindex++;
- acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- allxfer_len++;
- }
- writel(allxfer_len, &pwbuffer->data_len);
- writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
- &reg->inbound_doorbell);
- }
- if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
- acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
}
+ break;
}
- if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
- int id, lun;
+}
+
+static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
/*
- ****************************************************************
- ** areca cdb command done
- ****************************************************************
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
*/
- while (1) {
- if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
- break;/*chip FIFO no ccb for completion already*/
- /* check if command done with no error*/
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
- (flag_ccb << 5));
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
- if (abortcmd) {
- abortcmd->result |= DID_ABORT >> 16;
- arcmsr_ccb_complete(ccb, 1);
- printk(KERN_NOTICE
- "arcmsr%d: ccb ='0x%p' isr got aborted command \n"
- , acb->host->host_no, ccb);
- }
- continue;
- }
- printk(KERN_NOTICE
- "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'"
- "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
- " ccboutstandingcount = %d \n"
- , acb->host->host_no
- , acb
- , ccb
- , ccb->acb
- , ccb->startdone
- , atomic_read(&acb->ccboutstandingcount));
- continue;
- }
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- } else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_ABORTED:
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get command error done, "
- "but got unknown DeviceStatus = 0x%x \n"
- , acb->host->host_no
- , id
- , lun
- , ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- }/*drain reply FIFO*/
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+ }
+ break;
+ }
+}
+
+struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
+{
+ static struct QBUFFER *qbuffer;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ qbuffer = (struct QBUFFER __iomem *) &reg->message_rbuffer;
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ qbuffer = (struct QBUFFER __iomem *) reg->ioctl_rbuffer_reg;
+ }
+ break;
+ }
+ return qbuffer;
+}
+
+static struct QBUFFER *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
+{
+ static struct QBUFFER *pqbuffer;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ pqbuffer = (struct QBUFFER *) &reg->message_wbuffer;
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+ }
+ break;
+ }
+ return pqbuffer;
+}
+
+static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
+{
+ struct QBUFFER *prbuffer;
+ struct QBUFFER *pQbuffer;
+ uint8_t *iop_data;
+ int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+ rqbuf_lastindex = acb->rqbuf_lastindex;
+ rqbuf_firstindex = acb->rqbuf_firstindex;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = (uint8_t *)prbuffer->data;
+ iop_len = prbuffer->data_len;
+ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
+
+ if (my_empty_len >= iop_len)
+ {
+ while (iop_len > 0) {
+ pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
+ memcpy(pQbuffer, iop_data,1);
+ rqbuf_lastindex++;
+ rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ acb->rqbuf_lastindex = rqbuf_lastindex;
+ arcmsr_iop_message_read(acb);
+ }
+
+ else {
+ acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+ }
+}
+
+static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
+{
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
+ if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+ uint8_t *pQbuffer;
+ struct QBUFFER *pwbuffer;
+ uint8_t *iop_data;
+ int32_t allxfer_len = 0;
+
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+ iop_data = (uint8_t __iomem *)pwbuffer->data;
+
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
+ (allxfer_len < 124)) {
+ pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
+ memcpy(iop_data, pQbuffer, 1);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ pwbuffer->data_len = allxfer_len;
+
+ arcmsr_iop_message_wrote(acb);
+ }
+
+ if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ }
+}
+
+static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+ arcmsr_iop2drv_data_wrote_handle(acb);
+ }
+
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+ arcmsr_iop2drv_data_read_handle(acb);
+ }
+}
+
+static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t flag_ccb;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+ while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+}
+
+static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t index;
+ uint32_t flag_ccb;
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+ index = reg->doneq_index;
+
+ while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
+ writel(0, &reg->done_qbuffer[index]);
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ index++;
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;
+ reg->doneq_index = index;
+ }
+}
+
+static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_intstatus;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+ outbound_intstatus = readl(&reg->outbound_intstatus) & \
+ acb->outbound_int_enable;
+ if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) {
+ return 1;
+ }
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
+ arcmsr_hba_doorbell_isr(acb);
+ }
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+ arcmsr_hba_postqueue_isr(acb);
+ }
+ return 0;
+}
+
+static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+ outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \
+ acb->outbound_int_enable;
+ if (!outbound_doorbell)
+ return 1;
+
+ writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+
+ if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
+ arcmsr_iop2drv_data_wrote_handle(acb);
+ }
+ if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
+ arcmsr_iop2drv_data_read_handle(acb);
+ }
+ if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
+ arcmsr_hbb_postqueue_isr(acb);
+ }
+
+ return 0;
+}
+
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ if (arcmsr_handle_hba_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ if (arcmsr_handle_hbb_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
+ break;
}
- if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
- return IRQ_NONE;
return IRQ_HANDLED;
}
@@ -818,16 +1290,47 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
if (acb) {
/* stop adapter background rebuild */
if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
+ uint32_t intmask_org;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
+ arcmsr_enable_outbound_ints(acb, intmask_org);
}
}
}
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
+void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
+{
+ int32_t wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer;
+ struct QBUFFER *pwbuffer;
+ uint8_t *iop_data;
+ int32_t allxfer_len = 0;
+
+ pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+ iop_data = (uint8_t __iomem *)pwbuffer->data;
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
+ pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
+ memcpy(iop_data, pQbuffer, 1);
+ wqbuf_firstindex++;
+ wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ acb->wqbuf_firstindex = wqbuf_firstindex;
+ pwbuffer->data_len = allxfer_len;
+ arcmsr_iop_message_wrote(acb);
+ }
+}
+
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
+ struct scsi_cmnd *cmd)
{
- struct MessageUnit __iomem *reg = acb->pmu;
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
@@ -836,7 +1339,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
(uint32_t ) cmd->cmnd[6] << 16 |
(uint32_t ) cmd->cmnd[7] << 8 |
(uint32_t ) cmd->cmnd[8];
- /* 4 bytes: Areca io control code */
+ /* 4 bytes: Areca io control code */
sg = scsi_sglist(cmd);
buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
@@ -852,194 +1355,199 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
}
pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
switch(controlcode) {
+
case ARCMSR_MESSAGE_READ_RQBUFFER: {
- unsigned long *ver_addr;
- dma_addr_t buf_handle;
- uint8_t *pQbuffer, *ptmpQbuffer;
- int32_t allxfer_len = 0;
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ uint8_t *pQbuffer, *ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpQbuffer = (uint8_t *) ver_addr;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- ptmpQbuffer = (uint8_t *) ver_addr;
- while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
- && (allxfer_len < 1031)) {
- pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
- memcpy(ptmpQbuffer, pQbuffer, 1);
- acb->rqbuf_firstindex++;
- acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- ptmpQbuffer++;
- allxfer_len++;
- }
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
- &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
- int32_t iop_len;
-
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- iop_len = readl(&prbuffer->data_len);
- while (iop_len > 0) {
- acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
- acb->rqbuf_lastindex++;
- acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- iop_len--;
- }
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
+ struct QBUFFER *prbuffer;
+ uint8_t *iop_data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = (uint8_t *)prbuffer->data;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
}
- memcpy(pcmdmessagefld->messagedatabuffer,
- (uint8_t *)ver_addr, allxfer_len);
- pcmdmessagefld->cmdmessage.Length = allxfer_len;
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
- pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ arcmsr_iop_message_read(acb);
+ }
+ memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len);
+ pcmdmessagefld->cmdmessage.Length = allxfer_len;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
- case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
- unsigned long *ver_addr;
- dma_addr_t buf_handle;
- int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
- uint8_t *pQbuffer, *ptmpuserbuffer;
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- ptmpuserbuffer = (uint8_t *)ver_addr;
- user_len = pcmdmessagefld->cmdmessage.Length;
- memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
- wqbuf_lastindex = acb->wqbuf_lastindex;
- wqbuf_firstindex = acb->wqbuf_firstindex;
- if (wqbuf_lastindex != wqbuf_firstindex) {
+ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpuserbuffer = (uint8_t *)ver_addr;
+ user_len = pcmdmessagefld->cmdmessage.Length;
+ memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ arcmsr_post_ioctldata2iop(acb);
+ /* has error report sensedata */
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_ioctldata2iop(acb);
+ }
+ } else {
+ /* has error report sensedata */
struct SENSE_DATA *sensebuffer =
(struct SENSE_DATA *)cmd->sense_buffer;
- arcmsr_post_Qbuffer(acb);
- /* has error report sensedata */
sensebuffer->ErrorCode = 0x70;
sensebuffer->SenseKey = ILLEGAL_REQUEST;
sensebuffer->AdditionalSenseLength = 0x0A;
sensebuffer->AdditionalSenseCode = 0x20;
sensebuffer->Valid = 1;
retvalue = ARCMSR_MESSAGE_FAIL;
- } else {
- my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
- &(ARCMSR_MAX_QBUFFER - 1);
- if (my_empty_len >= user_len) {
- while (user_len > 0) {
- pQbuffer =
- &acb->wqbuffer[acb->wqbuf_lastindex];
- memcpy(pQbuffer, ptmpuserbuffer, 1);
- acb->wqbuf_lastindex++;
- acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- ptmpuserbuffer++;
- user_len--;
- }
- if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
- acb->acb_flags &=
- ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
- arcmsr_post_Qbuffer(acb);
- }
- } else {
- /* has error report sensedata */
- struct SENSE_DATA *sensebuffer =
- (struct SENSE_DATA *)cmd->sense_buffer;
- sensebuffer->ErrorCode = 0x70;
- sensebuffer->SenseKey = ILLEGAL_REQUEST;
- sensebuffer->AdditionalSenseLength = 0x0A;
- sensebuffer->AdditionalSenseCode = 0x20;
- sensebuffer->Valid = 1;
- retvalue = ARCMSR_MESSAGE_FAIL;
- }
+ }
}
pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
+
case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
- uint8_t *pQbuffer = acb->rqbuffer;
+ uint8_t *pQbuffer = acb->rqbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- }
- acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
- acb->rqbuf_firstindex = 0;
- acb->rqbuf_lastindex = 0;
- memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
- uint8_t *pQbuffer = acb->wqbuffer;
+ uint8_t *pQbuffer = acb->wqbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
- }
- acb->acb_flags |=
- (ACB_F_MESSAGE_WQBUFFER_CLEARED |
- ACB_F_MESSAGE_WQBUFFER_READED);
- acb->wqbuf_firstindex = 0;
- acb->wqbuf_lastindex = 0;
- memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
- uint8_t *pQbuffer;
+ uint8_t *pQbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
- }
- acb->acb_flags |=
- (ACB_F_MESSAGE_WQBUFFER_CLEARED
- | ACB_F_MESSAGE_RQBUFFER_CLEARED
- | ACB_F_MESSAGE_WQBUFFER_READED);
- acb->rqbuf_firstindex = 0;
- acb->rqbuf_lastindex = 0;
- acb->wqbuf_firstindex = 0;
- acb->wqbuf_lastindex = 0;
- pQbuffer = acb->rqbuffer;
- memset(pQbuffer, 0, sizeof (struct QBUFFER));
- pQbuffer = acb->wqbuffer;
- memset(pQbuffer, 0, sizeof (struct QBUFFER));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof(struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof(struct QBUFFER));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_RETURN_CODE_3F: {
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
}
break;
+
case ARCMSR_MESSAGE_SAY_HELLO: {
- int8_t * hello_string = "Hello! I am ARCMSR";
+ int8_t *hello_string = "Hello! I am ARCMSR";
- memcpy(pcmdmessagefld->messagedatabuffer, hello_string
- , (int16_t)strlen(hello_string));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+ , (int16_t)strlen(hello_string));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_SAY_GOODBYE:
arcmsr_iop_parking(acb);
break;
+
case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
arcmsr_flush_adapter_cache(acb);
break;
+
default:
retvalue = ARCMSR_MESSAGE_FAIL;
}
- message_out:
+ message_out:
sg = scsi_sglist(cmd);
kunmap_atomic(buffer - sg->offset, KM_IRQ0);
-
return retvalue;
}
@@ -1109,8 +1617,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
void (* done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
- struct AdapterControlBlock *acb =
- (struct AdapterControlBlock *) host->hostdata;
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
struct CommandControlBlock *ccb;
int target = cmd->device->id;
int lun = cmd->device->lun;
@@ -1153,26 +1660,27 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
+
arcmsr_build_ccb(acb, ccb, cmd);
arcmsr_post_ccb(acb, ccb);
return 0;
}
-static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
- char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
- char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+ char *iop_firm_model = (char *) (&reg->message_rwbuffer[15]);
+ char *iop_firm_version = (char *) (&reg->message_rwbuffer[17]);
int count;
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE
- "arcmsr%d: wait "
- "'get adapter firmware miscellaneous data' timeout \n"
- , acb->host->host_no);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+ miscellaneous data' timeout \n", acb->host->host_no);
+ }
+
count = 8;
while (count) {
*acb_firm_model = readb(iop_firm_model);
@@ -1180,6 +1688,7 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
iop_firm_model++;
count--;
}
+
count = 16;
while (count) {
*acb_firm_version = readb(iop_firm_version);
@@ -1187,28 +1696,93 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
iop_firm_version++;
count--;
}
- printk(KERN_INFO
- "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+
+ printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
, acb->host->host_no
, acb->firm_version);
+
acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
}
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ uint32_t *lrwbuffer = reg->msgcode_rwbuffer_reg;
+ char *acb_firm_model = acb->firm_model;
+ char *acb_firm_version = acb->firm_version;
+ char *iop_firm_model = (char *) (&lrwbuffer[15]);
+ /*firm_model,15,60-67*/
+ char *iop_firm_version = (char *) (&lrwbuffer[17]);
+ /*firm_version,17,68-83*/
+ int count;
+
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+ miscellaneous data' timeout \n", acb->host->host_no);
+ }
+
+ count = 8;
+ while (count)
+ {
+ *acb_firm_model = readb(iop_firm_model);
+ acb_firm_model++;
+ iop_firm_model++;
+ count--;
+ }
+
+ count = 16;
+ while (count)
+ {
+ *acb_firm_version = readb(iop_firm_version);
+ acb_firm_version++;
+ iop_firm_version++;
+ count--;
+ }
+
+ printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
+ acb->host->host_no,
+ acb->firm_version);
+
+ lrwbuffer++;
+ acb->firm_request_len = readl(lrwbuffer++);
+ /*firm_request_len,1,04-07*/
+ acb->firm_numbers_queue = readl(lrwbuffer++);
+ /*firm_numbers_queue,2,08-11*/
+ acb->firm_sdram_size = readl(lrwbuffer++);
+ /*firm_sdram_size,3,12-15*/
+ acb->firm_hd_channels = readl(lrwbuffer);
+ /*firm_ide_channels,4,16-19*/
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_get_hba_config(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_get_hbb_config(acb);
+ }
+ break;
+ }
+}
+
+static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
struct CommandControlBlock *ccb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
- int id, lun;
- polling_ccb_retry:
+ polling_hba_ccb_retry:
poll_count++;
- outbound_intstatus = readl(&reg->outbound_intstatus)
- & acb->outbound_int_enable;
+ outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
while (1) {
if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
@@ -1218,17 +1792,14 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
msleep(25);
if (poll_count > 100)
break;
- goto polling_ccb_retry;
+ goto polling_hba_ccb_retry;
}
}
- ccb = (struct CommandControlBlock *)
- (acb->vir2phy_offset + (flag_ccb << 5));
- if ((ccb->acb != acb) ||
- (ccb->startdone != ARCMSR_CCB_START)) {
- if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
- (ccb == poll_ccb)) {
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
" poll command abort successfully \n"
, acb->host->host_no
, ccb->pcmd->device->id
@@ -1239,176 +1810,280 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
poll_ccb_done = 1;
continue;
}
- printk(KERN_NOTICE
- "arcmsr%d: polling get an illegal ccb"
- " command done ccb ='0x%p'"
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
"ccboutstandingcount = %d \n"
, acb->host->host_no
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
}
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- } else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_ABORTED:
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ }
+}
+
+static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+ int index;
+
+ polling_hbb_ccb_retry:
+ poll_count++;
+ /* clear doorbell interrupt */
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ while (1) {
+ index = reg->doneq_index;
+ if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+ if (poll_ccb_done)
+ break;
+ else {
+ msleep(25);
+ if (poll_count > 100)
+ break;
+ goto polling_hbb_ccb_retry;
}
- break;
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
+ }
+ writel(0, &reg->done_qbuffer[index]);
+ index++;
+ /*if last index number set it to 0 */
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;
+ reg->doneq_index = index;
+ /* check ifcommand done with no error*/
+ ccb = (struct CommandControlBlock *)\
+ (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: \
+ scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
+ ,acb->host->host_no
+ ,ccb->pcmd->device->id
+ ,ccb->pcmd->device->lun
+ ,ccb);
+ ccb->pcmd->result = DID_ABORT << 16;
arcmsr_ccb_complete(ccb, 1);
+ continue;
}
- break;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " polling and getting command error done"
- "but got unknown DeviceStatus = 0x%x \n"
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
, acb->host->host_no
- , id
- , lun
- , ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
+ , ccb
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
}
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ } /*drain reply FIFO*/
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *poll_ccb)
+{
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
}
}
}
-static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb)
+
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
-(i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
-(flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone != \
-ARCMSR_CCB_START)){
- printk(KERN_NOTICE "arcmsr%d: polling get \
-an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
+ uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+ dma_addr_t dma_coherent_handle;
+ /*
+ ********************************************************************
+ ** here we need to tell iop 331 our freeccb.HighPart
+ ** if freeccb.HighPart is not zero
+ ********************************************************************
+ */
+ dma_coherent_handle = acb->dma_coherent_handle;
+ cdb_phyaddr = (uint32_t)(dma_coherent_handle);
+ ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ /*
+ ***********************************************************************
+ ** if adapter type B, set window of "post command Q"
+ ***********************************************************************
+ */
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ if (ccb_phyaddr_hi32 != 0) {
+ struct MessageUnit_A __iomem *reg = \
+ (struct MessageUnit_A *)acb->pmu;
+ uint32_t intmask_org;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, \
+ &reg->message_rwbuffer[0]);
+ writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
+ &reg->inbound_msgaddr0);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
+ part physical address timeout\n",
+ acb->host->host_no);
+ return 1;
}
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ }
+ break;
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ case ACB_ADAPTER_TYPE_B: {
+ unsigned long post_queue_phyaddr;
+ uint32_t *rwbuffer;
- case ARCMSR_DEV_ABORTED:
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ uint32_t intmask_org;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ reg->postq_index = 0;
+ reg->doneq_index = 0;
+ writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
+ acb->host->host_no);
+ return 1;
+ }
+ post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
+ sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
+ rwbuffer = reg->msgcode_rwbuffer_reg;
+ /* driver "set config" signature */
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
+ /* normal should be zero */
+ writel(ccb_phyaddr_hi32, rwbuffer++);
+ /* postQ size (256 + 8)*4 */
+ writel(post_queue_phyaddr, rwbuffer++);
+ /* doneQ size (256 + 8)*4 */
+ writel(post_queue_phyaddr + 1056, rwbuffer++);
+ /* ccb maxQ size must be --> [(256 + 8)*4]*/
+ writel(1056, rwbuffer);
+
+ writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
+ timeout \n",acb->host->host_no);
+ return 1;
+ }
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
+ ,acb->host->host_no);
+ return 1;
+ }
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ break;
+ }
+ return 0;
+}
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
+{
+ uint32_t firmware_state = 0;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d \
- lun = %d""polling and \
- getting command error \
- done""but got unknown \
- DeviceStatus = 0x%x \n",
- acb->host->host_no, id,
- lun, ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
- }
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ do {
+ firmware_state = readl(reg->iop2drv_doorbell_reg);
+ } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
+ }
+ break;
}
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) & \
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
+}
+
+static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", acb->host->host_no);
}
- return;
}
+static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n",acb->host->host_no);
+ }
+}
-static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
- uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:
+ arcmsr_start_hba_bgrb(acb);
+ break;
+ case ACB_ADAPTER_TYPE_B:
+ arcmsr_start_hbb_bgrb(acb);
+ break;
+ }
+}
- do {
- firmware_state = readl(&reg->outbound_msgaddr1);
- } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
- intmask_org = readl(&reg->outbound_intmask)
- | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
- arcmsr_get_firmware_spec(acb);
+static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ /*clear doorbell interrupt */
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ }
+ break;
- acb->acb_flags |= ACB_F_MSG_START_BGRB;
- writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb)) {
- printk(KERN_NOTICE "arcmsr%d: "
- "wait 'start adapter background rebulid' timeout\n",
- acb->host->host_no);
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ /* let IOP know data has been read */
+ }
+ break;
}
+}
- outbound_doorbell = readl(&reg->outbound_doorbell);
- writel(outbound_doorbell, &reg->outbound_doorbell);
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
- mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
- | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
- writel(intmask_org & mask, &reg->outbound_intmask);
- acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+{
+ uint32_t intmask_org;
+
+ arcmsr_wait_firmware_ready(acb);
+ arcmsr_iop_confirm(acb);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ arcmsr_get_firmware_spec(acb);
+ /*start background rebuild*/
+ arcmsr_start_adapter_bgrb(acb);
+ /* empty doorbell Qbuffer if door bell ringed */
+ arcmsr_clear_doorbell_queue_buffer(acb);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
acb->acb_flags |= ACB_F_IOP_INITED;
}
@@ -1421,22 +2096,24 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
if (atomic_read(&acb->ccboutstandingcount) != 0) {
/* talk to iop 331 outstanding command aborted */
arcmsr_abort_allcmd(acb);
+
/* wait for 3 sec for all command aborted*/
- msleep_interruptible(3000);
+ ssleep(3);
+
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
/* clear all outbound posted Q */
- arcmsr_done4_abort_postqueue(acb);
+ arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
+ arcmsr_ccb_complete(ccb, 1);
}
}
/* enable all outbound interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
}
-
}
static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
@@ -1450,7 +2127,7 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
for (i = 0; i < 400; i++) {
if (!atomic_read(&acb->ccboutstandingcount))
break;
- arcmsr_interrupt(acb);
+ arcmsr_interrupt(acb);/* FIXME: need spinlock */
msleep(25);
}
arcmsr_iop_reset(acb);
@@ -1468,7 +2145,7 @@ static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
/*
** Wait for 3 sec for all command done.
*/
- msleep_interruptible(3000);
+ ssleep(3);
intmask = arcmsr_disable_outbound_ints(acb);
arcmsr_polling_ccbdone(acb, ccb);
@@ -1515,6 +2192,8 @@ static const char *arcmsr_info(struct Scsi_Host *host)
switch (acb->pdev->device) {
case PCI_DEVICE_ID_ARECA_1110:
+ case PCI_DEVICE_ID_ARECA_1200:
+ case PCI_DEVICE_ID_ARECA_1202:
case PCI_DEVICE_ID_ARECA_1210:
raid6 = 0;
/*FALLTHRU*/
@@ -1522,6 +2201,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1130:
case PCI_DEVICE_ID_ARECA_1160:
case PCI_DEVICE_ID_ARECA_1170:
+ case PCI_DEVICE_ID_ARECA_1201:
case PCI_DEVICE_ID_ARECA_1220:
case PCI_DEVICE_ID_ARECA_1230:
case PCI_DEVICE_ID_ARECA_1260:
@@ -1544,287 +2224,82 @@ static const char *arcmsr_info(struct Scsi_Host *host)
ARCMSR_DRIVER_VERSION);
return buf;
}
-
+#ifdef CONFIG_SCSI_ARCMSR_AER
static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
{
- struct Scsi_Host *host;
- struct AdapterControlBlock *acb;
- uint8_t bus, dev_fun;
- int error;
-
- error = pci_enable_device(pdev);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
- pci_set_master(pdev);
-
- host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \
-(struct AdapterControlBlock));
- if (!host)
- return PCI_ERS_RESULT_DISCONNECT;
- acb = (struct AdapterControlBlock *)host->hostdata;
- memset(acb, 0, sizeof (struct AdapterControlBlock));
-
- error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
- if (error) {
- error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (error) {
- printk(KERN_WARNING
- "scsi%d: No suitable DMA mask available\n",
- host->host_no);
- return PCI_ERS_RESULT_DISCONNECT;
- }
- }
- bus = pdev->bus->number;
- dev_fun = pdev->devfn;
- acb = (struct AdapterControlBlock *) host->hostdata;
- memset(acb, 0, sizeof(struct AdapterControlBlock));
- acb->pdev = pdev;
- acb->host = host;
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
- host->max_lun = ARCMSR_MAX_TARGETLUN;
- host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
- host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
- host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
- host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
- host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
- host->this_id = ARCMSR_SCSI_INITIATOR_ID;
- host->unique_id = (bus << 8) | dev_fun;
- host->irq = pdev->irq;
- error = pci_request_regions(pdev, "arcmsr");
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ uint32_t intmask_org;
+ int i, j;
- acb->pmu = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!acb->pmu) {
- printk(KERN_NOTICE "arcmsr%d: memory"
- " mapping region fail \n", acb->host->host_no);
+ if (pci_enable_device(pdev)) {
return PCI_ERS_RESULT_DISCONNECT;
}
+ pci_set_master(pdev);
+ intmask_org = arcmsr_disable_outbound_ints(acb);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
- INIT_LIST_HEAD(&acb->ccb_free_list);
-
- error = arcmsr_alloc_ccb_pool(acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
-
- error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
-
- arcmsr_iop_init(acb);
- if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B;
-
- pci_set_drvdata(pdev, host);
-
- error = scsi_add_host(host, &pdev->dev);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
- error = arcmsr_alloc_sysfs_attr(acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ arcmsr_wait_firmware_ready(acb);
+ arcmsr_iop_confirm(acb);
+ /* disable all outbound interrupt */
+ arcmsr_get_firmware_spec(acb);
+ /*start background rebuild*/
+ arcmsr_start_adapter_bgrb(acb);
+ /* empty doorbell Qbuffer if door bell ringed */
+ arcmsr_clear_doorbell_queue_buffer(acb);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ acb->acb_flags |= ACB_F_IOP_INITED;
- scsi_scan_host(host);
+ pci_enable_pcie_error_reporting(pdev);
return PCI_ERS_RESULT_RECOVERED;
}
static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata;
struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
- (i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset
- + (flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone !=
- ARCMSR_CCB_START)){
- printk(KERN_NOTICE "arcmsr%d: polling \
- get an illegal ccb"" command done ccb = '0x%p'"
- "ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
- }
-
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] ==
- ARECA_RAID_GONE)
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_ABORTED:
-
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ uint32_t intmask_org;
+ int i = 0;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi \
- id = %d lun = %d"
- " polling and \
- getting command \
- error done"
- "but got unknown \
- DeviceStatus = 0x%x \n"
- , acb->host->host_no,
- id, lun,
- ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
+ if (atomic_read(&acb->ccboutstandingcount) != 0) {
+ /* talk to iop 331 outstanding command aborted */
+ arcmsr_abort_allcmd(acb);
+ /* wait for 3 sec for all command aborted*/
+ ssleep(3);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ /* clear all outbound posted Q */
+ arcmsr_done4abort_postqueue(acb);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ arcmsr_ccb_complete(ccb, 1);
}
}
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) &
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
- }
- return;
+ /* enable all outbound interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ pci_disable_device(pdev);
}
-
static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
- (i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
- (flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone !=
- ARCMSR_CCB_START)){
- printk(KERN_NOTICE
- "arcmsr%d: polling get an illegal ccb"
- " command done ccb = '0x%p'"
- "ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
- }
-
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_ABORTED:
-
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = \
+ (struct AdapterControlBlock *)host->hostdata;
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- default:
- printk(KERN_NOTICE "arcmsr%d: \
- scsi id = %d lun = %d"
- " polling and \
- getting command error done"
- "but got unknown \
- DeviceStatus = 0x%x \n"
- , acb->host->host_no,
- id, lun, ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
- }
- }
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) &
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
- }
- return;
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
}
static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
@@ -1840,5 +2315,6 @@ static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
break;
default:
return PCI_ERS_RESULT_NEED_RESET;
- }
+ }
}
+#endif
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 03dbe60c264..52d0b87e9aa 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -2041,7 +2041,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
case PHASE_DATAIN:
@@ -2100,7 +2100,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2235,24 +2235,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) &&
(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
- /* this is initialized from initialize_SCp
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- */
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
index cac35408673..d858f3d4127 100644
--- a/drivers/scsi/bvme6000_scsi.c
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -36,19 +36,18 @@ static struct platform_device *bvme6000_scsi_device;
static __devinit int
bvme6000_probe(struct device *dev)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
if (!MACH_IS_BVME6000)
goto out;
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "bvme6000-scsi: "
"Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 2a458d66b6f..024553f9c24 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -1235,7 +1235,21 @@ scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
}
EXPORT_SYMBOL(scsi_print_sense_hdr);
+/*
+ * Print normalized SCSI sense header with device information and a prefix.
+ */
void
+scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc,
+ struct scsi_sense_hdr *sshdr)
+{
+ scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+ scsi_show_sense_hdr(sshdr);
+ scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+EXPORT_SYMBOL(scsi_cmd_print_sense_hdr);
+
+static void
scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
struct scsi_sense_hdr *sshdr)
{
@@ -1258,7 +1272,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
}
}
-void
+static void
scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
struct scsi_sense_hdr *sshdr)
{
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 7b8a3457b69..1591824cf4b 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -778,7 +778,7 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add(&srb->list, &dcb->srb_waiting_list);
}
@@ -787,7 +787,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_waiting_list);
}
@@ -795,7 +795,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_going_list);
}
@@ -805,7 +805,7 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
if (i == srb) {
@@ -821,7 +821,7 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
if (i == srb) {
@@ -836,7 +836,7 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
{
dprintkdbg(DBG_0,
"srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_waiting_list);
}
@@ -846,7 +846,7 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
{
dprintkdbg(DBG_0,
"srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_going_list);
}
@@ -982,7 +982,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
int nseg;
enum dma_data_direction dir = cmd->sc_data_direction;
dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
- cmd->pid, dcb->target_id, dcb->target_lun);
+ cmd->serial_number, dcb->target_id, dcb->target_lun);
srb->dcb = dcb;
srb->cmd = cmd;
@@ -1086,7 +1086,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
/* Assume BAD_TARGET; will be cleared later */
cmd->result = DID_BAD_TARGET << 16;
@@ -1139,7 +1139,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
/* process immediately */
send_srb(acb, srb);
}
- dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid);
+ dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number);
return 0;
complete:
@@ -1203,7 +1203,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
else
dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
"cmnd=0x%02x <%02i-%i>\n",
- srb, srb->cmd, srb->cmd->pid,
+ srb, srb->cmd, srb->cmd->serial_number,
srb->cmd->cmnd[0], srb->cmd->device->id,
srb->cmd->device->lun);
printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
@@ -1300,7 +1300,7 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
dprintkl(KERN_INFO,
"eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
if (timer_pending(&acb->waiting_timer))
del_timer(&acb->waiting_timer);
@@ -1367,7 +1367,7 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
if (!dcb) {
@@ -1494,7 +1494,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
u8 s_stat, scsicommand, i, identify_message;
u8 *ptr;
dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */
@@ -1504,7 +1504,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
#if 1
if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
- srb->cmd->pid, s_stat, s_stat2);
+ srb->cmd->serial_number, s_stat, s_stat2);
/*
* Try anyway?
*
@@ -1522,14 +1522,14 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
if (acb->active_dcb) {
dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
"command while another command (pid#%li) is active.",
- srb->cmd->pid,
+ srb->cmd->serial_number,
acb->active_dcb->active_srb ?
- acb->active_dcb->active_srb->cmd->pid : 0);
+ acb->active_dcb->active_srb->cmd->serial_number : 0);
return 1;
}
if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
return 1;
}
/* Allow starting of SCSI commands half a second before we allow the mid-level
@@ -1603,7 +1603,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
if (tag_number >= dcb->max_command) {
dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
"Out of tags target=<%02i-%i>)\n",
- srb->cmd->pid, srb->cmd->device->id,
+ srb->cmd->serial_number, srb->cmd->device->id,
srb->cmd->device->lun);
srb->state = SRB_READY;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
@@ -1622,7 +1622,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
/*polling:*/
/* Send CDB ..command block ......... */
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
srb->cmd->cmnd[0], srb->tag_number);
if (srb->flag & AUTO_REQSENSE) {
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
@@ -1647,7 +1647,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
* : Let's process it first!
*/
dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
srb->state = SRB_READY;
free_tag(dcb, srb);
srb->msg_count = 0;
@@ -1842,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number);
if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
*pscsi_status = PH_BUS_FREE; /*.. initial phase */
@@ -1856,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
{
u16 i;
u8 *ptr;
- dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "msgout_phase1");
if (!(srb->state & SRB_MSGOUT)) {
srb->state |= SRB_MSGOUT;
dprintkl(KERN_DEBUG,
"msgout_phase1: (pid#%li) Phase unexpected\n",
- srb->cmd->pid); /* So what ? */
+ srb->cmd->serial_number); /* So what ? */
}
if (!srb->msg_count) {
dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
@@ -1887,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}
@@ -1898,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
struct DeviceCtlBlk *dcb;
u8 *ptr;
u16 i;
- dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "command_phase1");
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
@@ -2042,7 +2042,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
u32 d_left_counter = 0;
dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: We need to drain the buffers before we draw any conclusions!
@@ -2172,7 +2172,7 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
clear_fifo(acb, "data_out_phase1");
/* do prepare before transfer when data out phase */
data_io_transfer(acb, srb, XFERDATAOUT);
@@ -2184,7 +2184,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: DataIn is much more tricky than DataOut. When the device is finished
@@ -2205,7 +2205,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
if (scsi_status & PARITYERROR) {
dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
- "Parity Error\n", srb->cmd->pid);
+ "Parity Error\n", srb->cmd->serial_number);
srb->status |= PARITY_ERROR;
}
/*
@@ -2395,7 +2395,7 @@ static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
data_io_transfer(acb, srb, XFERDATAIN);
}
@@ -2407,7 +2407,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
u8 bval;
dprintkdbg(DBG_0,
"data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
((io_dir & DMACMD_DIR) ? 'r' : 'w'),
srb->total_xfer_length, srb->sg_index, srb->sg_count);
if (srb == acb->tmp_srb)
@@ -2580,7 +2580,7 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */
srb->state = SRB_COMPLETED;
@@ -2594,7 +2594,7 @@ static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
srb->state = SRB_STATUS;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
@@ -2636,7 +2636,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
struct ScsiReqBlk *srb = NULL;
struct ScsiReqBlk *i;
dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
- srb->cmd->pid, tag, srb);
+ srb->cmd->serial_number, tag, srb);
if (!(dcb->tag_mask & (1 << tag)))
dprintkl(KERN_DEBUG,
@@ -2655,7 +2655,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
goto mingx0;
dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun);
+ srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun);
if (dcb->flag & ABORT_DEV_) {
/*srb->state = SRB_ABORT_SENT; */
enable_msgout_abort(acb, srb);
@@ -2865,7 +2865,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
struct DeviceCtlBlk *dcb = acb->active_dcb;
- dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number);
srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
@@ -2933,7 +2933,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
*/
dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
"SAVE POINTER rem=%i Ignore\n",
- srb->cmd->pid, srb->total_xfer_length);
+ srb->cmd->serial_number, srb->total_xfer_length);
break;
case RESTORE_POINTERS:
@@ -2943,7 +2943,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
case ABORT:
dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
"<%02i-%i> ABORT msg\n",
- srb->cmd->pid, dcb->target_id,
+ srb->cmd->serial_number, dcb->target_id,
dcb->target_lun);
dcb->flag |= ABORT_DEV_;
enable_msgout_abort(acb, srb);
@@ -2975,7 +2975,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "msgin_phase1");
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
if (!(srb->state & SRB_MSGIN)) {
@@ -3041,7 +3041,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
}
srb = dcb->active_srb;
acb->active_dcb = NULL;
- dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number);
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
clear_fifo(acb, "disconnect");
@@ -3072,13 +3072,13 @@ static void disconnect(struct AdapterCtlBlk *acb)
srb->state = SRB_READY;
dprintkl(KERN_DEBUG,
"disconnect: (pid#%li) Unexpected\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
srb->target_status = SCSI_STAT_SEL_TIMEOUT;
goto disc1;
} else {
/* Normal selection timeout */
dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
- "<%02i-%i> SelTO\n", srb->cmd->pid,
+ "<%02i-%i> SelTO\n", srb->cmd->serial_number,
dcb->target_id, dcb->target_lun);
if (srb->retry_count++ > DC395x_MAX_RETRIES
|| acb->scan_devices) {
@@ -3090,7 +3090,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
srb_going_to_waiting_move(dcb, srb);
dprintkdbg(DBG_KG,
"disconnect: (pid#%li) Retry\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
waiting_set_timer(acb, HZ / 20);
}
} else if (srb->state & SRB_DISCONNECT) {
@@ -3144,7 +3144,7 @@ static void reselect(struct AdapterCtlBlk *acb)
if (!acb->scan_devices) {
dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
"Arb lost but Resel win rsel=%i stat=0x%04x\n",
- srb->cmd->pid, dcb->target_id,
+ srb->cmd->serial_number, dcb->target_id,
dcb->target_lun, rsel_tar_lun_id,
DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
arblostflag = 1;
@@ -3318,7 +3318,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
enum dma_data_direction dir = cmd->sc_data_direction;
int ckc_only = 1;
- dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
+ dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number,
srb->cmd->device->id, srb->cmd->device->lun);
dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
@@ -3499,7 +3499,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (srb->total_xfer_length)
dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
"cmnd=0x%02x Missed %i bytes\n",
- cmd->pid, cmd->device->id, cmd->device->lun,
+ cmd->serial_number, cmd->device->id, cmd->device->lun,
cmd->cmnd[0], srb->total_xfer_length);
}
@@ -3509,7 +3509,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
else {
dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
- cmd->pid, cmd->result);
+ cmd->serial_number, cmd->result);
srb_free_insert(acb, srb);
}
pci_unmap_srb(acb, srb);
@@ -3538,7 +3538,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
dir = p->sc_data_direction;
result = MK_RES(0, did_flag, 0, 0);
- printk("G:%li(%02i-%i) ", p->pid,
+ printk("G:%li(%02i-%i) ", p->serial_number,
p->device->id, p->device->lun);
srb_going_remove(dcb, srb);
free_tag(dcb, srb);
@@ -3568,7 +3568,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
result = MK_RES(0, did_flag, 0, 0);
- printk("W:%li<%02i-%i>", p->pid, p->device->id,
+ printk("W:%li<%02i-%i>", p->serial_number, p->device->id,
p->device->lun);
srb_waiting_remove(dcb, srb);
srb_free_insert(acb, srb);
@@ -3678,7 +3678,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
{
struct scsi_cmnd *cmd = srb->cmd;
dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
- cmd->pid, cmd->device->id, cmd->device->lun);
+ cmd->serial_number, cmd->device->id, cmd->device->lun);
srb->flag |= AUTO_REQSENSE;
srb->adapter_status = 0;
@@ -3709,7 +3709,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */
dprintkl(KERN_DEBUG,
"request_sense: (pid#%li) failed <%02i-%i>\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 100);
}
@@ -4717,13 +4717,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_waiting_list));
list_for_each_entry(srb, &dcb->srb_waiting_list, list)
- SPRINTF(" %li", srb->cmd->pid);
+ SPRINTF(" %li", srb->cmd->serial_number);
if (!list_empty(&dcb->srb_going_list))
SPRINTF("\nDCB (%02i-%i): Going : %i:",
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_going_list));
list_for_each_entry(srb, &dcb->srb_going_list, list)
- SPRINTF(" %li", srb->cmd->pid);
+ SPRINTF(" %li", srb->cmd->serial_number);
if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
SPRINTF("\n");
}
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 502732ac270..bea9d659af1 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -949,16 +949,14 @@ static int adpt_install_hba(struct pci_dev* pDev)
}
// Allocate and zero the data structure
- pHba = kmalloc(sizeof(adpt_hba), GFP_KERNEL);
- if( pHba == NULL) {
- if(msg_addr_virt != base_addr_virt){
+ pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL);
+ if (!pHba) {
+ if (msg_addr_virt != base_addr_virt)
iounmap(msg_addr_virt);
- }
iounmap(base_addr_virt);
pci_release_regions(pDev);
return -ENOMEM;
}
- memset(pHba, 0, sizeof(adpt_hba));
mutex_lock(&adpt_configuration_lock);
@@ -2622,14 +2620,13 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
- status = kmalloc(4,GFP_KERNEL|ADDR32);
- if (status==NULL) {
+ status = kzalloc(4, GFP_KERNEL|ADDR32);
+ if (!status) {
adpt_send_nop(pHba, m);
printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
pHba->name);
return -ENOMEM;
}
- memset(status, 0, 4);
writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2668,12 +2665,11 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
kfree(pHba->reply_pool);
- pHba->reply_pool = kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
- if(!pHba->reply_pool){
- printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name);
- return -1;
+ pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ if (!pHba->reply_pool) {
+ printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
+ return -ENOMEM;
}
- memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
ptr = pHba->reply_pool;
for(i = 0; i < pHba->reply_fifo_size; i++) {
@@ -2884,12 +2880,11 @@ static int adpt_i2o_build_sys_table(void)
kfree(sys_tbl);
- sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
- if(!sys_tbl) {
+ sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+ if (!sys_tbl) {
printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
}
- memset(sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = hba_count;
sys_tbl->version = I2OVERSION;
@@ -3351,7 +3346,7 @@ static int __init adpt_init(void)
return count > 0 ? 0 : -ENODEV;
}
-static void __exit adpt_exit(void)
+static void adpt_exit(void)
{
while (hba_chain)
adpt_release(hba_chain);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 9d52e45c7d3..2596165096d 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -137,11 +137,9 @@ static struct override {
#ifdef OVERRIDE
[] __initdata = OVERRIDE;
#else
-[4] __initdata = { {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}};
+[4] __initdata = {
+ { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }
+};
#endif
#define NO_OVERRIDES ARRAY_SIZE(overrides)
@@ -176,7 +174,7 @@ static const struct signature {
* Inputs : str - unused, ints - array of integer parameters with ints[0]
* equal to the number of ints.
*
-*/
+ */
static void __init dtc_setup(char *str, int *ints)
{
@@ -233,7 +231,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
} else
for (; !addr && (current_base < NO_BASES); ++current_base) {
#if (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : probing address %08x\n", bases[current_base].address);
+ printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
#endif
if (bases[current_base].noauto)
continue;
@@ -244,7 +242,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
addr = bases[current_base].address;
#if (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : detected board.\n");
+ printk(KERN_DEBUG "scsi-dtc : detected board.\n");
#endif
goto found;
}
@@ -253,7 +251,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
}
#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : base = %08x\n", addr);
+ printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
#endif
if (!addr)
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index a83e9f150b9..ec2233114bc 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1758,7 +1758,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
if (SCpnt->host_scribble)
panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
- ha->board_name, SCpnt->pid, SCpnt);
+ ha->board_name, SCpnt->serial_number, SCpnt);
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
@@ -1792,7 +1792,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
if (do_trace)
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, mbox %d, pid %ld.\n", i, SCpnt->pid);
+ "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number);
cpp->reqsen = 1;
cpp->dispri = 1;
@@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
unmap_dma(i, ha);
SCpnt->host_scribble = NULL;
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+ "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
return 1;
}
@@ -1841,13 +1841,13 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
if (SCarg->host_scribble == NULL) {
scmd_printk(KERN_INFO, SCarg,
- "abort, pid %ld inactive.\n", SCarg->pid);
+ "abort, pid %ld inactive.\n", SCarg->serial_number);
return SUCCESS;
}
i = *(unsigned int *)SCarg->host_scribble;
scmd_printk(KERN_WARNING, SCarg,
- "abort, mbox %d, pid %ld.\n", i, SCarg->pid);
+ "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number);
if (i >= shost->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
@@ -1892,7 +1892,7 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
SCarg->host_scribble = NULL;
ha->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- ha->board_name, i, SCarg->pid);
+ ha->board_name, i, SCarg->serial_number);
SCarg->scsi_done(SCarg);
return SUCCESS;
}
@@ -1909,12 +1909,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
struct hostdata *ha = (struct hostdata *)shost->hostdata;
scmd_printk(KERN_INFO, SCarg,
- "reset, enter, pid %ld.\n", SCarg->pid);
+ "reset, enter, pid %ld.\n", SCarg->serial_number);
spin_lock_irq(shost->host_lock);
if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid);
+ printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number);
if (ha->in_reset) {
printk("%s: reset, exit, already in reset.\n", ha->board_name);
@@ -1954,13 +1954,13 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
ha->cp_stat[i] = ABORTING;
printk("%s: reset, mbox %d aborting, pid %ld.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else {
ha->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
if (SCpnt->host_scribble == NULL)
@@ -2015,7 +2015,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
printk
("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else if (ha->cp_stat[i] == ABORTING) {
@@ -2029,7 +2029,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
printk
("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else
@@ -2043,7 +2043,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
do_trace = 0;
if (arg_done)
- printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid);
+ printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number);
else
printk("%s: reset, exit.\n", ha->board_name);
@@ -2182,7 +2182,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
cpp = &ha->cp[k];
SCpnt = cpp->SCpnt;
ll[n] = SCpnt->request->nr_sectors;
- pl[n] = SCpnt->pid;
+ pl[n] = SCpnt->serial_number;
if (!n)
continue;
@@ -2230,7 +2230,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
"%s pid %ld mb %d fc %d nr %d sec %ld ns %ld"
" cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k, flushcount,
+ SCpnt->serial_number, k, flushcount,
n_ready, SCpnt->request->sector,
SCpnt->request->nr_sectors, cursec, YESNO(s),
YESNO(r), YESNO(rev), YESNO(input_only),
@@ -2277,7 +2277,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
"%s, pid %ld, mbox %d, adapter"
" busy, will abort.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k);
+ SCpnt->serial_number, k);
ha->cp_stat[k] = ABORTING;
continue;
}
@@ -2391,11 +2391,11 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name,
- i, SCpnt->pid, SCpnt);
+ i, SCpnt->serial_number, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
- ha->board_name, i, SCpnt->pid,
+ ha->board_name, i, SCpnt->serial_number,
*(unsigned int *)SCpnt->host_scribble);
sync_dma(i, ha);
@@ -2445,12 +2445,12 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
"target_status 0x%x, sense key 0x%x.\n",
ha->board_name,
SCpnt->device->channel, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->pid,
+ SCpnt->device->lun, SCpnt->serial_number,
spp->target_status, SCpnt->sense_buffer[2]);
ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
- if (ha->last_retried_pid == SCpnt->pid)
+ if (ha->last_retried_pid == SCpnt->serial_number)
ha->retries = 0;
break;
@@ -2485,7 +2485,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
#endif
ha->retries++;
- ha->last_retried_pid = SCpnt->pid;
+ ha->last_retried_pid = SCpnt->serial_number;
} else
status = DID_ERROR << 16;
@@ -2516,7 +2516,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
" pid %ld, reg 0x%x, count %d.\n",
i, spp->adapter_status, spp->target_status,
- SCpnt->pid, reg, ha->iocount);
+ SCpnt->serial_number, reg, ha->iocount);
unmap_dma(i, ha);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index f33ad01064a..96180bb47e4 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -107,59 +107,44 @@ static struct scsi_host_template driver_template;
static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
int length, int rw)
{
- static u8 buff[512];
- int size, len = 0;
- off_t begin = 0, pos = 0;
+ int len = 0;
+ off_t begin = 0, pos = 0;
- if (rw)
- return -ENOSYS;
- if (offset == 0)
- memset(buff, 0, sizeof(buff));
+ if (rw)
+ return -ENOSYS;
- size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+ len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
- len += size; pos = begin + len;
- size = sprintf(buffer + len, "queued commands: %10ld\n"
+ len += sprintf(buffer + len, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
- len += size; pos = begin + len;
-
- size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+ len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
shost->host_no, SD(shost)->name);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Firmware revision: v%s\n",
+ len += sprintf(buffer + len, "Firmware revision: v%s\n",
SD(shost)->revision);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "IO: PIO\n");
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Host Bus: %s\n",
+ len += sprintf(buffer + len, "IO: PIO\n");
+ len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
+ len += sprintf(buffer + len, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
(SD(shost)->bustype == 'E')?"EISA":"ISA ");
- len += size;
- pos = begin + len;
+ pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
- stop_output:
- DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len = length; /* Ending slop */
- DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+stop_output:
+ DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
- return (len);
+ return len;
}
static int eata_pio_release(struct Scsi_Host *sh)
@@ -390,7 +375,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"eata_pio_queue pid %ld, y %d\n",
- cmd->pid, y));
+ cmd->serial_number, y));
cmd->scsi_done = (void *) done;
@@ -435,10 +420,10 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cmd->result = DID_BUS_BUSY << 16;
scmd_printk(KERN_NOTICE, cmd,
"eata_pio_queue pid %ld, HBA busy, "
- "returning DID_BUS_BUSY, done.\n", cmd->pid);
+ "returning DID_BUS_BUSY, done.\n", cmd->serial_number);
done(cmd);
cp->status = FREE;
- return (0);
+ return 0;
}
/* FIXME: timeout */
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
@@ -450,9 +435,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"Queued base %#.4lx pid: %ld "
- "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
+ "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq));
- return (0);
+ return 0;
}
static int eata_pio_abort(struct scsi_cmnd *cmd)
@@ -461,7 +446,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_abort called pid: %ld\n",
- cmd->pid));
+ cmd->serial_number));
while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
@@ -497,7 +482,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_reset called pid:%ld\n",
- cmd->pid));
+ cmd->serial_number));
spin_lock_irq(host->host_lock);
@@ -516,7 +501,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
- printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+ printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number);
if (sp == NULL)
panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
@@ -589,23 +574,28 @@ static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned i
cp.cp_cdb[5] = 0;
if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
- return (NULL);
- while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+ return NULL;
+
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+ cpu_relax();
+
outsw(base + HA_RDATA, &cp, cplen);
outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
for (z = 0; z < cppadlen; z++)
outw(0, base + HA_RDATA);
- while (inb(base + HA_RSTATUS) & HA_SBUSY);
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
+ cpu_relax();
+
if (inb(base + HA_RSTATUS) & HA_SERROR)
- return (NULL);
+ return NULL;
else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
- return (NULL);
+ return NULL;
else {
insw(base + HA_RDATA, &buff, 127);
while (inb(base + HA_RSTATUS) & HA_SDRQ)
inw(base + HA_RDATA);
- return (buff);
+ return buff;
}
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 95cf7b6cd62..4ed3a529706 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2138,7 +2138,7 @@ irqreturn_t scsi_esp_intr(int irq, void *dev_id)
}
EXPORT_SYMBOL(scsi_esp_intr);
-static void __devinit esp_get_revision(struct esp *esp)
+static void esp_get_revision(struct esp *esp)
{
u8 val;
@@ -2187,7 +2187,7 @@ static void __devinit esp_get_revision(struct esp *esp)
}
}
-static void __devinit esp_init_swstate(struct esp *esp)
+static void esp_init_swstate(struct esp *esp)
{
int i;
@@ -2233,7 +2233,7 @@ static void esp_bootup_reset(struct esp *esp)
esp_read8(ESP_INTRPT);
}
-static void __devinit esp_set_clock_params(struct esp *esp)
+static void esp_set_clock_params(struct esp *esp)
{
int fmhz;
u8 ccf;
@@ -2306,7 +2306,7 @@ static const char *esp_chip_names[] = {
static struct scsi_transport_template *esp_transport_template;
-int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+int scsi_esp_register(struct esp *esp, struct device *dev)
{
static int instance;
int err;
@@ -2346,7 +2346,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
}
EXPORT_SYMBOL(scsi_esp_register);
-void __devexit scsi_esp_unregister(struct esp *esp)
+void scsi_esp_unregister(struct esp *esp)
{
scsi_remove_host(esp->host);
}
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 36169d597e9..5d282e6a6ae 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -387,7 +387,9 @@ static void __iomem * bios_mem;
static int bios_major;
static int bios_minor;
static int PCI_bus;
+#ifdef CONFIG_PCI
static struct pci_dev *PCI_dev;
+#endif
static int Quantum; /* Quantum board variant */
static int interrupt_level;
static volatile int in_command;
@@ -1764,6 +1766,7 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
+#ifdef CONFIG_PCI
static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
@@ -1771,7 +1774,7 @@ static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
{ }
};
MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
-
+#endif
#define driver_template fdomain_driver_template
#include "scsi_module.c"
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 880f70d24e6..607336f56d5 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -556,7 +556,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
#endif
-#if NCR53C400_PSEUDO_DMA
+#ifdef NCR53C400_PSEUDO_DMA
/**
* NCR5380_pread - pseudo DMA read
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 55e4d2dc2bb..3ac080ee6e2 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -27,280 +27,8 @@
* along with this kernel; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
- * Linux kernel 2.4.x, 2.6.x supported *
+ * Linux kernel 2.6.x supported *
* *
- * $Log: gdth.c,v $
- * Revision 1.74 2006/04/10 13:44:47 achim
- * Community changes for 2.6.x
- * Kernel 2.2.x no longer supported
- * scsi_request interface removed, thanks to Christoph Hellwig
- *
- * Revision 1.73 2004/03/31 13:33:03 achim
- * Special command 0xfd implemented to detect 64-bit DMA support
- *
- * Revision 1.72 2004/03/17 08:56:04 achim
- * 64-bit DMA only enabled if FW >= x.43
- *
- * Revision 1.71 2004/03/05 15:51:29 achim
- * Screen service: separate message buffer, bugfixes
- *
- * Revision 1.70 2004/02/27 12:19:07 achim
- * Bugfix: Reset bit in config (0xfe) call removed
- *
- * Revision 1.69 2004/02/20 09:50:24 achim
- * Compatibility changes for kernels < 2.4.20
- * Bugfix screen service command size
- * pci_set_dma_mask() error handling added
- *
- * Revision 1.68 2004/02/19 15:46:54 achim
- * 64-bit DMA bugfixes
- * Drive size bugfix for drives > 1TB
- *
- * Revision 1.67 2004/01/14 13:11:57 achim
- * Tool access over /proc no longer supported
- * Bugfixes IOCTLs
- *
- * Revision 1.66 2003/12/19 15:04:06 achim
- * Bugfixes support for drives > 2TB
- *
- * Revision 1.65 2003/12/15 11:21:56 achim
- * 64-bit DMA support added
- * Support for drives > 2 TB implemented
- * Kernels 2.2.x, 2.4.x, 2.6.x supported
- *
- * Revision 1.64 2003/09/17 08:30:26 achim
- * EISA/ISA controller scan disabled
- * Command line switch probe_eisa_isa added
- *
- * Revision 1.63 2003/07/12 14:01:00 Daniele Bellucci <bellucda@tiscali.it>
- * Minor cleanups in gdth_ioctl.
- *
- * Revision 1.62 2003/02/27 15:01:59 achim
- * Dynamic DMA mapping implemented
- * New (character device) IOCTL interface added
- * Other controller related changes made
- *
- * Revision 1.61 2002/11/08 13:09:52 boji
- * Added support for XSCALE based RAID Controllers
- * Fixed SCREENSERVICE initialization in SMP cases
- * Added checks for gdth_polling before GDTH_HA_LOCK
- *
- * Revision 1.60 2002/02/05 09:35:22 achim
- * MODULE_LICENSE only if kernel >= 2.4.11
- *
- * Revision 1.59 2002/01/30 09:46:33 achim
- * Small changes
- *
- * Revision 1.58 2002/01/29 15:30:02 achim
- * Set default value of shared_access to Y
- * New status S_CACHE_RESERV for clustering added
- *
- * Revision 1.57 2001/08/21 11:16:35 achim
- * Bugfix free_irq()
- *
- * Revision 1.56 2001/08/09 11:19:39 achim
- * Scsi_Host_Template changes
- *
- * Revision 1.55 2001/08/09 10:11:28 achim
- * Command HOST_UNFREEZE_IO before cache service init.
- *
- * Revision 1.54 2001/07/20 13:48:12 achim
- * Expand: gdth_analyse_hdrive() removed
- *
- * Revision 1.53 2001/07/17 09:52:49 achim
- * Small OEM related change
- *
- * Revision 1.52 2001/06/19 15:06:20 achim
- * New host command GDT_UNFREEZE_IO added
- *
- * Revision 1.51 2001/05/22 06:42:37 achim
- * PCI: Subdevice ID added
- *
- * Revision 1.50 2001/05/17 13:42:16 achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.50 2001/05/17 12:12:34 achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.49 2001/03/15 15:07:17 achim
- * New __setup interface for boot command line options added
- *
- * Revision 1.48 2001/02/06 12:36:28 achim
- * Bugfix Cluster protocol
- *
- * Revision 1.47 2001/01/10 14:42:06 achim
- * New switch shared_access added
- *
- * Revision 1.46 2001/01/09 08:11:35 achim
- * gdth_command() removed
- * meaning of Scsi_Pointer members changed
- *
- * Revision 1.45 2000/11/16 12:02:24 achim
- * Changes for kernel 2.4
- *
- * Revision 1.44 2000/10/11 08:44:10 achim
- * Clustering changes: New flag media_changed added
- *
- * Revision 1.43 2000/09/20 12:59:01 achim
- * DPMEM remap functions for all PCI controller types implemented
- * Small changes for ia64 platform
- *
- * Revision 1.42 2000/07/20 09:04:50 achim
- * Small changes for kernel 2.4
- *
- * Revision 1.41 2000/07/04 14:11:11 achim
- * gdth_analyse_hdrive() added to rescan drives after online expansion
- *
- * Revision 1.40 2000/06/27 11:24:16 achim
- * Changes Clustering, Screenservice
- *
- * Revision 1.39 2000/06/15 13:09:04 achim
- * Changes for gdth_do_cmd()
- *
- * Revision 1.38 2000/06/15 12:08:43 achim
- * Bugfix gdth_sync_event(), service SCREENSERVICE
- * Data direction for command 0xc2 changed to DOU
- *
- * Revision 1.37 2000/05/25 13:50:10 achim
- * New driver parameter virt_ctr added
- *
- * Revision 1.36 2000/05/04 08:50:46 achim
- * Event buffer now in gdth_ha_str
- *
- * Revision 1.35 2000/03/03 10:44:08 achim
- * New event_string only valid for the RP controller family
- *
- * Revision 1.34 2000/03/02 14:55:29 achim
- * New mechanism for async. event handling implemented
- *
- * Revision 1.33 2000/02/21 15:37:37 achim
- * Bugfix Alpha platform + DPMEM above 4GB
- *
- * Revision 1.32 2000/02/14 16:17:37 achim
- * Bugfix sense_buffer[] + raw devices
- *
- * Revision 1.31 2000/02/10 10:29:00 achim
- * Delete sense_buffer[0], if command OK
- *
- * Revision 1.30 1999/11/02 13:42:39 achim
- * ARRAY_DRV_LIST2 implemented
- * Now 255 log. and 100 host drives supported
- *
- * Revision 1.29 1999/10/05 13:28:47 achim
- * GDT_CLUST_RESET added
- *
- * Revision 1.28 1999/08/12 13:44:54 achim
- * MOUNTALL removed
- * Cluster drives -> removeable drives
- *
- * Revision 1.27 1999/06/22 07:22:38 achim
- * Small changes
- *
- * Revision 1.26 1999/06/10 16:09:12 achim
- * Cluster Host Drive support: Bugfixes
- *
- * Revision 1.25 1999/06/01 16:03:56 achim
- * gdth_init_pci(): Manipulate config. space to start RP controller
- *
- * Revision 1.24 1999/05/26 11:53:06 achim
- * Cluster Host Drive support added
- *
- * Revision 1.23 1999/03/26 09:12:31 achim
- * Default value for hdr_channel set to 0
- *
- * Revision 1.22 1999/03/22 16:27:16 achim
- * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA()
- *
- * Revision 1.21 1999/03/16 13:40:34 achim
- * Problems with reserved drives solved
- * gdth_eh_bus_reset() implemented
- *
- * Revision 1.20 1999/03/10 09:08:13 achim
- * Bugfix: Corrections in gdth_direction_tab[] made
- * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq()
- *
- * Revision 1.19 1999/03/05 14:38:16 achim
- * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong
- * -> gdth_eval_mapping() implemented, changes in gdth_bios_param()
- * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers
- * with BIOS disabled and memory test set to Intensive
- * Enhanced /proc support
- *
- * Revision 1.18 1999/02/24 09:54:33 achim
- * Command line parameter hdr_channel implemented
- * Bugfix for EISA controllers + Linux 2.2.x
- *
- * Revision 1.17 1998/12/17 15:58:11 achim
- * Command line parameters implemented
- * Changes for Alpha platforms
- * PCI controller scan changed
- * SMP support improved (spin_lock_irqsave(),...)
- * New async. events, new scan/reserve commands included
- *
- * Revision 1.16 1998/09/28 16:08:46 achim
- * GDT_PCIMPR: DPMEM remapping, if required
- * mdelay() added
- *
- * Revision 1.15 1998/06/03 14:54:06 achim
- * gdth_delay(), gdth_flush() implemented
- * Bugfix: gdth_release() changed
- *
- * Revision 1.14 1998/05/22 10:01:17 achim
- * mj: pcibios_strerror() removed
- * Improved SMP support (if version >= 2.1.95)
- * gdth_halt(): halt_called flag added (if version < 2.1)
- *
- * Revision 1.13 1998/04/16 09:14:57 achim
- * Reserve drives (for raw service) implemented
- * New error handling code enabled
- * Get controller name from board_info() IOCTL
- * Final round of PCI device driver patches by Martin Mares
- *
- * Revision 1.12 1998/03/03 09:32:37 achim
- * Fibre channel controller support added
- *
- * Revision 1.11 1998/01/27 16:19:14 achim
- * SA_SHIRQ added
- * add_timer()/del_timer() instead of GDTH_TIMER
- * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
- * New error handling included
- *
- * Revision 1.10 1997/10/31 12:29:57 achim
- * Read heads/sectors from host drive
- *
- * Revision 1.9 1997/09/04 10:07:25 achim
- * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ...
- * register_reboot_notifier() to get a notify on shutown used
- *
- * Revision 1.8 1997/04/02 12:14:30 achim
- * Version 1.00 (see gdth.h), tested with kernel 2.0.29
- *
- * Revision 1.7 1997/03/12 13:33:37 achim
- * gdth_reset() changed, new async. events
- *
- * Revision 1.6 1997/03/04 14:01:11 achim
- * Shutdown routine gdth_halt() implemented
- *
- * Revision 1.5 1997/02/21 09:08:36 achim
- * New controller included (RP, RP1, RP2 series)
- * IOCTL interface implemented
- *
- * Revision 1.4 1996/07/05 12:48:55 achim
- * Function gdth_bios_param() implemented
- * New constant GDTH_MAXC_P_L inserted
- * GDT_WRITE_THR, GDT_EXT_INFO implemented
- * Function gdth_reset() changed
- *
- * Revision 1.3 1996/05/10 09:04:41 achim
- * Small changes for Linux 1.2.13
- *
- * Revision 1.2 1996/05/09 12:45:27 achim
- * Loadable module support implemented
- * /proc support corrections made
- *
- * Revision 1.1 1996/04/11 07:35:57 achim
- * Initial revision
- *
************************************************************************/
/* All GDT Disk Array Controllers are fully supported by this driver.
@@ -328,8 +56,6 @@
* max_ids:x x - target ID count per channel (1..MAXID)
* rescan:Y rescan all channels/IDs
* rescan:N use all devices found until now
- * virt_ctr:Y map every channel to a virtual controller
- * virt_ctr:N use multi channel support
* hdr_channel:x x - number of virtual bus for host drives
* shared_access:Y disable driver reserve/release protocol to
* access a shared resource from several nodes,
@@ -341,7 +67,7 @@
* force_dma32:N use 64 bit DMA mode, if supported
*
* The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- * max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
+ * max_ids:127,rescan:N,hdr_channel:0,
* shared_access:Y,probe_eisa_isa:N,force_dma32:N".
* Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
*
@@ -352,22 +78,22 @@
* '1' in place of 'Y' and '0' in place of 'N'.
*
* Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0
+ * max_ids=127 rescan=0 hdr_channel=0 shared_access=0
* probe_eisa_isa=0 force_dma32=0"
* The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
*/
/* The meaning of the Scsi_Pointer members in this driver is as follows:
* ptr: Chaining
- * this_residual: Command priority
- * buffer: phys. DMA sense buffer
- * dma_handle: phys. DMA buffer (kernel >= 2.4.0)
- * buffers_residual: Timeout value
- * Status: Command status (gdth_do_cmd()), DMA mem. mappings
- * Message: Additional info (gdth_do_cmd()), DMA direction
- * have_data_in: Flag for gdth_wait_completion()
- * sent_command: Opcode special command
- * phase: Service/parameter/return code special command
+ * this_residual: gdth_bufflen
+ * buffer: gdth_sglist
+ * dma_handle: unused
+ * buffers_residual: gdth_sg_count
+ * Status: unused
+ * Message: unused
+ * have_data_in: unused
+ * sent_command: unused
+ * phase: unused
*/
@@ -392,12 +118,8 @@
#include <linux/proc_fs.h>
#include <linux/time.h>
#include <linux/timer.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)
#include <linux/dma-mapping.h>
-#else
-#define DMA_32BIT_MASK 0x00000000ffffffffULL
-#define DMA_64BIT_MASK 0xffffffffffffffffULL
-#endif
+#include <linux/list.h>
#ifdef GDTH_RTC
#include <linux/mc146818rtc.h>
@@ -409,29 +131,27 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/spinlock.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/blkdev.h>
-#else
-#include <linux/blk.h>
-#include "sd.h"
-#endif
+#include <linux/scatterlist.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
-#include "gdth_kcompat.h"
#include "gdth.h"
static void gdth_delay(int milliseconds);
static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
static irqreturn_t gdth_interrupt(int irq, void *dev_id);
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
-static int gdth_async_event(int hanum);
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+ int gdth_from_wait, int* pIndex);
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+ Scsi_Cmnd *scp);
+static int gdth_async_event(gdth_ha_str *ha);
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
-static void gdth_next(int hanum);
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp);
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority);
+static void gdth_next(gdth_ha_str *ha);
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b);
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
ushort idx, gdth_evt_data *evt);
static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
@@ -439,42 +159,34 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
gdth_evt_str *estr);
static void gdth_clear_events(void);
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
- char *buffer,ushort count);
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+ char *buffer, ushort count, int to_buffer);
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
-static int gdth_search_eisa(ushort eisa_adr);
-static int gdth_search_isa(ulong32 bios_adr);
-static int gdth_search_pci(gdth_pci_str *pcistr);
-static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
- ushort vendor, ushort dev);
-static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt);
-static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
-static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha);
-static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
-
-static void gdth_enable_int(int hanum);
-static int gdth_get_status(unchar *pIStatus,int irq);
-static int gdth_test_busy(int hanum);
-static int gdth_get_cmd_index(int hanum);
-static void gdth_release_event(int hanum);
-static int gdth_wait(int hanum,int index,ulong32 time);
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
- ulong64 p2,ulong64 p3);
-static int gdth_search_drives(int hanum);
-static int gdth_analyse_hdrive(int hanum, ushort hdrive);
-
-static const char *gdth_ctr_name(int hanum);
+static void gdth_enable_int(gdth_ha_str *ha);
+static unchar gdth_get_status(gdth_ha_str *ha, int irq);
+static int gdth_test_busy(gdth_ha_str *ha);
+static int gdth_get_cmd_index(gdth_ha_str *ha);
+static void gdth_release_event(gdth_ha_str *ha);
+static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time);
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+ ulong32 p1, ulong64 p2,ulong64 p3);
+static int gdth_search_drives(gdth_ha_str *ha);
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive);
+
+static const char *gdth_ctr_name(gdth_ha_str *ha);
static int gdth_open(struct inode *inode, struct file *filep);
static int gdth_close(struct inode *inode, struct file *filep);
static int gdth_ioctl(struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg);
-static void gdth_flush(int hanum);
+static void gdth_flush(gdth_ha_str *ha);
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
+ struct gdth_cmndinfo *cmndinfo);
static void gdth_scsi_done(struct scsi_cmnd *scp);
#ifdef DEBUG_GDTH
@@ -571,29 +283,17 @@ static struct timer_list gdth_timer;
#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b)
#define INDEX_OK(i,t) ((i)<ARRAY_SIZE(t))
-#define NUMDATA(a) ( (gdth_num_str *)((a)->hostdata))
-#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext)
-#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext)
-
#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b))
-#define gdth_readb(addr) readb(addr)
-#define gdth_readw(addr) readw(addr)
-#define gdth_readl(addr) readl(addr)
-#define gdth_writeb(b,addr) writeb((b),(addr))
-#define gdth_writew(b,addr) writew((b),(addr))
-#define gdth_writel(b,addr) writel((b),(addr))
-
+#ifdef CONFIG_ISA
static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */
+#endif
+#if defined(CONFIG_EISA) || defined(CONFIG_ISA)
static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */
+#endif
static unchar gdth_polling; /* polling if TRUE */
-static unchar gdth_from_wait = FALSE; /* gdth_wait() */
-static int wait_index,wait_hanum; /* gdth_wait() */
static int gdth_ctr_count = 0; /* controller count */
-static int gdth_ctr_vcount = 0; /* virt. ctr. count */
-static int gdth_ctr_released = 0; /* gdth_release() */
-static struct Scsi_Host *gdth_ctr_tab[MAXHA]; /* controller table */
-static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS]; /* virt. ctr. table */
+static LIST_HEAD(gdth_instances); /* controller list */
static unchar gdth_write_through = FALSE; /* write through */
static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */
static int elastidx;
@@ -645,8 +345,6 @@ static int hdr_channel = 0;
static int max_ids = MAXID;
/* rescan all IDs */
static int rescan = 0;
-/* map channels to virtual controllers */
-static int virt_ctr = 0;
/* shared access */
static int shared_access = 1;
/* enable support for EISA and ISA controllers */
@@ -655,7 +353,6 @@ static int probe_eisa_isa = 0;
static int force_dma32 = 0;
/* parameters for modprobe/insmod */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
module_param_array(irq, int, NULL, 0);
module_param(disable, int, 0);
module_param(reserve_mode, int, 0);
@@ -664,24 +361,9 @@ module_param(reverse_scan, int, 0);
module_param(hdr_channel, int, 0);
module_param(max_ids, int, 0);
module_param(rescan, int, 0);
-module_param(virt_ctr, int, 0);
module_param(shared_access, int, 0);
module_param(probe_eisa_isa, int, 0);
module_param(force_dma32, int, 0);
-#else
-MODULE_PARM(irq, "i");
-MODULE_PARM(disable, "i");
-MODULE_PARM(reserve_mode, "i");
-MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i");
-MODULE_PARM(reverse_scan, "i");
-MODULE_PARM(hdr_channel, "i");
-MODULE_PARM(max_ids, "i");
-MODULE_PARM(rescan, "i");
-MODULE_PARM(virt_ctr, "i");
-MODULE_PARM(shared_access, "i");
-MODULE_PARM(probe_eisa_isa, "i");
-MODULE_PARM(force_dma32, "i");
-#endif
MODULE_AUTHOR("Achim Leubner");
MODULE_LICENSE("GPL");
@@ -692,6 +374,47 @@ static const struct file_operations gdth_fops = {
.release = gdth_close,
};
+/*
+ * gdth scsi_command access wrappers.
+ * below 6 functions are used throughout the driver to access scsi_command's
+ * io parameters. The reason we do not use the regular accessors from
+ * scsi_cmnd.h is because of gdth_execute(). Since it is unrecommended for
+ * llds to directly set scsi_cmnd's IO members. This driver will use SCp
+ * members for IO parameters, and will copy scsi_cmnd's members to Scp
+ * members in queuecommand. For internal commands through gdth_execute()
+ * SCp's members will be set directly.
+ */
+static inline unsigned gdth_bufflen(struct scsi_cmnd *cmd)
+{
+ return (unsigned)cmd->SCp.this_residual;
+}
+
+static inline void gdth_set_bufflen(struct scsi_cmnd *cmd, unsigned bufflen)
+{
+ cmd->SCp.this_residual = bufflen;
+}
+
+static inline unsigned gdth_sg_count(struct scsi_cmnd *cmd)
+{
+ return (unsigned)cmd->SCp.buffers_residual;
+}
+
+static inline void gdth_set_sg_count(struct scsi_cmnd *cmd, unsigned sg_count)
+{
+ cmd->SCp.buffers_residual = sg_count;
+}
+
+static inline struct scatterlist *gdth_sglist(struct scsi_cmnd *cmd)
+{
+ return cmd->SCp.buffer;
+}
+
+static inline void gdth_set_sglist(struct scsi_cmnd *cmd,
+ struct scatterlist *sglist)
+{
+ cmd->SCp.buffer = sglist;
+}
+
#include "gdth_proc.h"
#include "gdth_proc.c"
@@ -701,6 +424,45 @@ static struct notifier_block gdth_notifier = {
};
static int notifier_disabled = 0;
+static gdth_ha_str *gdth_find_ha(int hanum)
+{
+ gdth_ha_str *ha;
+
+ list_for_each_entry(ha, &gdth_instances, list)
+ if (hanum == ha->hanum)
+ return ha;
+
+ return NULL;
+}
+
+static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
+{
+ struct gdth_cmndinfo *priv = NULL;
+ ulong flags;
+ int i;
+
+ spin_lock_irqsave(&ha->smp_lock, flags);
+
+ for (i=0; i<GDTH_MAXCMDS; ++i) {
+ if (ha->cmndinfo[i].index == 0) {
+ priv = &ha->cmndinfo[i];
+ priv->index = i+1;
+ memset(priv, 0, sizeof(*priv));
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+ return priv;
+}
+
+static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv)
+{
+ BUG_ON(!priv);
+ priv->index = 0;
+}
+
static void gdth_delay(int milliseconds)
{
if (milliseconds == 0) {
@@ -710,80 +472,62 @@ static void gdth_delay(int milliseconds)
}
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static void gdth_scsi_done(struct scsi_cmnd *scp)
{
- TRACE2(("gdth_scsi_done()\n"));
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ int internal_command = cmndinfo->internal_command;
+
+ TRACE2(("gdth_scsi_done()\n"));
- if (scp->request)
- complete((struct completion *)scp->request);
+ gdth_put_cmndinfo(cmndinfo);
+ scp->host_scribble = NULL;
+
+ if (internal_command)
+ complete((struct completion *)scp->request);
+ else
+ scp->scsi_done(scp);
}
int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
{
+ gdth_ha_str *ha = shost_priv(sdev->host);
Scsi_Cmnd *scp;
+ struct gdth_cmndinfo cmndinfo;
+ struct scatterlist one_sg;
DECLARE_COMPLETION_ONSTACK(wait);
int rval;
- scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+ scp = kzalloc(sizeof(*scp), GFP_KERNEL);
if (!scp)
return -ENOMEM;
- memset(scp, 0, sizeof(*scp));
+
scp->device = sdev;
+ memset(&cmndinfo, 0, sizeof(cmndinfo));
+
/* use request field to save the ptr. to completion struct. */
scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ;
- scp->request_buffer = gdtcmd;
+ sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd));
+ gdth_set_sglist(scp, &one_sg);
+ gdth_set_sg_count(scp, 1);
+ gdth_set_bufflen(scp, sizeof(*gdtcmd));
scp->cmd_len = 12;
memcpy(scp->cmnd, cmnd, 12);
- scp->SCp.this_residual = IOCTL_PRI; /* priority */
- scp->done = gdth_scsi_done; /* some fn. test this */
- gdth_queuecommand(scp, gdth_scsi_done);
- wait_for_completion(&wait);
-
- rval = scp->SCp.Status;
- if (info)
- *info = scp->SCp.Message;
- kfree(scp);
- return rval;
-}
-#else
-static void gdth_scsi_done(Scsi_Cmnd *scp)
-{
- TRACE2(("gdth_scsi_done()\n"));
-
- scp->request.rq_status = RQ_SCSI_DONE;
- if (scp->request.waiting)
- complete(scp->request.waiting);
-}
+ cmndinfo.priority = IOCTL_PRI;
+ cmndinfo.internal_command = 1;
-int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
- int timeout, u32 *info)
-{
- Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
- unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
- DECLARE_COMPLETION_ONSTACK(wait);
- int rval;
+ TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0]));
+ __gdth_queuecommand(ha, scp, &cmndinfo);
- if (!scp)
- return -ENOMEM;
- scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->SCp.this_residual = IOCTL_PRI; /* priority */
- scp->request.rq_status = RQ_SCSI_BUSY;
- scp->request.waiting = &wait;
- scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
wait_for_completion(&wait);
- rval = scp->SCp.Status;
+ rval = cmndinfo.status;
if (info)
- *info = scp->SCp.Message;
-
- scsi_release_command(scp);
+ *info = cmndinfo.info;
+ kfree(scp);
return rval;
}
-#endif
int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
@@ -815,7 +559,7 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs
}
/* controller search and initialization functions */
-
+#ifdef CONFIG_EISA
static int __init gdth_search_eisa(ushort eisa_adr)
{
ulong32 id;
@@ -832,8 +576,9 @@ static int __init gdth_search_eisa(ushort eisa_adr)
return 0;
}
+#endif /* CONFIG_EISA */
-
+#ifdef CONFIG_ISA
static int __init gdth_search_isa(ulong32 bios_adr)
{
void __iomem *addr;
@@ -841,14 +586,18 @@ static int __init gdth_search_isa(ulong32 bios_adr)
TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
- id = gdth_readl(addr);
+ id = readl(addr);
iounmap(addr);
if (id == GDT2_ID) /* GDT2000 */
return 1;
}
return 0;
}
+#endif /* CONFIG_ISA */
+#ifdef CONFIG_PCI
+static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
+ ushort vendor, ushort dev);
static int __init gdth_search_pci(gdth_pci_str *pcistr)
{
@@ -928,7 +677,6 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
}
}
-
static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
{
gdth_pci_str temp;
@@ -965,8 +713,9 @@ static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
}
} while (changed);
}
+#endif /* CONFIG_PCI */
-
+#ifdef CONFIG_EISA
static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
{
ulong32 retries,id;
@@ -1058,8 +807,9 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
ha->dma64_support = 0;
return 1;
}
+#endif /* CONFIG_EISA */
-
+#ifdef CONFIG_ISA
static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
{
register gdt2_dpram_str __iomem *dp2_ptr;
@@ -1075,22 +825,22 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
return 0;
}
dp2_ptr = ha->brd;
- gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
+ writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
/* reset interface area */
memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u));
- if (gdth_readl(&dp2_ptr->u) != 0) {
+ if (readl(&dp2_ptr->u) != 0) {
printk("GDT-ISA: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
}
/* disable board interrupts, read DRQ and IRQ */
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
- gdth_writeb(0x00, &dp2_ptr->io.irqen);
- gdth_writeb(0x00, &dp2_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
+ writeb(0xff, &dp2_ptr->io.irqdel);
+ writeb(0x00, &dp2_ptr->io.irqen);
+ writeb(0x00, &dp2_ptr->u.ic.S_Status);
+ writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
- irq_drq = gdth_readb(&dp2_ptr->io.rq);
+ irq_drq = readb(&dp2_ptr->io.rq);
for (i=0; i<3; ++i) {
if ((irq_drq & 1)==0)
break;
@@ -1098,7 +848,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
ha->drq = gdth_drq_tab[i];
- irq_drq = gdth_readb(&dp2_ptr->io.rq) >> 3;
+ irq_drq = readb(&dp2_ptr->io.rq) >> 3;
for (i=1; i<5; ++i) {
if ((irq_drq & 1)==0)
break;
@@ -1107,12 +857,12 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
ha->irq = gdth_irq_tab[i];
/* deinitialize services */
- gdth_writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp2_ptr->io.event);
+ writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp2_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-ISA: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1120,9 +870,9 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp2_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp2_ptr->u.ic.Status);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+ prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp2_ptr->u.ic.Status);
+ writeb(0xff, &dp2_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-ISA: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1136,15 +886,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
ha->brd_phys = bios_adr >> 4;
/* special request to controller BIOS */
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
- gdth_writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp2_ptr->io.event);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
+ writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp2_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-ISA: Initialization error\n");
iounmap(ha->brd);
@@ -1152,14 +902,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp2_ptr->u.ic.Status);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+ writeb(0, &dp2_ptr->u.ic.Status);
+ writeb(0xff, &dp2_ptr->io.irqdel);
ha->dma64_support = 0;
return 1;
}
+#endif /* CONFIG_ISA */
-
+#ifdef CONFIG_PCI
static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
{
register gdt6_dpram_str __iomem *dp6_ptr;
@@ -1190,8 +941,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
/* check and reset interface area */
dp6_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
- if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (readl(&dp6_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1202,7 +953,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_old() address 0x%x busy\n", i));
continue;
}
@@ -1215,8 +966,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
- if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (readl(&dp6_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1229,24 +980,24 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
}
memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u));
- if (gdth_readl(&dp6_ptr->u) != 0) {
+ if (readl(&dp6_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
}
/* disable board interrupts, deinit services */
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
- gdth_writeb(0x00, &dp6_ptr->io.irqen);
- gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
-
- gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp6_ptr->io.event);
+ writeb(0xff, &dp6_ptr->io.irqdel);
+ writeb(0x00, &dp6_ptr->io.irqen);
+ writeb(0x00, &dp6_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+ writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1254,9 +1005,9 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6_ptr->u.ic.S_Status);
+ writeb(0xff, &dp6_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1267,15 +1018,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp6_ptr->io.event);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1283,8 +1034,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ writeb(0, &dp6_ptr->u.ic.S_Status);
+ writeb(0xff, &dp6_ptr->io.irqdel);
ha->dma64_support = 0;
@@ -1300,8 +1051,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
/* check and reset interface area */
dp6c_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
- if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1312,7 +1063,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_plx() address 0x%x busy\n", i));
continue;
}
@@ -1325,8 +1076,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6c_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
- if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1339,7 +1090,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
}
memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u));
- if (gdth_readl(&dp6c_ptr->u) != 0) {
+ if (readl(&dp6c_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
@@ -1349,17 +1100,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
outb(0x00,PTR2USHORT(&ha->plx->control1));
outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
- gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
+ writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
- gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
+ writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1367,8 +1118,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6c_ptr->u.ic.Status);
+ prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6c_ptr->u.ic.Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1379,17 +1130,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6c_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1397,7 +1148,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
+ writeb(0, &dp6c_ptr->u.ic.S_Status);
ha->dma64_support = 0;
@@ -1425,12 +1176,12 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
/* Ensure that it is safe to access the non HW portions of DPMEM.
* Aditional check needed for Xscale based RAID controllers */
- while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
+ while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
gdth_delay(1);
/* check and reset interface area */
- gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
- if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6m_ptr->u);
+ if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1441,7 +1192,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
continue;
}
@@ -1454,8 +1205,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6m_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
- if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6m_ptr->u);
+ if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1470,18 +1221,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u));
/* disable board interrupts, deinit services */
- gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
+ writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
&dp6m_ptr->i960r.edoor_en_reg);
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0x00, &dp6m_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0x00, &dp6m_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
- gdth_writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1489,8 +1240,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6m_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1501,15 +1252,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6m_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1517,14 +1268,14 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
/* read FW version to detect 64-bit DMA support */
- gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1532,8 +1283,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */
ha->dma64_support = 0;
else
@@ -1542,20 +1293,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 1;
}
-
+#endif /* CONFIG_PCI */
/* controller protocol functions */
-static void __init gdth_enable_int(int hanum)
+static void __init gdth_enable_int(gdth_ha_str *ha)
{
- gdth_ha_str *ha;
ulong flags;
gdt2_dpram_str __iomem *dp2_ptr;
gdt6_dpram_str __iomem *dp6_ptr;
gdt6m_dpram_str __iomem *dp6m_ptr;
- TRACE(("gdth_enable_int() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_enable_int() hanum %d\n",ha->hanum));
spin_lock_irqsave(&ha->smp_lock, flags);
if (ha->type == GDT_EISA) {
@@ -1564,93 +1313,80 @@ static void __init gdth_enable_int(int hanum)
outb(0x01, ha->bmic + EINTENABREG);
} else if (ha->type == GDT_ISA) {
dp2_ptr = ha->brd;
- gdth_writeb(1, &dp2_ptr->io.irqdel);
- gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);
- gdth_writeb(1, &dp2_ptr->io.irqen);
+ writeb(1, &dp2_ptr->io.irqdel);
+ writeb(0, &dp2_ptr->u.ic.Cmd_Index);
+ writeb(1, &dp2_ptr->io.irqen);
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
- gdth_writeb(1, &dp6_ptr->io.irqdel);
- gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);
- gdth_writeb(1, &dp6_ptr->io.irqen);
+ writeb(1, &dp6_ptr->io.irqdel);
+ writeb(0, &dp6_ptr->u.ic.Cmd_Index);
+ writeb(1, &dp6_ptr->io.irqen);
} else if (ha->type == GDT_PCINEW) {
outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
outb(0x03, PTR2USHORT(&ha->plx->control1));
} else if (ha->type == GDT_PCIMPR) {
dp6m_ptr = ha->brd;
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
&dp6m_ptr->i960r.edoor_en_reg);
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-
-static int gdth_get_status(unchar *pIStatus,int irq)
+/* return IStatus if interrupt was from this card else 0 */
+static unchar gdth_get_status(gdth_ha_str *ha, int irq)
{
- register gdth_ha_str *ha;
- int i;
+ unchar IStatus = 0;
+
+ TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
- TRACE(("gdth_get_status() irq %d ctr_count %d\n",
- irq,gdth_ctr_count));
-
- *pIStatus = 0;
- for (i=0; i<gdth_ctr_count; ++i) {
- ha = HADATA(gdth_ctr_tab[i]);
if (ha->irq != (unchar)irq) /* check IRQ */
- continue;
+ return false;
if (ha->type == GDT_EISA)
- *pIStatus = inb((ushort)ha->bmic + EDOORREG);
+ IStatus = inb((ushort)ha->bmic + EDOORREG);
else if (ha->type == GDT_ISA)
- *pIStatus =
- gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+ IStatus =
+ readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
else if (ha->type == GDT_PCI)
- *pIStatus =
- gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+ IStatus =
+ readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
else if (ha->type == GDT_PCINEW)
- *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+ IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
else if (ha->type == GDT_PCIMPR)
- *pIStatus =
- gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
-
- if (*pIStatus)
- return i; /* board found */
- }
- return -1;
+ IStatus =
+ readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
+
+ return IStatus;
}
-
-
-static int gdth_test_busy(int hanum)
+
+static int gdth_test_busy(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register int gdtsema0 = 0;
- TRACE(("gdth_test_busy() hanum %d\n",hanum));
-
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_test_busy() hanum %d\n", ha->hanum));
+
if (ha->type == GDT_EISA)
gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
else if (ha->type == GDT_ISA)
- gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
else if (ha->type == GDT_PCI)
- gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
else if (ha->type == GDT_PCINEW)
gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
else if (ha->type == GDT_PCIMPR)
gdtsema0 =
- (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+ (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
return (gdtsema0 & 1);
}
-static int gdth_get_cmd_index(int hanum)
+static int gdth_get_cmd_index(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
int i;
- TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+ TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
for (i=0; i<GDTH_MAXCMDS; ++i) {
if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
@@ -1663,30 +1399,26 @@ static int gdth_get_cmd_index(int hanum)
}
-static void gdth_set_sema0(int hanum)
+static void gdth_set_sema0(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
-
- TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+ TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
if (ha->type == GDT_EISA) {
outb(1, ha->bmic + SEMA0REG);
} else if (ha->type == GDT_ISA) {
- gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
} else if (ha->type == GDT_PCI) {
- gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
} else if (ha->type == GDT_PCINEW) {
outb(1, PTR2USHORT(&ha->plx->sema0_reg));
} else if (ha->type == GDT_PCIMPR) {
- gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+ writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
}
}
-static void gdth_copy_command(int hanum)
+static void gdth_copy_command(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmd_ptr;
register gdt6m_dpram_str __iomem *dp6m_ptr;
register gdt6c_dpram_str __iomem *dp6c_ptr;
@@ -1694,9 +1426,8 @@ static void gdth_copy_command(int hanum)
gdt2_dpram_str __iomem *dp2_ptr;
ushort cp_count,dp_offset,cmd_no;
- TRACE(("gdth_copy_command() hanum %d\n",hanum));
+ TRACE(("gdth_copy_command() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
cp_count = ha->cmd_len;
dp_offset= ha->cmd_offs_dpmem;
cmd_no = ha->cmd_cnt;
@@ -1715,42 +1446,39 @@ static void gdth_copy_command(int hanum)
/* set offset and service, copy command to DPMEM */
if (ha->type == GDT_ISA) {
dp2_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp2_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCINEW) {
dp6c_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCIMPR) {
dp6m_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
}
}
-static void gdth_release_event(int hanum)
+static void gdth_release_event(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
-
- TRACE(("gdth_release_event() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_release_event() hanum %d\n", ha->hanum));
#ifdef GDTH_STATISTICS
{
@@ -1774,56 +1502,50 @@ static void gdth_release_event(int hanum)
outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
outb(ha->pccb->Service, ha->bmic + LDOORREG);
} else if (ha->type == GDT_ISA) {
- gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
+ writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
} else if (ha->type == GDT_PCI) {
- gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
+ writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
} else if (ha->type == GDT_PCINEW) {
outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
} else if (ha->type == GDT_PCIMPR) {
- gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
+ writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
}
}
-
-static int gdth_wait(int hanum,int index,ulong32 time)
+static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
{
- gdth_ha_str *ha;
int answer_found = FALSE;
+ int wait_index = 0;
- TRACE(("gdth_wait() hanum %d index %d time %d\n",hanum,index,time));
+ TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time));
- ha = HADATA(gdth_ctr_tab[hanum]);
if (index == 0)
return 1; /* no wait required */
- gdth_from_wait = TRUE;
do {
- gdth_interrupt((int)ha->irq,ha);
- if (wait_hanum==hanum && wait_index==index) {
+ __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
+ if (wait_index == index) {
answer_found = TRUE;
break;
}
gdth_delay(1);
} while (--time);
- gdth_from_wait = FALSE;
-
- while (gdth_test_busy(hanum))
+
+ while (gdth_test_busy(ha))
gdth_delay(0);
return (answer_found);
}
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
- ulong64 p2,ulong64 p3)
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+ ulong32 p1, ulong64 p2, ulong64 p3)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmd_ptr;
int retries,index;
TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
- ha = HADATA(gdth_ctr_tab[hanum]);
cmd_ptr = ha->pccb;
memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
@@ -1831,11 +1553,11 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
for (retries = INIT_RETRIES;;) {
cmd_ptr->Service = service;
cmd_ptr->RequestBuffer = INTERNAL_CMND;
- if (!(index=gdth_get_cmd_index(hanum))) {
+ if (!(index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
cmd_ptr->OpCode = opcode;
cmd_ptr->BoardNode = LOCALBOARD;
if (service == CACHESERVICE) {
@@ -1875,10 +1597,10 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
ha->cmd_len = sizeof(gdth_cmd_str);
ha->cmd_offs_dpmem = 0;
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
gdth_delay(20);
- if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+ if (!gdth_wait(ha, index, INIT_TIMEOUT)) {
printk("GDT: Initialization error (timeout service %d)\n",service);
return 0;
}
@@ -1893,9 +1615,8 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
/* search for devices */
-static int __init gdth_search_drives(int hanum)
+static int __init gdth_search_drives(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
ushort cdev_cnt, i;
int ok;
ulong32 bus_no, drv_cnt, drv_no, j;
@@ -1915,22 +1636,21 @@ static int __init gdth_search_drives(int hanum)
ulong flags;
#endif
- TRACE(("gdth_search_drives() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_search_drives() hanum %d\n", ha->hanum));
ok = 0;
/* initialize controller services, at first: screen service */
ha->screen_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+ ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0);
if (ok)
ha->screen_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+ ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error screen service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
@@ -1954,25 +1674,26 @@ static int __init gdth_search_drives(int hanum)
TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
/* 3. send to controller firmware */
- gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+ gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
#endif
/* unfreeze all IOs */
- gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
+ gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0);
/* initialize cache service */
ha->cache_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+ ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS,
+ 0, 0);
if (ok)
ha->cache_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+ ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error cache service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
@@ -2001,9 +1722,9 @@ static int __init gdth_search_drives(int hanum)
pmod->cmd_buff_size = 0;
pmod->reserved1 = 0;
pmod->reserved2 = 0;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES,
INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
- printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+ printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum);
}
}
#endif
@@ -2015,7 +1736,7 @@ static int __init gdth_search_drives(int hanum)
iocr->hdr.first_chan = 0;
iocr->hdr.last_chan = MAXBUS-1;
iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC,
INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) {
TRACE2(("IOCHAN_RAW_DESC supported!\n"));
ha->bus_cnt = iocr->hdr.chan_count;
@@ -2030,13 +1751,13 @@ static int __init gdth_search_drives(int hanum)
chn = (gdth_getch_str *)ha->pscratch;
for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
chn->channel_no = bus_no;
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_CHAN_CNT | L_CTRL_PATTERN,
IO_CHANNEL | INVALID_CHANNEL,
sizeof(gdth_getch_str))) {
if (bus_no == 0) {
printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
break;
@@ -2051,10 +1772,10 @@ static int __init gdth_search_drives(int hanum)
TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt));
/* read cache configuration */
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO,
INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
printk("GDT-HA %d: Initialization error cache service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
@@ -2064,11 +1785,11 @@ static int __init gdth_search_drives(int hanum)
/* read board info and features */
ha->more_proc = FALSE;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO,
INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
sizeof(gdth_binfo_str));
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES,
INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
ha->bfeat = *(gdth_bfeat_str *)ha->pscratch;
@@ -2076,7 +1797,7 @@ static int __init gdth_search_drives(int hanum)
}
} else {
TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n"));
- strcpy(ha->binfo.type_string, gdth_ctr_name(hanum));
+ strcpy(ha->binfo.type_string, gdth_ctr_name(ha));
}
TRACE2(("Controller name: %s\n",ha->binfo.type_string));
@@ -2089,7 +1810,7 @@ static int __init gdth_search_drives(int hanum)
ioc->hdr.first_chan = 0;
ioc->hdr.last_chan = MAXBUS-1;
ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC,
INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
ha->raw[bus_no].address = ioc->list[bus_no].address;
@@ -2104,7 +1825,7 @@ static int __init gdth_search_drives(int hanum)
for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
chn = (gdth_getch_str *)ha->pscratch;
chn->channel_no = ha->raw[bus_no].local_no;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_CHAN_CNT | L_CTRL_PATTERN,
ha->raw[bus_no].address | INVALID_CHANNEL,
sizeof(gdth_getch_str))) {
@@ -2116,7 +1837,7 @@ static int __init gdth_search_drives(int hanum)
drl = (gdth_drlist_str *)ha->pscratch;
drl->sc_no = ha->raw[bus_no].local_no;
drl->sc_cnt = ha->raw[bus_no].pdev_cnt;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_DR_LIST | L_CTRL_PATTERN,
ha->raw[bus_no].address | INVALID_CHANNEL,
sizeof(gdth_drlist_str))) {
@@ -2129,10 +1850,10 @@ static int __init gdth_search_drives(int hanum)
}
/* logical drives */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT,
INVALID_CHANNEL,sizeof(ulong32))) {
drv_cnt = *(ulong32 *)ha->pscratch;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST,
INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
for (j = 0; j < drv_cnt; ++j) {
drv_no = ((ulong32 *)ha->pscratch)[j];
@@ -2146,7 +1867,7 @@ static int __init gdth_search_drives(int hanum)
alst->entries_avail = MAX_LDRIVES;
alst->first_entry = 0;
alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
ARRAY_DRV_LIST2 | LA_CTRL_PATTERN,
INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
(alst->entries_avail-1) * sizeof(gdth_alist_str))) {
@@ -2157,7 +1878,7 @@ static int __init gdth_search_drives(int hanum)
ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
ha->hdr[j].master_no = alst->list[j].cd_handle;
}
- } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
ARRAY_DRV_LIST | LA_CTRL_PATTERN,
0, 35 * sizeof(gdth_alist_str))) {
for (j = 0; j < 35; ++j) {
@@ -2175,24 +1896,24 @@ static int __init gdth_search_drives(int hanum)
/* initialize raw service */
ha->raw_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+ ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0);
if (ok)
ha->raw_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+ ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error raw service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
/* set/get features raw service (scatter/gather) */
- if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
- 0,0)) {
+ if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER,
+ 0, 0)) {
TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
- if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
+ if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
ha->info));
ha->raw_feat |= (ushort)ha->info;
@@ -2200,10 +1921,10 @@ static int __init gdth_search_drives(int hanum)
}
/* set/get features cache service (equal to raw service) */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0,
SCATTER_GATHER,0)) {
TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
ha->info));
ha->cache_feat |= (ushort)ha->info;
@@ -2212,22 +1933,22 @@ static int __init gdth_search_drives(int hanum)
/* reserve drives for raw service */
if (reserve_mode != 0) {
- gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE_ALL,
+ gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL,
reserve_mode == 1 ? 1 : 3, 0, 0);
TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n",
ha->status));
}
for (i = 0; i < MAX_RES_ARGS; i += 4) {
- if (reserve_list[i] == hanum && reserve_list[i+1] < ha->bus_cnt &&
+ if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt &&
reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) {
TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n",
reserve_list[i], reserve_list[i+1],
reserve_list[i+2], reserve_list[i+3]));
- if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
+ if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0,
reserve_list[i+1], reserve_list[i+2] |
(reserve_list[i+3] << 8))) {
printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
}
}
}
@@ -2236,58 +1957,44 @@ static int __init gdth_search_drives(int hanum)
oemstr = (gdth_oem_str_ioctl *)ha->pscratch;
oemstr->params.ctl_version = 0x01;
oemstr->params.buffer_size = sizeof(oemstr->text);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
sizeof(gdth_oem_str_ioctl))) {
TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
printk("GDT-HA %d: Vendor: %s Name: %s\n",
- hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
+ ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string);
/* Save the Host Drive inquiry data */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
sizeof(ha->oem_name));
-#else
- strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
- ha->oem_name[7] = '\0';
-#endif
} else {
/* Old method, based on PCI ID */
TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
printk("GDT-HA %d: Name: %s\n",
- hanum,ha->binfo.type_string);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ ha->hanum, ha->binfo.type_string);
if (ha->oem_id == OEM_ID_INTEL)
strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name));
else
strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name));
-#else
- if (ha->oem_id == OEM_ID_INTEL)
- strcpy(ha->oem_name,"Intel ");
- else
- strcpy(ha->oem_name,"ICP ");
-#endif
}
/* scanning for host drives */
for (i = 0; i < cdev_cnt; ++i)
- gdth_analyse_hdrive(hanum,i);
+ gdth_analyse_hdrive(ha, i);
TRACE(("gdth_search_drives() OK\n"));
return 1;
}
-static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
{
- register gdth_ha_str *ha;
ulong32 drv_cyls;
int drv_hds, drv_secs;
- TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+ TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive));
if (hdrive >= MAX_HDRIVES)
return 0;
- ha = HADATA(gdth_ctr_tab[hanum]);
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0))
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0))
return 0;
ha->hdr[hdrive].present = TRUE;
ha->hdr[hdrive].size = ha->info;
@@ -2307,7 +2014,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs;
if (ha->cache_feat & GDT_64BIT) {
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0)
&& ha->info2 != 0) {
ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
}
@@ -2316,14 +2023,14 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
/* get informations about device */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
hdrive,ha->info));
ha->hdr[hdrive].devtype = (ushort)ha->info;
}
/* cluster info */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
hdrive,ha->info));
if (!shared_access)
@@ -2331,7 +2038,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
}
/* R/W attributes */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
hdrive,ha->info));
ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
@@ -2343,27 +2050,26 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
/* command queueing/sending functions */
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
{
- register gdth_ha_str *ha;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
ulong flags;
unchar b, t;
TRACE(("gdth_putq() priority %d\n",priority));
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
- if (scp->done != gdth_scsi_done) {
- scp->SCp.this_residual = (int)priority;
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum:scp->device->channel;
+ if (!cmndinfo->internal_command) {
+ cmndinfo->priority = priority;
+ b = scp->device->channel;
t = scp->device->id;
if (priority >= DEFAULT_PRI) {
if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
(b==ha->virt_bus && t<MAX_HDRIVES && ha->hdr[t].lock)) {
TRACE2(("gdth_putq(): locked IO ->update_timeout()\n"));
- scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+ cmndinfo->timeout = gdth_update_timeout(scp, 0);
}
}
}
@@ -2375,7 +2081,7 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
pscp = ha->req_first;
nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
/* priority: 0-highest,..,0xff-lowest */
- while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+ while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) {
pscp = nscp;
nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
}
@@ -2395,9 +2101,8 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
#endif
}
-static void gdth_next(int hanum)
+static void gdth_next(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
unchar b, t, l, firsttime;
@@ -2405,8 +2110,7 @@ static void gdth_next(int hanum)
ulong flags = 0;
int cmd_index;
- TRACE(("gdth_next() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_next() hanum %d\n", ha->hanum));
if (!gdth_polling)
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -2416,14 +2120,14 @@ static void gdth_next(int hanum)
cmd_index = 0;
for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+ struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp);
if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
- if (nscp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
+ if (!nscp_cmndinfo->internal_command) {
+ b = nscp->device->channel;
t = nscp->device->id;
l = nscp->device->lun;
- if (nscp->SCp.this_residual >= DEFAULT_PRI) {
+ if (nscp_cmndinfo->priority >= DEFAULT_PRI) {
if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
(b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock))
continue;
@@ -2432,21 +2136,21 @@ static void gdth_next(int hanum)
b = t = l = 0;
if (firsttime) {
- if (gdth_test_busy(hanum)) { /* controller busy ? */
- TRACE(("gdth_next() controller %d busy !\n",hanum));
+ if (gdth_test_busy(ha)) { /* controller busy ? */
+ TRACE(("gdth_next() controller %d busy !\n", ha->hanum));
if (!gdth_polling) {
spin_unlock_irqrestore(&ha->smp_lock, flags);
return;
}
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(1);
}
firsttime = FALSE;
}
- if (nscp->done != gdth_scsi_done) {
- if (nscp->SCp.phase == -1) {
- nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */
+ if (!nscp_cmndinfo->internal_command) {
+ if (nscp_cmndinfo->phase == -1) {
+ nscp_cmndinfo->phase = CACHESERVICE; /* default: cache svc. */
if (nscp->cmnd[0] == TEST_UNIT_READY) {
TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n",
b, t, l));
@@ -2459,8 +2163,8 @@ static void gdth_next(int hanum)
} else if ((ha->scan_mode & 0x0f) == 1) {
if (b == 0 && ((t == 0 && l == 1) ||
(t == 1 && l == 0))) {
- nscp->SCp.sent_command = GDT_SCAN_START;
- nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8)
+ nscp_cmndinfo->OpCode = GDT_SCAN_START;
+ nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8)
| SCSIRAWSERVICE;
ha->scan_mode = 0x12;
TRACE2(("Scan mode: 0x%x (SCAN_START)\n",
@@ -2471,8 +2175,8 @@ static void gdth_next(int hanum)
}
} else if (ha->scan_mode == 0x12) {
if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
- nscp->SCp.phase = SCSIRAWSERVICE;
- nscp->SCp.sent_command = GDT_SCAN_END;
+ nscp_cmndinfo->phase = SCSIRAWSERVICE;
+ nscp_cmndinfo->OpCode = GDT_SCAN_END;
ha->scan_mode &= 0x10;
TRACE2(("Scan mode: 0x%x (SCAN_END)\n",
ha->scan_mode));
@@ -2483,18 +2187,18 @@ static void gdth_next(int hanum)
nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
(ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
/* always GDT_CLUST_INFO! */
- nscp->SCp.sent_command = GDT_CLUST_INFO;
+ nscp_cmndinfo->OpCode = GDT_CLUST_INFO;
}
}
}
- if (nscp->SCp.sent_command != -1) {
- if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (nscp_cmndinfo->OpCode != -1) {
+ if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) {
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
next_cmd = FALSE;
- } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
- if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+ } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) {
+ if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
this_cmd = FALSE;
next_cmd = FALSE;
} else {
@@ -2502,18 +2206,18 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = NOT_READY;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
}
- } else if (nscp->done == gdth_scsi_done) {
- if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
+ } else if (gdth_cmnd_priv(nscp)->internal_command) {
+ if (!(cmd_index=gdth_special_cmd(ha, nscp)))
this_cmd = FALSE;
next_cmd = FALSE;
} else if (b != ha->virt_bus) {
if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
- !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+ !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
this_cmd = FALSE;
else
ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
@@ -2521,10 +2225,10 @@ static void gdth_next(int hanum)
TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
nscp->cmnd[0], b, t, l));
nscp->result = DID_BAD_TARGET << 16;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
} else {
switch (nscp->cmnd[0]) {
case TEST_UNIT_READY:
@@ -2547,12 +2251,12 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = UNIT_ATTENTION;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
- } else if (gdth_internal_cache_cmd(hanum,nscp))
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
+ } else if (gdth_internal_cache_cmd(ha, nscp))
+ gdth_scsi_done(nscp);
break;
case ALLOW_MEDIUM_REMOVAL:
@@ -2563,15 +2267,15 @@ static void gdth_next(int hanum)
TRACE(("Prevent r. nonremov. drive->do nothing\n"));
nscp->result = DID_OK << 16;
nscp->sense_buffer[0] = 0;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
} else {
nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
TRACE(("Prevent/allow r. %d rem. drive %d\n",
nscp->cmnd[4],nscp->cmnd[3]));
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
}
break;
@@ -2580,7 +2284,7 @@ static void gdth_next(int hanum)
case RELEASE:
TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
"RESERVE" : "RELEASE"));
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
break;
@@ -2599,11 +2303,11 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = UNIT_ATTENTION;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
- } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ gdth_scsi_done(nscp);
+ } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
break;
@@ -2612,12 +2316,12 @@ static void gdth_next(int hanum)
nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
nscp->cmnd[4],nscp->cmnd[5]));
printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
- hanum, nscp->cmnd[0]);
+ ha->hanum, nscp->cmnd[0]);
nscp->result = DID_ABORT << 16;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
break;
}
}
@@ -2633,79 +2337,77 @@ static void gdth_next(int hanum)
}
if (ha->cmd_cnt > 0) {
- gdth_release_event(hanum);
+ gdth_release_event(ha);
}
if (!gdth_polling)
spin_unlock_irqrestore(&ha->smp_lock, flags);
if (gdth_polling && ha->cmd_cnt > 0) {
- if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+ if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT))
printk("GDT-HA %d: Command %d timed out !\n",
- hanum,cmd_index);
+ ha->hanum, cmd_index);
}
}
-
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
- char *buffer,ushort count)
+
+/*
+ * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's
+ * buffers, kmap_atomic() as needed.
+ */
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+ char *buffer, ushort count, int to_buffer)
{
- ushort cpcount,i;
+ ushort cpcount,i, max_sg = gdth_sg_count(scp);
ushort cpsum,cpnow;
struct scatterlist *sl;
- gdth_ha_str *ha;
char *address;
- cpcount = count<=(ushort)scp->request_bufflen ? count:(ushort)scp->request_bufflen;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ cpcount = min_t(ushort, count, gdth_bufflen(scp));
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+ if (cpcount) {
+ cpsum=0;
+ scsi_for_each_sg(scp, sl, max_sg, i) {
unsigned long flags;
cpnow = (ushort)sl->length;
TRACE(("copy_internal() now %d sum %d count %d %d\n",
- cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+ cpnow, cpsum, cpcount, gdth_bufflen(scp)));
if (cpsum+cpnow > cpcount)
cpnow = cpcount - cpsum;
cpsum += cpnow;
if (!sl->page) {
printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
- hanum);
+ ha->hanum);
return;
}
local_irq_save(flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset;
- memcpy(address,buffer,cpnow);
+ if (to_buffer)
+ memcpy(buffer, address, cpnow);
+ else
+ memcpy(address, buffer, cpnow);
flush_dcache_page(sl->page);
kunmap_atomic(address, KM_BIO_SRC_IRQ);
-#else
- address = kmap_atomic(sl->page, KM_BH_IRQ) + sl->offset;
- memcpy(address,buffer,cpnow);
- flush_dcache_page(sl->page);
- kunmap_atomic(address, KM_BH_IRQ);
-#endif
local_irq_restore(flags);
if (cpsum == cpcount)
break;
buffer += cpnow;
}
- } else {
- TRACE(("copy_internal() count %d\n",cpcount));
- memcpy((char*)scp->request_buffer,buffer,cpcount);
+ } else if (count) {
+ printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n",
+ ha->hanum);
+ WARN_ON(1);
}
}
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
unchar t;
gdth_inq_data inq;
gdth_rdcap_data rdc;
gdth_sense_data sd;
gdth_modep_data mpd;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- ha = HADATA(gdth_ctr_tab[hanum]);
t = scp->device->id;
TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
scp->cmnd[0],t));
@@ -2736,7 +2438,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
strcpy(inq.vendor,ha->oem_name);
sprintf(inq.product,"Host Drive #%02d",t);
strcpy(inq.revision," ");
- gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data));
+ gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0);
break;
case REQUEST_SENSE:
@@ -2746,7 +2448,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
sd.key = NO_SENSE;
sd.info = 0;
sd.add_length= 0;
- gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data));
+ gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0);
break;
case MODE_SENSE:
@@ -2758,7 +2460,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
- gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data));
+ gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0);
break;
case READ_CAPACITY:
@@ -2768,7 +2470,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
else
rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
rdc.block_length = cpu_to_be32(SECTOR_SIZE);
- gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+ gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0);
break;
case SERVICE_ACTION_IN:
@@ -2779,7 +2481,8 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
TRACE2(("Read capacity (16) hdrive %d\n",t));
rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
rdc16.block_length = cpu_to_be32(SECTOR_SIZE);
- gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+ gdth_copy_internal_data(ha, scp, (char*)&rdc16,
+ sizeof(gdth_rdcap16_data), 0);
} else {
scp->result = DID_ABORT << 16;
}
@@ -2790,27 +2493,22 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
break;
}
- if (!scp->SCp.have_data_in)
- scp->SCp.have_data_in++;
+ if (!cmndinfo->wait_for_completion)
+ cmndinfo->wait_for_completion++;
else
return 1;
return 0;
}
-
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
- struct scatterlist *sl;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
ulong32 cnt, blockcnt;
ulong64 no, blockno;
- dma_addr_t phys_addr;
int i, cmd_index, read_write, sgcnt, mode64;
- struct page *page;
- ulong offset;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp = ha->pccb;
TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
scp->cmnd[0],scp->cmd_len,hdrive));
@@ -2826,18 +2524,18 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->Service = CACHESERVICE;
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
/* fill command */
read_write = 0;
- if (scp->SCp.sent_command != -1)
- cmdp->OpCode = scp->SCp.sent_command; /* special cache cmd. */
+ if (cmndinfo->OpCode != -1)
+ cmdp->OpCode = cmndinfo->OpCode; /* special cache cmd. */
else if (scp->cmnd[0] == RESERVE)
cmdp->OpCode = GDT_RESERVE_DRV;
else if (scp->cmnd[0] == RELEASE)
@@ -2898,17 +2596,17 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->u.cache.BlockCnt = blockcnt;
}
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- sgcnt = scp->use_sg;
- scp->SCp.Status = GDTH_MAP_SG;
- scp->SCp.Message = (read_write == 1 ?
+ if (gdth_bufflen(scp)) {
+ cmndinfo->dma_dir = (read_write == 1 ?
PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+ sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
if (mode64) {
+ struct scatterlist *sl;
+
cmdp->u.cache64.DestAddr= (ulong64)-1;
cmdp->u.cache64.sg_canz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -2919,9 +2617,11 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
}
} else {
+ struct scatterlist *sl;
+
cmdp->u.cache.DestAddr= 0xffffffff;
cmdp->u.cache.sg_canz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
ha->dma32_cnt++;
@@ -2937,38 +2637,6 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
}
#endif
- } else if (scp->request_bufflen) {
- scp->SCp.Status = GDTH_MAP_SINGLE;
- scp->SCp.Message = (read_write == 1 ?
- PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- page = virt_to_page(scp->request_buffer);
- offset = (ulong)scp->request_buffer & ~PAGE_MASK;
- phys_addr = pci_map_page(ha->pdev,page,offset,
- scp->request_bufflen,scp->SCp.Message);
- scp->SCp.dma_handle = phys_addr;
- if (mode64) {
- if (ha->cache_feat & SCATTER_GATHER) {
- cmdp->u.cache64.DestAddr = (ulong64)-1;
- cmdp->u.cache64.sg_canz = 1;
- cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.cache64.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.cache64.DestAddr = phys_addr;
- cmdp->u.cache64.sg_canz= 0;
- }
- } else {
- if (ha->cache_feat & SCATTER_GATHER) {
- cmdp->u.cache.DestAddr = 0xffffffff;
- cmdp->u.cache.sg_canz = 1;
- cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.cache.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.cache.DestAddr = phys_addr;
- cmdp->u.cache.sg_canz= 0;
- }
- }
}
}
/* evaluate command size, check space */
@@ -3004,23 +2672,21 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
- struct scatterlist *sl;
ushort i;
- dma_addr_t phys_addr, sense_paddr;
+ dma_addr_t sense_paddr;
int cmd_index, sgcnt, mode64;
unchar t,l;
struct page *page;
ulong offset;
+ struct gdth_cmndinfo *cmndinfo;
- ha = HADATA(gdth_ctr_tab[hanum]);
t = scp->device->id;
l = scp->device->lun;
cmdp = ha->pccb;
@@ -3035,26 +2701,27 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->Service = SCSIRAWSERVICE;
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
+ cmndinfo = gdth_cmnd_priv(scp);
/* fill command */
- if (scp->SCp.sent_command != -1) {
- cmdp->OpCode = scp->SCp.sent_command; /* special raw cmd. */
+ if (cmndinfo->OpCode != -1) {
+ cmdp->OpCode = cmndinfo->OpCode; /* special raw cmd. */
cmdp->BoardNode = LOCALBOARD;
if (mode64) {
- cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+ cmdp->u.raw64.direction = (cmndinfo->phase >> 8);
TRACE2(("special raw cmd 0x%x param 0x%x\n",
cmdp->OpCode, cmdp->u.raw64.direction));
/* evaluate command size */
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
} else {
- cmdp->u.raw.direction = (scp->SCp.phase >> 8);
+ cmdp->u.raw.direction = (cmndinfo->phase >> 8);
TRACE2(("special raw cmd 0x%x param 0x%x\n",
cmdp->OpCode, cmdp->u.raw.direction));
/* evaluate command size */
@@ -3066,9 +2733,8 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
sense_paddr = pci_map_page(ha->pdev,page,offset,
16,PCI_DMA_FROMDEVICE);
- *(ulong32 *)&scp->SCp.buffer = (ulong32)sense_paddr;
- /* high part, if 64bit */
- *(ulong32 *)&scp->host_scribble = (ulong32)((ulong64)sense_paddr >> 32);
+
+ cmndinfo->sense_paddr = sense_paddr;
cmdp->OpCode = GDT_WRITE; /* always */
cmdp->BoardNode = LOCALBOARD;
if (mode64) {
@@ -3080,7 +2746,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw64.lun = l;
cmdp->u.raw64.bus = b;
cmdp->u.raw64.priority = 0;
- cmdp->u.raw64.sdlen = scp->request_bufflen;
+ cmdp->u.raw64.sdlen = gdth_bufflen(scp);
cmdp->u.raw64.sense_len = 16;
cmdp->u.raw64.sense_data = sense_paddr;
cmdp->u.raw64.direction =
@@ -3097,7 +2763,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw.bus = b;
cmdp->u.raw.priority = 0;
cmdp->u.raw.link_p = 0;
- cmdp->u.raw.sdlen = scp->request_bufflen;
+ cmdp->u.raw.sdlen = gdth_bufflen(scp);
cmdp->u.raw.sense_len = 16;
cmdp->u.raw.sense_data = sense_paddr;
cmdp->u.raw.direction =
@@ -3106,16 +2772,16 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw.sg_ranz = 0;
}
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- sgcnt = scp->use_sg;
- scp->SCp.Status = GDTH_MAP_SG;
- scp->SCp.Message = PCI_DMA_BIDIRECTIONAL;
- sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+ if (gdth_bufflen(scp)) {
+ cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL;
+ sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
if (mode64) {
+ struct scatterlist *sl;
+
cmdp->u.raw64.sdata = (ulong64)-1;
cmdp->u.raw64.sg_ranz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -3126,9 +2792,11 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
}
} else {
+ struct scatterlist *sl;
+
cmdp->u.raw.sdata = 0xffffffff;
cmdp->u.raw.sg_ranz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
ha->dma32_cnt++;
@@ -3144,38 +2812,6 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
}
#endif
- } else if (scp->request_bufflen) {
- scp->SCp.Status = GDTH_MAP_SINGLE;
- scp->SCp.Message = PCI_DMA_BIDIRECTIONAL;
- page = virt_to_page(scp->request_buffer);
- offset = (ulong)scp->request_buffer & ~PAGE_MASK;
- phys_addr = pci_map_page(ha->pdev,page,offset,
- scp->request_bufflen,scp->SCp.Message);
- scp->SCp.dma_handle = phys_addr;
-
- if (mode64) {
- if (ha->raw_feat & SCATTER_GATHER) {
- cmdp->u.raw64.sdata = (ulong64)-1;
- cmdp->u.raw64.sg_ranz= 1;
- cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.raw64.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.raw64.sdata = phys_addr;
- cmdp->u.raw64.sg_ranz= 0;
- }
- } else {
- if (ha->raw_feat & SCATTER_GATHER) {
- cmdp->u.raw.sdata = 0xffffffff;
- cmdp->u.raw.sg_ranz= 1;
- cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.raw.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.raw.sdata = phys_addr;
- cmdp->u.raw.sg_ranz= 0;
- }
- }
}
if (mode64) {
TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
@@ -3209,35 +2845,33 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
int cmd_index;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp= ha->pccb;
TRACE2(("gdth_special_cmd(): "));
if (ha->type==GDT_EISA && ha->cmd_cnt>0)
return 0;
- memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+ gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1);
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
/* evaluate command size, check space */
if (cmdp->OpCode == GDT_IOCTL) {
@@ -3275,7 +2909,7 @@ static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
@@ -3402,15 +3036,14 @@ static void gdth_clear_events(void)
/* SCSI interface functions */
-static irqreturn_t gdth_interrupt(int irq,void *dev_id)
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+ int gdth_from_wait, int* pIndex)
{
- gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
- register gdth_ha_str *ha;
gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
gdt6_dpram_str __iomem *dp6_ptr;
gdt2_dpram_str __iomem *dp2_ptr;
Scsi_Cmnd *scp;
- int hanum, rval, i;
+ int rval, i;
unchar IStatus;
ushort Service;
ulong flags = 0;
@@ -3431,17 +3064,15 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
}
if (!gdth_polling)
- spin_lock_irqsave(&ha2->smp_lock, flags);
- wait_index = 0;
+ spin_lock_irqsave(&ha->smp_lock, flags);
/* search controller */
- if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+ if (0 == (IStatus = gdth_get_status(ha, irq))) {
/* spurious interrupt */
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
- return IRQ_HANDLED;
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+ return IRQ_HANDLED;
}
- ha = HADATA(gdth_ctr_tab[hanum]);
#ifdef GDTH_STATISTICS
++act_ints;
@@ -3482,32 +3113,32 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
dp2_ptr = ha->brd;
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
- ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+ ha->status = readw(&dp2_ptr->u.ic.Status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
- ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
- ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
- ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+ ha->info = readl(&dp2_ptr->u.ic.Info[0]);
+ ha->service = readw(&dp2_ptr->u.ic.Service);
+ ha->info2 = readl(&dp2_ptr->u.ic.Info[1]);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
- gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
- gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */
+ writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+ writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+ writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
- ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+ ha->status = readw(&dp6_ptr->u.ic.Status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
- ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
- ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
- ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+ ha->info = readl(&dp6_ptr->u.ic.Info[0]);
+ ha->service = readw(&dp6_ptr->u.ic.Service);
+ ha->info2 = readl(&dp6_ptr->u.ic.Info[1]);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
- gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
- gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */
+ writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+ writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+ writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */
} else if (ha->type == GDT_PCINEW) {
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
@@ -3530,7 +3161,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
ha->status = pcs->ext_status & 0xffff;
else
#endif
- ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+ ha->status = readw(&dp6m_ptr->i960r.status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
@@ -3543,18 +3174,18 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
} else
#endif
{
- ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
- ha->service = gdth_readw(&dp6m_ptr->i960r.service);
- ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+ ha->info = readl(&dp6m_ptr->i960r.info[0]);
+ ha->service = readw(&dp6m_ptr->i960r.service);
+ ha->info2 = readl(&dp6m_ptr->i960r.info[1]);
}
/* event string */
if (IStatus == ASYNCINDEX) {
if (ha->service != SCREENSERVICE &&
(ha->fw_vers & 0xff) >= 0x1a) {
- ha->dvr.severity = gdth_readb
+ ha->dvr.severity = readb
(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity);
for (i = 0; i < 256; ++i) {
- ha->dvr.event_string[i] = gdth_readb
+ ha->dvr.event_string[i] = readb
(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]);
if (ha->dvr.event_string[i] == 0)
break;
@@ -3567,13 +3198,13 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
if (!coalesced)
#endif
{
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0, &dp6m_ptr->i960r.sema1_reg);
}
} else {
TRACE2(("gdth_interrupt() unknown controller type\n"));
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
@@ -3581,26 +3212,25 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
IStatus,ha->status,ha->info));
if (gdth_from_wait) {
- wait_hanum = hanum;
- wait_index = (int)IStatus;
+ *pIndex = (int)IStatus;
}
if (IStatus == ASYNCINDEX) {
TRACE2(("gdth_interrupt() async. event\n"));
- gdth_async_event(hanum);
+ gdth_async_event(ha);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
- gdth_next(hanum);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+ gdth_next(ha);
return IRQ_HANDLED;
}
if (IStatus == SPEZINDEX) {
TRACE2(("Service unknown or not initialized !\n"));
ha->dvr.size = sizeof(ha->dvr.eu.driver);
- ha->dvr.eu.driver.ionode = hanum;
+ ha->dvr.eu.driver.ionode = ha->hanum;
gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
scp = ha->cmd_tab[IStatus-2].cmnd;
@@ -3609,28 +3239,28 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
if (scp == UNUSED_CMND) {
TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
ha->dvr.size = sizeof(ha->dvr.eu.driver);
- ha->dvr.eu.driver.ionode = hanum;
+ ha->dvr.eu.driver.ionode = ha->hanum;
ha->dvr.eu.driver.index = IStatus;
gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
if (scp == INTERNAL_CMND) {
TRACE(("gdth_interrupt() answer to internal command\n"));
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
TRACE(("gdth_interrupt() sync. status\n"));
- rval = gdth_sync_event(hanum,Service,IStatus,scp);
+ rval = gdth_sync_event(ha,Service,IStatus,scp);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
if (rval == 2) {
- gdth_putq(hanum,scp,scp->SCp.this_residual);
+ gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority);
} else if (rval == 1) {
- scp->scsi_done(scp);
+ gdth_scsi_done(scp);
}
#ifdef INT_COAL
@@ -3653,23 +3283,30 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
/* coalescing only for new GDT_PCIMPR controllers available */
if (ha->type == GDT_PCIMPR && coalesced) {
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0, &dp6m_ptr->i960r.sema1_reg);
}
#endif
- gdth_next(hanum);
+ gdth_next(ha);
return IRQ_HANDLED;
}
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+static irqreturn_t gdth_interrupt(int irq, void *dev_id)
+{
+ gdth_ha_str *ha = (gdth_ha_str *)dev_id;
+
+ return __gdth_interrupt(ha, irq, false, NULL);
+}
+
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+ Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
gdth_msg_str *msg;
gdth_cmd_str *cmdp;
unchar b, t;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp = ha->pccb;
TRACE(("gdth_sync_event() serv %d status %d\n",
service,ha->status));
@@ -3687,12 +3324,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
if (msg->msg_ext && !msg->msg_answer) {
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_READ;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -3702,8 +3339,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
return 0;
}
@@ -3721,12 +3358,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
msg->msg_ext = 0;
msg->msg_answer = 0;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_WRITE;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -3736,74 +3373,67 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
return 0;
}
printk("\n");
} else {
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ b = scp->device->channel;
t = scp->device->id;
- if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
+ if (cmndinfo->OpCode == -1 && b != ha->virt_bus) {
ha->raw[BUS_L2P(ha,b)].io_cnt[t]--;
}
/* cache or raw service */
if (ha->status == S_BSY) {
TRACE2(("Controller busy -> retry !\n"));
- if (scp->SCp.sent_command == GDT_MOUNT)
- scp->SCp.sent_command = GDT_CLUST_INFO;
+ if (cmndinfo->OpCode == GDT_MOUNT)
+ cmndinfo->OpCode = GDT_CLUST_INFO;
/* retry */
return 2;
}
- if (scp->SCp.Status == GDTH_MAP_SG)
- pci_unmap_sg(ha->pdev,scp->request_buffer,
- scp->use_sg,scp->SCp.Message);
- else if (scp->SCp.Status == GDTH_MAP_SINGLE)
- pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
- scp->request_bufflen,scp->SCp.Message);
- if (scp->SCp.buffer) {
- dma_addr_t addr;
- addr = (dma_addr_t)*(ulong32 *)&scp->SCp.buffer;
- if (scp->host_scribble)
- addr += (dma_addr_t)
- ((ulong64)(*(ulong32 *)&scp->host_scribble) << 32);
- pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
- }
+ if (gdth_bufflen(scp))
+ pci_unmap_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
+
+ if (cmndinfo->sense_paddr)
+ pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16,
+ PCI_DMA_FROMDEVICE);
if (ha->status == S_OK) {
- scp->SCp.Status = S_OK;
- scp->SCp.Message = ha->info;
- if (scp->SCp.sent_command != -1) {
+ cmndinfo->status = S_OK;
+ cmndinfo->info = ha->info;
+ if (cmndinfo->OpCode != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
- scp->SCp.sent_command));
+ cmndinfo->OpCode));
/* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
- if (scp->SCp.sent_command == GDT_CLUST_INFO) {
+ if (cmndinfo->OpCode == GDT_CLUST_INFO) {
ha->hdr[t].cluster_type = (unchar)ha->info;
if (!(ha->hdr[t].cluster_type &
CLUSTER_MOUNTED)) {
/* NOT MOUNTED -> MOUNT */
- scp->SCp.sent_command = GDT_MOUNT;
+ cmndinfo->OpCode = GDT_MOUNT;
if (ha->hdr[t].cluster_type &
CLUSTER_RESERVED) {
/* cluster drive RESERVED (on the other node) */
- scp->SCp.phase = -2; /* reservation conflict */
+ cmndinfo->phase = -2; /* reservation conflict */
}
} else {
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode = -1;
}
} else {
- if (scp->SCp.sent_command == GDT_MOUNT) {
+ if (cmndinfo->OpCode == GDT_MOUNT) {
ha->hdr[t].cluster_type |= CLUSTER_MOUNTED;
ha->hdr[t].media_changed = TRUE;
- } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
+ } else if (cmndinfo->OpCode == GDT_UNMOUNT) {
ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED;
ha->hdr[t].media_changed = TRUE;
}
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode = -1;
}
/* retry */
- scp->SCp.this_residual = HIGH_PRI;
+ cmndinfo->priority = HIGH_PRI;
return 2;
} else {
/* RESERVE/RELEASE ? */
@@ -3816,17 +3446,17 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
scp->sense_buffer[0] = 0;
}
} else {
- scp->SCp.Status = ha->status;
- scp->SCp.Message = ha->info;
+ cmndinfo->status = ha->status;
+ cmndinfo->info = ha->info;
- if (scp->SCp.sent_command != -1) {
+ if (cmndinfo->OpCode != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
- scp->SCp.sent_command, ha->status));
- if (scp->SCp.sent_command == GDT_SCAN_START ||
- scp->SCp.sent_command == GDT_SCAN_END) {
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode, ha->status));
+ if (cmndinfo->OpCode == GDT_SCAN_START ||
+ cmndinfo->OpCode == GDT_SCAN_END) {
+ cmndinfo->OpCode = -1;
/* retry */
- scp->SCp.this_residual = HIGH_PRI;
+ cmndinfo->priority = HIGH_PRI;
return 2;
}
memset((char*)scp->sense_buffer,0,16);
@@ -3848,9 +3478,9 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
scp->sense_buffer[2] = NOT_READY;
scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
}
- if (scp->done != gdth_scsi_done) {
+ if (!cmndinfo->internal_command) {
ha->dvr.size = sizeof(ha->dvr.eu.sync);
- ha->dvr.eu.sync.ionode = hanum;
+ ha->dvr.eu.sync.ionode = ha->hanum;
ha->dvr.eu.sync.service = service;
ha->dvr.eu.sync.status = ha->status;
ha->dvr.eu.sync.info = ha->info;
@@ -3869,8 +3499,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
}
}
- if (!scp->SCp.have_data_in)
- scp->SCp.have_data_in++;
+ if (!cmndinfo->wait_for_completion)
+ cmndinfo->wait_for_completion++;
else
return 1;
}
@@ -4034,25 +3664,23 @@ static char *async_cache_tab[] = {
};
-static int gdth_async_event(int hanum)
+static int gdth_async_event(gdth_ha_str *ha)
{
- gdth_ha_str *ha;
gdth_cmd_str *cmdp;
int cmd_index;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp= ha->pccb;
TRACE2(("gdth_async_event() ha %d serv %d\n",
- hanum,ha->service));
+ ha->hanum, ha->service));
if (ha->service == SCREENSERVICE) {
if (ha->status == MSG_REQUEST) {
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- cmd_index = gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ cmd_index = gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_READ;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -4062,7 +3690,7 @@ static int gdth_async_event(int hanum)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
if (ha->type == GDT_EISA)
printk("[EISA slot %d] ",(ushort)ha->brd_phys);
else if (ha->type == GDT_ISA)
@@ -4070,19 +3698,19 @@ static int gdth_async_event(int hanum)
else
printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
(ushort)((ha->brd_phys>>3)&0x1f));
- gdth_release_event(hanum);
+ gdth_release_event(ha);
}
} else {
if (ha->type == GDT_PCIMPR &&
(ha->fw_vers & 0xff) >= 0x1a) {
ha->dvr.size = 0;
- ha->dvr.eu.async.ionode = hanum;
+ ha->dvr.eu.async.ionode = ha->hanum;
ha->dvr.eu.async.status = ha->status;
/* severity and event_string already set! */
} else {
ha->dvr.size = sizeof(ha->dvr.eu.async);
- ha->dvr.eu.async.ionode = hanum;
+ ha->dvr.eu.async.ionode = ha->hanum;
ha->dvr.eu.async.service = ha->service;
ha->dvr.eu.async.status = ha->status;
ha->dvr.eu.async.info = ha->info;
@@ -4164,9 +3792,8 @@ static void gdth_timeout(ulong data)
Scsi_Cmnd *nscp;
gdth_ha_str *ha;
ulong flags;
- int hanum = 0;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
spin_lock_irqsave(&ha->smp_lock, flags);
for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i)
@@ -4229,8 +3856,6 @@ static void __init internal_setup(char *str,int *ints)
max_ids = val;
else if (!strncmp(argv, "rescan:", 7))
rescan = val;
- else if (!strncmp(argv, "virt_ctr:", 9))
- virt_ctr = val;
else if (!strncmp(argv, "shared_access:", 14))
shared_access = val;
else if (!strncmp(argv, "probe_eisa_isa:", 15))
@@ -4277,523 +3902,10 @@ int __init option_setup(char *str)
return 1;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static int __init gdth_detect(struct scsi_host_template *shtp)
-#else
-static int __init gdth_detect(Scsi_Host_Template *shtp)
-#endif
+static const char *gdth_ctr_name(gdth_ha_str *ha)
{
- struct Scsi_Host *shp;
- gdth_pci_str pcistr[MAXHA];
- gdth_ha_str *ha;
- ulong32 isa_bios;
- ushort eisa_slot;
- int i,hanum,cnt,ctr,err;
- unchar b;
-
-
-#ifdef DEBUG_GDTH
- printk("GDT: This driver contains debugging information !! Trace level = %d\n",
- DebugState);
- printk(" Destination of debugging information: ");
-#ifdef __SERIAL__
-#ifdef __COM2__
- printk("Serial port COM2\n");
-#else
- printk("Serial port COM1\n");
-#endif
-#else
- printk("Console\n");
-#endif
- gdth_delay(3000);
-#endif
-
- TRACE(("gdth_detect()\n"));
-
- if (disable) {
- printk("GDT-HA: Controller driver disabled from command line !\n");
- return 0;
- }
-
- printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",GDTH_VERSION_STR);
- /* initializations */
- gdth_polling = TRUE; b = 0;
- gdth_clear_events();
-
- /* As default we do not probe for EISA or ISA controllers */
- if (probe_eisa_isa) {
- /* scanning for controllers, at first: ISA controller */
- for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- if (gdth_search_isa(isa_bios)) { /* controller found */
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_isa(isa_bios,ha)) {
- scsi_unregister(shp);
- continue;
- }
-#ifdef __ia64__
- break;
-#else
- /* controller found and initialized */
- printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
- isa_bios,ha->irq,ha->drq);
-
- if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
- printk("GDT-ISA: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- if (request_dma(ha->drq,"gdth")) {
- printk("GDT-ISA: Unable to allocate DMA channel\n");
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- set_dma_mode(ha->drq,DMA_MODE_CASCADE);
- enable_dma(ha->drq);
- shp->unchecked_isa_dma = 1;
- shp->irq = ha->irq;
- shp->dma_channel = ha->drq;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
- ha->pdev = NULL;
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
-
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- printk("GDT-ISA: Error during device scan\n");
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
-
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
- LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- shp->highmem_io = 0;
-#endif
- if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
- shp->max_cmd_len = 16;
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 1;
- shp->irq = ha->irq;
- shp->dma_channel = ha->drq;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
-#endif /* !__ia64__ */
- }
- }
-
- /* scanning for EISA controllers */
- for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- if (gdth_search_eisa(eisa_slot)) { /* controller found */
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_eisa(eisa_slot,ha)) {
- scsi_unregister(shp);
- continue;
- }
- /* controller found and initialized */
- printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
- eisa_slot>>12,ha->irq);
-
- if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
- printk("GDT-EISA: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
- TRACE2(("EISA detect Bus 0: hanum %d\n",
- NUMDATA(shp)->hanum));
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
-
- ha->pdev = NULL;
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
- ha->ccb_phys =
- pci_map_single(ha->pdev,ha->pccb,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- printk("GDT-EISA: Error during device scan\n");
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- if (ha->ccb_phys)
- pci_unmap_single(ha->pdev,ha->ccb_phys,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
- LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- shp->highmem_io = 0;
-#endif
- if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
- shp->max_cmd_len = 16;
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
- }
- }
- }
-
- /* scanning for PCI controllers */
- cnt = gdth_search_pci(pcistr);
- printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
- gdth_sort_pci(pcistr,cnt);
- for (ctr = 0; ctr < cnt; ++ctr) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_pci(&pcistr[ctr],ha)) {
- scsi_unregister(shp);
- continue;
- }
- /* controller found and initialized */
- printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
- pcistr[ctr].pdev->bus->number,
- PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq);
-
- if (request_irq(ha->irq, gdth_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
- {
- printk("GDT-PCI: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
-
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- err = FALSE;
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- err = TRUE;
- } else {
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- scsi_set_pci_device(shp, pcistr[ctr].pdev);
-#endif
- if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
- /* 64-bit DMA only supported from FW >= x.43 */
- (!ha->dma64_support)) {
- if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
- err = TRUE;
- }
- } else {
- shp->max_cmd_len = 16;
- if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
- printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
- } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
- err = TRUE;
- }
- }
- }
-
- if (err) {
- printk("GDT-PCI %d: Error during device scan\n", hanum);
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
- }
-
- TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
- if (gdth_ctr_count > 0) {
-#ifdef GDTH_STATISTICS
- TRACE2(("gdth_detect(): Initializing timer !\n"));
- init_timer(&gdth_timer);
- gdth_timer.expires = jiffies + HZ;
- gdth_timer.data = 0L;
- gdth_timer.function = gdth_timeout;
- add_timer(&gdth_timer);
-#endif
- major = register_chrdev(0,"gdth",&gdth_fops);
- notifier_disabled = 0;
- register_reboot_notifier(&gdth_notifier);
- }
- gdth_polling = FALSE;
- return gdth_ctr_vcount;
-}
-
-static int gdth_release(struct Scsi_Host *shp)
-{
- int hanum;
- gdth_ha_str *ha;
-
- TRACE2(("gdth_release()\n"));
- if (NUMDATA(shp)->busnum == 0) {
- hanum = NUMDATA(shp)->hanum;
- ha = HADATA(gdth_ctr_tab[hanum]);
- if (ha->sdev) {
- scsi_free_host_dev(ha->sdev);
- ha->sdev = NULL;
- }
- gdth_flush(hanum);
-
- if (shp->irq) {
- free_irq(shp->irq,ha);
- }
-#ifndef __ia64__
- if (shp->dma_channel != 0xff) {
- free_dma(shp->dma_channel);
- }
-#endif
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- if (ha->ccb_phys)
- pci_unmap_single(ha->pdev,ha->ccb_phys,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- gdth_ctr_released++;
- TRACE2(("gdth_release(): HA %d of %d\n",
- gdth_ctr_released, gdth_ctr_count));
-
- if (gdth_ctr_released == gdth_ctr_count) {
-#ifdef GDTH_STATISTICS
- del_timer(&gdth_timer);
-#endif
- unregister_chrdev(major,"gdth");
- unregister_reboot_notifier(&gdth_notifier);
- }
- }
-
- scsi_unregister(shp);
- return 0;
-}
-
-
-static const char *gdth_ctr_name(int hanum)
-{
- gdth_ha_str *ha;
-
TRACE2(("gdth_ctr_name()\n"));
- ha = HADATA(gdth_ctr_tab[hanum]);
-
if (ha->type == GDT_EISA) {
switch (ha->stype) {
case GDT3_ID:
@@ -4820,29 +3932,23 @@ static const char *gdth_ctr_name(int hanum)
static const char *gdth_info(struct Scsi_Host *shp)
{
- int hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(shp);
TRACE2(("gdth_info()\n"));
- hanum = NUMDATA(shp)->hanum;
- ha = HADATA(gdth_ctr_tab[hanum]);
-
return ((const char *)ha->binfo.type_string);
}
static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
{
- int i, hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(scp->device->host);
+ int i;
ulong flags;
Scsi_Cmnd *cmnd;
unchar b;
TRACE2(("gdth_eh_bus_reset()\n"));
- hanum = NUMDATA(scp->device->host)->hanum;
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ b = scp->device->channel;
/* clear command tab */
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -4859,9 +3965,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
if (ha->hdr[i].present) {
spin_lock_irqsave(&ha->smp_lock, flags);
gdth_polling = TRUE;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
- if (gdth_internal_cmd(hanum, CACHESERVICE,
+ if (gdth_internal_cmd(ha, CACHESERVICE,
GDT_CLUST_RESET, i, 0, 0))
ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
gdth_polling = FALSE;
@@ -4874,9 +3980,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
for (i = 0; i < MAXID; ++i)
ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
gdth_polling = TRUE;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
- gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+ gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS,
BUS_L2P(ha,b), 0, 0);
gdth_polling = FALSE;
spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -4884,30 +3990,18 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
return SUCCESS;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
-#else
-static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
-#endif
{
unchar b, t;
- int hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(sdev->host);
struct scsi_device *sd;
unsigned capacity;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
sd = sdev;
capacity = cap;
-#else
- sd = disk->device;
- capacity = disk->capacity;
-#endif
- hanum = NUMDATA(sd->host)->hanum;
- b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel;
+ b = sd->channel;
t = sd->id;
- TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t));
if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
/* raw device or host drive without mapping information */
@@ -4925,33 +4019,42 @@ static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
}
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+static int gdth_queuecommand(struct scsi_cmnd *scp,
+ void (*done)(struct scsi_cmnd *))
{
- int hanum;
- int priority;
+ gdth_ha_str *ha = shost_priv(scp->device->host);
+ struct gdth_cmndinfo *cmndinfo;
TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0]));
-
- scp->scsi_done = (void *)done;
- scp->SCp.have_data_in = 1;
- scp->SCp.phase = -1;
- scp->SCp.sent_command = -1;
- scp->SCp.Status = GDTH_MAP_NONE;
- scp->SCp.buffer = (struct scatterlist *)NULL;
-
- hanum = NUMDATA(scp->device->host)->hanum;
+
+ cmndinfo = gdth_get_cmndinfo(ha);
+ BUG_ON(!cmndinfo);
+
+ scp->scsi_done = done;
+ gdth_update_timeout(scp, scp->timeout_per_command * 6);
+ cmndinfo->priority = DEFAULT_PRI;
+
+ gdth_set_bufflen(scp, scsi_bufflen(scp));
+ gdth_set_sg_count(scp, scsi_sg_count(scp));
+ gdth_set_sglist(scp, scsi_sglist(scp));
+
+ return __gdth_queuecommand(ha, scp, cmndinfo);
+}
+
+static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
+ struct gdth_cmndinfo *cmndinfo)
+{
+ scp->host_scribble = (unsigned char *)cmndinfo;
+ cmndinfo->wait_for_completion = 1;
+ cmndinfo->phase = -1;
+ cmndinfo->OpCode = -1;
+
#ifdef GDTH_STATISTICS
++act_ios;
#endif
- priority = DEFAULT_PRI;
- if (scp->done == gdth_scsi_done)
- priority = scp->SCp.this_residual;
- else
- gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
-
- gdth_putq( hanum, scp, priority );
- gdth_next( hanum );
+ gdth_putq(ha, scp, cmndinfo->priority);
+ gdth_next(ha);
return 0;
}
@@ -4959,12 +4062,10 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
static int gdth_open(struct inode *inode, struct file *filep)
{
gdth_ha_str *ha;
- int i;
- for (i = 0; i < gdth_ctr_count; i++) {
- ha = HADATA(gdth_ctr_tab[i]);
+ list_for_each_entry(ha, &gdth_instances, list) {
if (!ha->sdev)
- ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+ ha->sdev = scsi_get_host_dev(ha->shost);
}
TRACE(("gdth_open()\n"));
@@ -4983,10 +4084,11 @@ static int ioc_event(void __user *arg)
gdth_ha_str *ha;
ulong flags;
- if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) ||
- evt.ionode >= gdth_ctr_count)
+ if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)))
+ return -EFAULT;
+ ha = gdth_find_ha(evt.ionode);
+ if (!ha)
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[evt.ionode]);
if (evt.erase == 0xff) {
if (evt.event.event_source == ES_TEST)
@@ -5020,11 +4122,12 @@ static int ioc_lockdrv(void __user *arg)
ulong flags;
gdth_ha_str *ha;
- if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) ||
- ldrv.ionode >= gdth_ctr_count)
+ if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
-
+ ha = gdth_find_ha(ldrv.ionode);
+ if (!ha)
+ return -EFAULT;
+
for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
j = ldrv.drives[i];
if (j >= MAX_HDRIVES || !ha->hdr[j].present)
@@ -5033,14 +4136,14 @@ static int ioc_lockdrv(void __user *arg)
spin_lock_irqsave(&ha->smp_lock, flags);
ha->hdr[j].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j);
- gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j);
+ gdth_wait_completion(ha, ha->bus_cnt, j);
+ gdth_stop_timeout(ha, ha->bus_cnt, j);
} else {
spin_lock_irqsave(&ha->smp_lock, flags);
ha->hdr[j].lock = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j);
- gdth_next(ldrv.ionode);
+ gdth_start_timeout(ha, ha->bus_cnt, j);
+ gdth_next(ha);
}
}
return 0;
@@ -5050,16 +4153,16 @@ static int ioc_resetdrv(void __user *arg, char *cmnd)
{
gdth_ioctl_reset res;
gdth_cmd_str cmd;
- int hanum;
gdth_ha_str *ha;
int rval;
if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) ||
- res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+ res.number >= MAX_HDRIVES)
return -EFAULT;
- hanum = res.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
-
+ ha = gdth_find_ha(res.ionode);
+ if (!ha)
+ return -EFAULT;
+
if (!ha->hdr[res.number].present)
return 0;
memset(&cmd, 0, sizeof(gdth_cmd_str));
@@ -5085,22 +4188,21 @@ static int ioc_general(void __user *arg, char *cmnd)
gdth_ioctl_general gen;
char *buf = NULL;
ulong64 paddr;
- int hanum;
gdth_ha_str *ha;
int rval;
-
- if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) ||
- gen.ionode >= gdth_ctr_count)
+
+ if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)))
+ return -EFAULT;
+ ha = gdth_find_ha(gen.ionode);
+ if (!ha)
return -EFAULT;
- hanum = gen.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
if (gen.data_len + gen.sense_len != 0) {
- if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len,
+ if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len,
FALSE, &paddr)))
return -EFAULT;
if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),
gen.data_len + gen.sense_len)) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
@@ -5174,7 +4276,7 @@ static int ioc_general(void __user *arg, char *cmnd)
gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
}
} else {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
}
@@ -5186,15 +4288,15 @@ static int ioc_general(void __user *arg, char *cmnd)
if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf,
gen.data_len + gen.sense_len)) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
if (copy_to_user(arg, &gen,
sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return 0;
}
@@ -5204,7 +4306,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
gdth_cmd_str *cmd;
gdth_ha_str *ha;
unchar i;
- int hanum, rc = -ENOMEM;
+ int rc = -ENOMEM;
u32 cluster_type = 0;
rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
@@ -5213,12 +4315,10 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
goto free_fail;
if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
- rsc->ionode >= gdth_ctr_count) {
+ (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
rc = -EFAULT;
goto free_fail;
}
- hanum = rsc->ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
memset(cmd, 0, sizeof(gdth_cmd_str));
for (i = 0; i < MAX_HDRIVES; ++i) {
@@ -5259,7 +4359,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
gdth_cmd_str *cmd;
ushort i, status, hdr_cnt;
ulong32 info;
- int hanum, cyls, hds, secs;
+ int cyls, hds, secs;
int rc = -ENOMEM;
ulong flags;
gdth_ha_str *ha;
@@ -5270,12 +4370,10 @@ static int ioc_rescan(void __user *arg, char *cmnd)
goto free_fail;
if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
- rsc->ionode >= gdth_ctr_count) {
+ (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
rc = -EFAULT;
goto free_fail;
}
- hanum = rsc->ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
memset(cmd, 0, sizeof(gdth_cmd_str));
if (rsc->flag == 0) {
@@ -5432,9 +4530,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
gdth_ioctl_ctrtype ctrt;
if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) ||
- ctrt.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(ctrt.ionode))))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[ctrt.ionode]);
+
if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
ctrt.type = (unchar)((ha->stype>>20) - 0x10);
} else {
@@ -5473,10 +4571,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
unchar i, j;
if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) ||
- lchn.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(lchn.ionode))))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[lchn.ionode]);
-
+
i = lchn.channel;
if (i < ha->bus_cnt) {
if (lchn.lock) {
@@ -5484,16 +4581,16 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
ha->raw[i].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
for (j = 0; j < ha->tid_cnt; ++j) {
- gdth_wait_completion(lchn.ionode, i, j);
- gdth_stop_timeout(lchn.ionode, i, j);
+ gdth_wait_completion(ha, i, j);
+ gdth_stop_timeout(ha, i, j);
}
} else {
spin_lock_irqsave(&ha->smp_lock, flags);
ha->raw[i].lock = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
for (j = 0; j < ha->tid_cnt; ++j) {
- gdth_start_timeout(lchn.ionode, i, j);
- gdth_next(lchn.ionode);
+ gdth_start_timeout(ha, i, j);
+ gdth_next(ha);
}
}
}
@@ -5509,37 +4606,22 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
case GDTIOCTL_RESET_BUS:
{
gdth_ioctl_reset res;
- int hanum, rval;
+ int rval;
if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) ||
- res.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(res.ionode))))
return -EFAULT;
- hanum = res.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+ scp = kzalloc(sizeof(*scp), GFP_KERNEL);
if (!scp)
return -ENOMEM;
- memset(scp, 0, sizeof(*scp));
scp->device = ha->sdev;
scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->device->channel = virt_ctr ? 0 : res.number;
+ scp->device->channel = res.number;
rval = gdth_eh_bus_reset(scp);
res.status = (rval == SUCCESS ? S_OK : S_GENERR);
kfree(scp);
-#else
- scp = scsi_allocate_device(ha->sdev, 1, FALSE);
- if (!scp)
- return -ENOMEM;
- scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->channel = virt_ctr ? 0 : res.number;
- rval = gdth_eh_bus_reset(scp);
- res.status = (rval == SUCCESS ? S_OK : S_GENERR);
- scsi_release_command(scp);
-#endif
+
if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset)))
return -EFAULT;
break;
@@ -5556,16 +4638,14 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
/* flush routine */
-static void gdth_flush(int hanum)
+static void gdth_flush(gdth_ha_str *ha)
{
int i;
- gdth_ha_str *ha;
gdth_cmd_str gdtcmd;
char cmnd[MAX_COMMAND_SIZE];
memset(cmnd, 0xff, MAX_COMMAND_SIZE);
- TRACE2(("gdth_flush() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_flush() hanum %d\n", ha->hanum));
for (i = 0; i < MAX_HDRIVES; ++i) {
if (ha->hdr[i].present) {
@@ -5581,9 +4661,9 @@ static void gdth_flush(int hanum)
gdtcmd.u.cache.BlockNo = 1;
gdtcmd.u.cache.sg_canz = 0;
}
- TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+ TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i));
- gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 30, NULL);
+ gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL);
}
}
}
@@ -5591,7 +4671,7 @@ static void gdth_flush(int hanum)
/* shutdown routine */
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
{
- int hanum;
+ gdth_ha_str *ha;
#ifndef __alpha__
gdth_cmd_str gdtcmd;
char cmnd[MAX_COMMAND_SIZE];
@@ -5606,8 +4686,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
notifier_disabled = 1;
printk("GDT-HA: Flushing all host drives .. ");
- for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
- gdth_flush(hanum);
+ list_for_each_entry(ha, &gdth_instances, list) {
+ gdth_flush(ha);
#ifndef __alpha__
/* controller reset */
@@ -5615,8 +4695,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
gdtcmd.BoardNode = LOCALBOARD;
gdtcmd.Service = CACHESERVICE;
gdtcmd.OpCode = GDT_RESET;
- TRACE2(("gdth_halt(): reset controller %d\n", hanum));
- gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 10, NULL);
+ TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum));
+ gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL);
#endif
}
printk("Done.\n");
@@ -5627,7 +4707,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
return NOTIFY_OK;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
/* configure lun */
static int gdth_slave_configure(struct scsi_device *sdev)
{
@@ -5636,40 +4715,540 @@ static int gdth_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_8 = 1;
return 0;
}
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static struct scsi_host_template driver_template = {
-#else
-static Scsi_Host_Template driver_template = {
-#endif
- .proc_name = "gdth",
- .proc_info = gdth_proc_info,
+static struct scsi_host_template gdth_template = {
.name = "GDT SCSI Disk Array Controller",
- .detect = gdth_detect,
- .release = gdth_release,
.info = gdth_info,
.queuecommand = gdth_queuecommand,
.eh_bus_reset_handler = gdth_eh_bus_reset,
+ .slave_configure = gdth_slave_configure,
.bios_param = gdth_bios_param,
+ .proc_info = gdth_proc_info,
+ .proc_name = "gdth",
.can_queue = GDTH_MAXCMDS,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- .slave_configure = gdth_slave_configure,
-#endif
.this_id = -1,
.sg_tablesize = GDTH_MAXSG,
.cmd_per_lun = GDTH_MAXC_P_L,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- .use_new_eh_code = 1,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
- .highmem_io = 1,
+};
+
+#ifdef CONFIG_ISA
+static int gdth_isa_probe_one(ulong32 isa_bios)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ if (!gdth_search_isa(isa_bios))
+ return -ENXIO;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_isa(isa_bios,ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
+ isa_bios, ha->irq, ha->drq);
+
+ error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ if (error) {
+ printk("GDT-ISA: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ error = request_dma(ha->drq, "gdth");
+ if (error) {
+ printk("GDT-ISA: Unable to allocate DMA channel\n");
+ goto out_free_irq;
+ }
+
+ set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+ enable_dma(ha->drq);
+ shp->unchecked_isa_dma = 1;
+ shp->irq = ha->irq;
+ shp->dma_channel = ha->drq;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+ ha->pdev = NULL;
+
+ error = -ENOMEM;
+
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_dec_counters;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
#endif
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ error = -ENODEV;
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-ISA: Error during device scan\n");
+ goto out_free_coal_stat;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+ shp->max_cmd_len = 16;
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, NULL);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
#endif
-};
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_dec_counters:
+ gdth_ctr_count--;
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_EISA
+static int gdth_eisa_probe_one(ushort eisa_slot)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ if (!gdth_search_eisa(eisa_slot))
+ return -ENXIO;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_eisa(eisa_slot,ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+ eisa_slot >> 12, ha->irq);
+
+ error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ if (error) {
+ printk("GDT-EISA: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum));
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+
+ error = -ENOMEM;
+
+ ha->pdev = NULL;
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_free_irq;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+ ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb,
+ sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL);
+ if (!ha->ccb_phys)
+ goto out_free_coal_stat;
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-EISA: Error during device scan\n");
+ error = -ENODEV;
+ goto out_free_ccb_phys;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+ shp->max_cmd_len = 16;
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, NULL);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_ccb_phys:
+ pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str),
+ PCI_DMA_BIDIRECTIONAL);
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ gdth_ctr_count--;
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_PCI
+static int gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_pci(&pcistr[ctr],ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+ pcistr[ctr].pdev->bus->number,
+ PCI_SLOT(pcistr[ctr].pdev->devfn),
+ ha->irq);
+
+ error = request_irq(ha->irq, gdth_interrupt,
+ IRQF_DISABLED|IRQF_SHARED, "gdth", ha);
+ if (error) {
+ printk("GDT-PCI: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+
+ error = -ENOMEM;
+
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_free_irq;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ error = -ENODEV;
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-PCI %d: Error during device scan\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ /* 64-bit DMA only supported from FW >= x.43 */
+ if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) ||
+ !ha->dma64_support) {
+ if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "GDT-PCI %d: "
+ "Unable to set 32-bit DMA\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+ } else {
+ shp->max_cmd_len = 16;
+ if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
+ printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum);
+ } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "GDT-PCI %d: "
+ "Unable to set 64/32-bit DMA\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+ }
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, &pcistr[ctr].pdev->dev);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ gdth_ctr_count--;
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_PCI */
+
+static void gdth_remove_one(gdth_ha_str *ha)
+{
+ struct Scsi_Host *shp = ha->shost;
+
+ TRACE2(("gdth_remove_one()\n"));
+
+ scsi_remove_host(shp);
+
+ if (ha->sdev) {
+ scsi_free_host_dev(ha->sdev);
+ ha->sdev = NULL;
+ }
+
+ gdth_flush(ha);
+
+ if (shp->irq)
+ free_irq(shp->irq,ha);
+
+#ifdef CONFIG_ISA
+ if (shp->dma_channel != 0xff)
+ free_dma(shp->dma_channel);
+#endif
+#ifdef INT_COAL
+ if (ha->coal_stat)
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+ MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+ if (ha->pscratch)
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ if (ha->pmsg)
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ if (ha->ccb_phys)
+ pci_unmap_single(ha->pdev,ha->ccb_phys,
+ sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+
+ scsi_host_put(shp);
+}
+
+static int __init gdth_init(void)
+{
+ if (disable) {
+ printk("GDT-HA: Controller driver disabled from"
+ " command line !\n");
+ return 0;
+ }
+
+ printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",
+ GDTH_VERSION_STR);
+
+ /* initializations */
+ gdth_polling = TRUE;
+ gdth_clear_events();
+
+ /* As default we do not probe for EISA or ISA controllers */
+ if (probe_eisa_isa) {
+ /* scanning for controllers, at first: ISA controller */
+#ifdef CONFIG_ISA
+ ulong32 isa_bios;
+ for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL;
+ isa_bios += 0x8000UL)
+ gdth_isa_probe_one(isa_bios);
+#endif
+#ifdef CONFIG_EISA
+ {
+ ushort eisa_slot;
+ for (eisa_slot = 0x1000; eisa_slot <= 0x8000;
+ eisa_slot += 0x1000)
+ gdth_eisa_probe_one(eisa_slot);
+ }
+#endif
+ }
+
+#ifdef CONFIG_PCI
+ /* scanning for PCI controllers */
+ {
+ gdth_pci_str pcistr[MAXHA];
+ int cnt,ctr;
+
+ cnt = gdth_search_pci(pcistr);
+ printk("GDT-HA: Found %d PCI Storage RAID Controllers\n", cnt);
+ gdth_sort_pci(pcistr,cnt);
+ for (ctr = 0; ctr < cnt; ++ctr)
+ gdth_pci_probe_one(pcistr, ctr);
+ }
+#endif /* CONFIG_PCI */
+
+ TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count));
+
+ if (list_empty(&gdth_instances))
+ return -ENODEV;
+
+#ifdef GDTH_STATISTICS
+ TRACE2(("gdth_detect(): Initializing timer !\n"));
+ init_timer(&gdth_timer);
+ gdth_timer.expires = jiffies + HZ;
+ gdth_timer.data = 0L;
+ gdth_timer.function = gdth_timeout;
+ add_timer(&gdth_timer);
+#endif
+ major = register_chrdev(0,"gdth", &gdth_fops);
+ notifier_disabled = 0;
+ register_reboot_notifier(&gdth_notifier);
+ gdth_polling = FALSE;
+ return 0;
+}
+
+static void __exit gdth_exit(void)
+{
+ gdth_ha_str *ha;
+
+ list_for_each_entry(ha, &gdth_instances, list)
+ gdth_remove_one(ha);
+
+#ifdef GDTH_STATISTICS
+ del_timer(&gdth_timer);
+#endif
+ unregister_chrdev(major,"gdth");
+ unregister_reboot_notifier(&gdth_notifier);
+}
+
+module_init(gdth_init);
+module_exit(gdth_exit);
-#include "scsi_module.c"
#ifndef MODULE
__setup("gdth=", option_setup);
#endif
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 37423300592..1434c6b0297 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -13,7 +13,6 @@
* $Id: gdth.h,v 1.58 2006/01/11 16:14:09 achim Exp $
*/
-#include <linux/version.h>
#include <linux/types.h>
#ifndef TRUE
@@ -304,15 +303,8 @@
#define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */
#define EISAREG 0x0cc0 /* EISA configuration */
-/* DMA memory mappings */
-#define GDTH_MAP_NONE 0
-#define GDTH_MAP_SINGLE 1
-#define GDTH_MAP_SG 2
-#define GDTH_MAP_IOCTL 3
-
/* other defines */
#define LINUX_OS 8 /* used for cache optim. */
-#define SCATTER_GATHER 1 /* s/g feature */
#define SECS32 0x1f /* round capacity */
#define BIOS_ID_OFFS 0x10 /* offset contr-ID in ISABIOS */
#define LOCALBOARD 0 /* board node always 0 */
@@ -854,6 +846,9 @@ typedef struct {
/* controller information structure */
typedef struct {
+ struct Scsi_Host *shost;
+ struct list_head list;
+ ushort hanum;
ushort oem_id; /* OEM */
ushort type; /* controller class */
ulong32 stype; /* subtype (PCI: device ID) */
@@ -865,6 +860,7 @@ typedef struct {
void __iomem *brd; /* DPRAM address */
ulong32 brd_phys; /* slot number/BIOS address */
gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */
+ gdth_cmd_str cmdext;
gdth_cmd_str *pccb; /* address command structure */
ulong32 ccb_phys; /* phys. address */
#ifdef INT_COAL
@@ -916,6 +912,19 @@ typedef struct {
Scsi_Cmnd *cmnd; /* pending request */
ushort service; /* service */
} cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */
+ struct gdth_cmndinfo { /* per-command private info */
+ int index;
+ int internal_command; /* don't call scsi_done */
+ dma_addr_t sense_paddr; /* sense dma-addr */
+ unchar priority;
+ int timeout;
+ volatile int wait_for_completion;
+ ushort status;
+ ulong32 info;
+ enum dma_data_direction dma_dir;
+ int phase; /* ???? */
+ int OpCode;
+ } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */
unchar bus_cnt; /* SCSI bus count */
unchar tid_cnt; /* Target ID count */
unchar bus_id[MAXBUS]; /* IOP IDs */
@@ -938,19 +947,10 @@ typedef struct {
struct scsi_device *sdev;
} gdth_ha_str;
-/* structure for scsi_register(), SCSI bus != 0 */
-typedef struct {
- ushort hanum;
- ushort busnum;
-} gdth_num_str;
-
-/* structure for scsi_register() */
-typedef struct {
- gdth_num_str numext; /* must be the first element */
- gdth_ha_str haext;
- gdth_cmd_str cmdext;
-} gdth_ext_str;
-
+static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd)
+{
+ return (struct gdth_cmndinfo *)cmd->host_scribble;
+}
/* INQUIRY data format */
typedef struct {
diff --git a/drivers/scsi/gdth_kcompat.h b/drivers/scsi/gdth_kcompat.h
deleted file mode 100644
index 2a302eee669..00000000000
--- a/drivers/scsi/gdth_kcompat.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef IRQ_HANDLED
-typedef void irqreturn_t;
-#define IRQ_NONE
-#define IRQ_HANDLED
-#endif
-
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(x)
-#endif
-
-#ifndef __iomem
-#define __iomem
-#endif
-
-#ifndef __attribute_used__
-#define __attribute_used__ __devinitdata
-#endif
-
-#ifndef __user
-#define __user
-#endif
-
-#ifndef SERVICE_ACTION_IN
-#define SERVICE_ACTION_IN 0x9e
-#endif
-#ifndef READ_16
-#define READ_16 0x88
-#endif
-#ifndef WRITE_16
-#define WRITE_16 0x8a
-#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 32982eb75c8..de5773443c6 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -4,62 +4,32 @@
#include <linux/completion.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,
int inout)
{
- int hanum,busnum;
+ gdth_ha_str *ha = shost_priv(host);
TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
length,(int)offset,inout));
- hanum = NUMDATA(host)->hanum;
- busnum= NUMDATA(host)->busnum;
-
- if (inout)
- return(gdth_set_info(buffer,length,host,hanum,busnum));
- else
- return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
-}
-#else
-int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,
- int inout)
-{
- int hanum,busnum,i;
-
- TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
- length,(int)offset,inout));
-
- for (i = 0; i < gdth_ctr_vcount; ++i) {
- if (gdth_ctr_vtab[i]->host_no == hostno)
- break;
- }
- if (i == gdth_ctr_vcount)
- return(-EINVAL);
-
- hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
- busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
-
if (inout)
- return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
+ return(gdth_set_info(buffer,length,host,ha));
else
- return(gdth_get_info(buffer,start,offset,length,
- gdth_ctr_vtab[i],hanum,busnum));
+ return(gdth_get_info(buffer,start,offset,length,host,ha));
}
-#endif
static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- int hanum,int busnum)
+ gdth_ha_str *ha)
{
int ret_val = -EINVAL;
- TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+ TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
if (length >= 4) {
if (strncmp(buffer,"gdth",4) == 0) {
buffer += 5;
length -= 5;
- ret_val = gdth_set_asc_info(host, buffer, length, hanum);
+ ret_val = gdth_set_asc_info(host, buffer, length, ha);
}
}
@@ -67,11 +37,10 @@ static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
}
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
- int length,int hanum)
+ int length, gdth_ha_str *ha)
{
int orig_length, drive, wb_mode;
int i, found;
- gdth_ha_str *ha;
gdth_cmd_str gdtcmd;
gdth_cpar_str *pcpar;
ulong64 paddr;
@@ -80,8 +49,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
memset(cmnd, 0xff, 12);
memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
- TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
orig_length = length + 5;
drive = -1;
wb_mode = 0;
@@ -157,7 +125,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
}
if (wb_mode) {
- if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
+ if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr))
return(-EBUSY);
pcpar = (gdth_cpar_str *)ha->pscratch;
memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
@@ -171,7 +139,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
- gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr);
printk("Done.\n");
return(orig_length);
}
@@ -181,11 +149,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
}
static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host,int hanum,int busnum)
+ struct Scsi_Host *host, gdth_ha_str *ha)
{
int size = 0,len = 0;
off_t begin = 0,pos = 0;
- gdth_ha_str *ha;
int id, i, j, k, sec, flag;
int no_mdrv = 0, drv_no, is_mirr;
ulong32 cnt;
@@ -214,8 +181,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
memset(cmnd, 0xff, 12);
memset(gdtcmd, 0, sizeof(gdth_cmd_str));
- TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
/* request is i.e. "cat /proc/scsi/gdth/0" */
@@ -245,13 +211,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
/* controller information */
size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
len += size; pos = begin + len;
- if (virt_ctr)
- sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
- else
- strcpy(hrec, ha->binfo.type_string);
+ strcpy(hrec, ha->binfo.type_string);
size = sprintf(buffer+len,
" Number: \t%d \tName: \t%s\n",
- hanum, hrec);
+ ha->hanum, hrec);
len += size; pos = begin + len;
if (ha->more_proc)
@@ -301,7 +264,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < ha->bus_cnt; ++i) {
@@ -404,7 +367,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
goto stop_output;
}
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -416,7 +379,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -510,7 +473,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
if (pos > offset + length)
goto stop_output;
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -522,7 +485,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -581,7 +544,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
goto stop_output;
}
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -593,7 +556,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -626,7 +589,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
}
}
}
- gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
+ gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr);
for (i = 0; i < MAX_HDRIVES; ++i) {
if (!(ha->hdr[i].present))
@@ -664,7 +627,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
id = gdth_read_event(ha, id, estr);
if (estr->event_source == 0)
break;
- if (estr->event_data.eu.driver.ionode == hanum &&
+ if (estr->event_data.eu.driver.ionode == ha->hanum &&
estr->event_source == ES_ASYNC) {
gdth_log_event(&estr->event_data, hrec);
do_gettimeofday(&tv);
@@ -699,17 +662,15 @@ free_fail:
return rc;
}
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
ulong64 *paddr)
{
- gdth_ha_str *ha;
ulong flags;
char *ret_val;
if (size == 0)
return NULL;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
@@ -729,12 +690,10 @@ static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
return ret_val;
}
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
{
- gdth_ha_str *ha;
ulong flags;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
if (buf == ha->pscratch) {
@@ -747,13 +706,11 @@ static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
}
#ifdef GDTH_IOCTL_PROC
-static int gdth_ioctl_check_bin(int hanum, ushort size)
+static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size)
{
- gdth_ha_str *ha;
ulong flags;
int ret_val;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
ret_val = FALSE;
@@ -766,27 +723,27 @@ static int gdth_ioctl_check_bin(int hanum, ushort size)
}
#endif
-static void gdth_wait_completion(int hanum, int busnum, int id)
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
int i;
Scsi_Cmnd *scp;
+ struct gdth_cmndinfo *cmndinfo;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (i = 0; i < GDTH_MAXCMDS; ++i) {
scp = ha->cmd_tab[i].cmnd;
+ cmndinfo = gdth_cmnd_priv(scp);
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ b = scp->device->channel;
t = scp->device->id;
if (!SPECIAL_SCP(scp) && t == (unchar)id &&
b == (unchar)busnum) {
- scp->SCp.have_data_in = 0;
+ cmndinfo->wait_for_completion = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- while (!scp->SCp.have_data_in)
+ while (!cmndinfo->wait_for_completion)
barrier();
spin_lock_irqsave(&ha->smp_lock, flags);
}
@@ -794,55 +751,51 @@ static void gdth_wait_completion(int hanum, int busnum, int id)
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static void gdth_stop_timeout(int hanum, int busnum, int id)
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
Scsi_Cmnd *scp;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- if (scp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ if (!cmndinfo->internal_command) {
+ b = scp->device->channel;
t = scp->device->id;
if (t == (unchar)id && b == (unchar)busnum) {
TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
- scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+ cmndinfo->timeout = gdth_update_timeout(scp, 0);
}
}
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static void gdth_start_timeout(int hanum, int busnum, int id)
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
Scsi_Cmnd *scp;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- if (scp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ if (!cmndinfo->internal_command) {
+ b = scp->device->channel;
t = scp->device->id;
if (t == (unchar)id && b == (unchar)busnum) {
TRACE2(("gdth_start_timeout(): update_timeout()\n"));
- gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
+ gdth_update_timeout(scp, cmndinfo->timeout);
}
}
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
{
int oldto;
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index a679eeb6820..45e6fdacf36 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -9,20 +9,20 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info);
static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- int hanum,int busnum);
+ gdth_ha_str *ha);
static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host,int hanum,int busnum);
+ struct Scsi_Host *host, gdth_ha_str *ha);
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
- int length, int hanum);
+ int length, gdth_ha_str *ha);
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
- ulong64 *paddr);
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
-static void gdth_wait_completion(int hanum, int busnum, int id);
-static void gdth_stop_timeout(int hanum, int busnum, int id);
-static void gdth_start_timeout(int hanum, int busnum, int id);
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
+ ulong64 *paddr);
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr);
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id);
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id);
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id);
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
#endif
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 96bc31266c9..adc9559cb6f 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -342,6 +342,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering;
shost->ordered_tag = sht->ordered_tag;
+ shost->active_mode = sht->supported_mode;
if (sht->max_host_blocked)
shost->max_host_blocked = sht->max_host_blocked;
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 0e579ca4581..8b384fa7f04 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
-static const char driver_ver[] = "v1.0 (060426)";
+static const char driver_ver[] = "v1.2 (070830)";
static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
@@ -76,7 +76,7 @@ static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
{
- if ((tag & IOPMU_QUEUE_MASK_HOST_BITS) == IOPMU_QUEUE_ADDR_HOST_BIT)
+ if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
return hptiop_host_request_callback(hba,
tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
else
@@ -323,12 +323,22 @@ static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
hba->req_list = req;
}
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag)
+static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
{
struct hpt_iop_request_scsi_command *req;
struct scsi_cmnd *scp;
+ u32 tag;
+
+ if (hba->iopintf_v2) {
+ tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
+ req = hba->reqs[tag].req_virt;
+ if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+ req->header.result = IOP_RESULT_SUCCESS;
+ } else {
+ tag = _tag;
+ req = hba->reqs[tag].req_virt;
+ }
- req = (struct hpt_iop_request_scsi_command *)hba->reqs[tag].req_virt;
dprintk("hptiop_host_request_callback: req=%p, type=%d, "
"result=%d, context=0x%x tag=%d\n",
req, req->header.type, req->header.result,
@@ -497,7 +507,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
goto cmd_done;
}
- req = (struct hpt_iop_request_scsi_command *)_req->req_virt;
+ req = _req->req_virt;
/* build S/G table */
sg_count = hptiop_buildsgl(scp, req->sg_list);
@@ -521,8 +531,19 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
- writel(IOPMU_QUEUE_ADDR_HOST_BIT | _req->req_shifted_phy,
- &hba->iop->inbound_queue);
+ if (hba->iopintf_v2) {
+ u32 size_bits;
+ if (req->header.size < 256)
+ size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+ else if (req->header.size < 512)
+ size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+ else
+ size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+ IOPMU_QUEUE_ADDR_HOST_BIT;
+ writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
+ } else
+ writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+ &hba->iop->inbound_queue);
return 0;
@@ -688,6 +709,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
hba->pcidev = pcidev;
hba->host = host;
hba->initialized = 0;
+ hba->iopintf_v2 = 0;
atomic_set(&hba->resetting, 0);
atomic_set(&hba->reset_count, 0);
@@ -722,8 +744,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
hba->max_request_size = le32_to_cpu(iop_config.request_size);
hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
+ hba->interface_version = le32_to_cpu(iop_config.interface_version);
hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
+ if (hba->firmware_version > 0x01020000 ||
+ hba->interface_version > 0x01020000)
+ hba->iopintf_v2 = 1;
+
host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
host->max_id = le32_to_cpu(iop_config.max_devices);
host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
@@ -731,8 +758,15 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
host->max_cmd_len = 16;
- set_config.vbus_id = cpu_to_le32(host->host_no);
+ req_size = sizeof(struct hpt_iop_request_scsi_command)
+ + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
+ if ((req_size & 0x1f) != 0)
+ req_size = (req_size + 0x1f) & ~0x1f;
+
+ memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
set_config.iop_id = cpu_to_le32(host->host_no);
+ set_config.vbus_id = cpu_to_le16(host->host_no);
+ set_config.max_host_request_size = cpu_to_le16(req_size);
if (iop_set_config(hba, &set_config)) {
printk(KERN_ERR "scsi%d: set config failed\n",
@@ -750,10 +784,6 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
}
/* Allocate request mem */
- req_size = sizeof(struct hpt_iop_request_scsi_command)
- + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
- if ((req_size& 0x1f) != 0)
- req_size = (req_size + 0x1f) & ~0x1f;
dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
@@ -879,8 +909,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
}
static struct pci_device_id hptiop_id_table[] = {
- { PCI_DEVICE(0x1103, 0x3220) },
- { PCI_DEVICE(0x1103, 0x3320) },
+ { PCI_VDEVICE(TTI, 0x3220) },
+ { PCI_VDEVICE(TTI, 0x3320) },
+ { PCI_VDEVICE(TTI, 0x3520) },
+ { PCI_VDEVICE(TTI, 0x4320) },
{},
};
@@ -910,3 +942,4 @@ module_init(hptiop_module_init);
module_exit(hptiop_module_exit);
MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index f04f7e81d1a..2a5e46e001c 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,219 +18,6 @@
#ifndef _HPTIOP_H_
#define _HPTIOP_H_
-/*
- * logical device type.
- * Identify array (logical device) and physical device.
- */
-#define LDT_ARRAY 1
-#define LDT_DEVICE 2
-
-/*
- * Array types
- */
-#define AT_UNKNOWN 0
-#define AT_RAID0 1
-#define AT_RAID1 2
-#define AT_RAID5 3
-#define AT_RAID6 4
-#define AT_JBOD 7
-
-#define MAX_NAME_LENGTH 36
-#define MAX_ARRAYNAME_LEN 16
-
-#define MAX_ARRAY_MEMBERS_V1 8
-#define MAX_ARRAY_MEMBERS_V2 16
-
-/* keep definition for source code compatiblity */
-#define MAX_ARRAY_MEMBERS MAX_ARRAY_MEMBERS_V1
-
-/*
- * array flags
- */
-#define ARRAY_FLAG_DISABLED 0x00000001 /* The array is disabled */
-#define ARRAY_FLAG_NEEDBUILDING 0x00000002 /* need to be rebuilt */
-#define ARRAY_FLAG_REBUILDING 0x00000004 /* in rebuilding process */
-#define ARRAY_FLAG_BROKEN 0x00000008 /* broken but still working */
-#define ARRAY_FLAG_BOOTDISK 0x00000010 /* has a active partition */
-#define ARRAY_FLAG_BOOTMARK 0x00000040 /* array has boot mark set */
-#define ARRAY_FLAG_NEED_AUTOREBUILD 0x00000080 /* auto-rebuild should start */
-#define ARRAY_FLAG_VERIFYING 0x00000100 /* is being verified */
-#define ARRAY_FLAG_INITIALIZING 0x00000200 /* is being initialized */
-#define ARRAY_FLAG_TRANSFORMING 0x00000400 /* tranform in progress */
-#define ARRAY_FLAG_NEEDTRANSFORM 0x00000800 /* array need tranform */
-#define ARRAY_FLAG_NEEDINITIALIZING 0x00001000 /* initialization not done */
-#define ARRAY_FLAG_BROKEN_REDUNDANT 0x00002000 /* broken but redundant */
-
-/*
- * device flags
- */
-#define DEVICE_FLAG_DISABLED 0x00000001 /* device is disabled */
-#define DEVICE_FLAG_UNINITIALIZED 0x00010000 /* device is not initialized */
-#define DEVICE_FLAG_LEGACY 0x00020000 /* lagacy drive */
-#define DEVICE_FLAG_IS_SPARE 0x80000000 /* is a spare disk */
-
-/*
- * ioctl codes
- */
-#define HPT_CTL_CODE(x) (x+0xFF00)
-#define HPT_CTL_CODE_LINUX_TO_IOP(x) ((x)-0xff00)
-
-#define HPT_IOCTL_GET_CONTROLLER_INFO HPT_CTL_CODE(2)
-#define HPT_IOCTL_GET_CHANNEL_INFO HPT_CTL_CODE(3)
-#define HPT_IOCTL_GET_LOGICAL_DEVICES HPT_CTL_CODE(4)
-#define HPT_IOCTL_GET_DRIVER_CAPABILITIES HPT_CTL_CODE(19)
-#define HPT_IOCTL_GET_DEVICE_INFO_V3 HPT_CTL_CODE(46)
-#define HPT_IOCTL_GET_CONTROLLER_INFO_V2 HPT_CTL_CODE(47)
-
-/*
- * Controller information.
- */
-struct hpt_controller_info {
- u8 chip_type; /* chip type */
- u8 interrupt_level; /* IRQ level */
- u8 num_buses; /* bus count */
- u8 chip_flags;
-
- u8 product_id[MAX_NAME_LENGTH];/* product name */
- u8 vendor_id[MAX_NAME_LENGTH]; /* vendor name */
-}
-__attribute__((packed));
-
-/*
- * Channel information.
- */
-struct hpt_channel_info {
- __le32 io_port; /* IDE Base Port Address */
- __le32 control_port; /* IDE Control Port Address */
- __le32 devices[2]; /* device connected to this channel */
-}
-__attribute__((packed));
-
-/*
- * Array information.
- */
-struct hpt_array_info_v3 {
- u8 name[MAX_ARRAYNAME_LEN]; /* array name */
- u8 description[64]; /* array description */
- u8 create_manager[16]; /* who created it */
- __le32 create_time; /* when created it */
-
- u8 array_type; /* array type */
- u8 block_size_shift; /* stripe size */
- u8 ndisk; /* Number of ID in Members[] */
- u8 reserved;
-
- __le32 flags; /* working flags, see ARRAY_FLAG_XXX */
- __le32 members[MAX_ARRAY_MEMBERS_V2]; /* member array/disks */
-
- __le32 rebuilding_progress;
- __le64 rebuilt_sectors; /* rebuilding point (LBA) for single member */
-
- __le32 transform_source;
- __le32 transform_target; /* destination device ID */
- __le32 transforming_progress;
- __le32 signature; /* persistent identification*/
- __le16 critical_members; /* bit mask of critical members */
- __le16 reserve2;
- __le32 reserve;
-}
-__attribute__((packed));
-
-/*
- * physical device information.
- */
-#define MAX_PARENTS_PER_DISK 8
-
-struct hpt_device_info_v2 {
- u8 ctlr_id; /* controller id */
- u8 path_id; /* bus */
- u8 target_id; /* id */
- u8 device_mode_setting; /* Current Data Transfer mode: 0-4 PIO0-4 */
- /* 5-7 MW DMA0-2, 8-13 UDMA0-5 */
- u8 device_type; /* device type */
- u8 usable_mode; /* highest usable mode */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u8 NCQ_enabled: 1;
- u8 NCQ_supported: 1;
- u8 TCQ_enabled: 1;
- u8 TCQ_supported: 1;
- u8 write_cache_enabled: 1;
- u8 write_cache_supported: 1;
- u8 read_ahead_enabled: 1;
- u8 read_ahead_supported: 1;
- u8 reserved6: 6;
- u8 spin_up_mode: 2;
-#else
- u8 read_ahead_supported: 1;
- u8 read_ahead_enabled: 1;
- u8 write_cache_supported: 1;
- u8 write_cache_enabled: 1;
- u8 TCQ_supported: 1;
- u8 TCQ_enabled: 1;
- u8 NCQ_supported: 1;
- u8 NCQ_enabled: 1;
- u8 spin_up_mode: 2;
- u8 reserved6: 6;
-#endif
-
- __le32 flags; /* working flags, see DEVICE_FLAG_XXX */
- u8 ident[150]; /* (partitial) Identify Data of this device */
-
- __le64 total_free;
- __le64 max_free;
- __le64 bad_sectors;
- __le32 parent_arrays[MAX_PARENTS_PER_DISK];
-}
-__attribute__((packed));
-
-/*
- * Logical device information.
- */
-#define INVALID_TARGET_ID 0xFF
-#define INVALID_BUS_ID 0xFF
-
-struct hpt_logical_device_info_v3 {
- u8 type; /* LDT_ARRAY or LDT_DEVICE */
- u8 cache_policy; /* refer to CACHE_POLICY_xxx */
- u8 vbus_id; /* vbus sequence in vbus_list */
- u8 target_id; /* OS target id. 0xFF is invalid */
- /* OS name: DISK $VBusId_$TargetId */
- __le64 capacity; /* array capacity */
- __le32 parent_array; /* don't use this field for physical
- device. use ParentArrays field in
- hpt_device_info_v2 */
- /* reserved statistic fields */
- __le32 stat1;
- __le32 stat2;
- __le32 stat3;
- __le32 stat4;
-
- union {
- struct hpt_array_info_v3 array;
- struct hpt_device_info_v2 device;
- } __attribute__((packed)) u;
-
-}
-__attribute__((packed));
-
-/*
- * ioctl structure
- */
-#define HPT_IOCTL_MAGIC 0xA1B2C3D4
-
-struct hpt_ioctl_u {
- u32 magic; /* used to check if it's a valid ioctl packet */
- u32 ioctl_code; /* operation control code */
- void __user *inbuf; /* input data buffer */
- u32 inbuf_size; /* size of input data buffer */
- void __user *outbuf; /* output data buffer */
- u32 outbuf_size; /* size of output data buffer */
- void __user *bytes_returned; /* count of bytes returned */
-}
-__attribute__((packed));
-
-
struct hpt_iopmu
{
__le32 resrved0[4];
@@ -252,6 +39,8 @@ struct hpt_iopmu
#define IOPMU_QUEUE_EMPTY 0xffffffff
#define IOPMU_QUEUE_MASK_HOST_BITS 0xf0000000
#define IOPMU_QUEUE_ADDR_HOST_BIT 0x80000000
+#define IOPMU_QUEUE_REQUEST_SIZE_BIT 0x40000000
+#define IOPMU_QUEUE_REQUEST_RESULT_BIT 0x40000000
#define IOPMU_OUTBOUND_INT_MSG0 1
#define IOPMU_OUTBOUND_INT_MSG1 2
@@ -336,7 +125,8 @@ struct hpt_iop_request_set_config
{
struct hpt_iop_request_header header;
__le32 iop_id;
- __le32 vbus_id;
+ __le16 vbus_id;
+ __le16 max_host_request_size;
__le32 reserve[6];
};
@@ -412,9 +202,8 @@ struct hptiop_hba {
struct Scsi_Host * host;
struct pci_dev * pcidev;
- struct list_head link;
-
/* IOP config info */
+ u32 interface_version;
u32 firmware_version;
u32 sdram_size;
u32 max_devices;
@@ -423,8 +212,10 @@ struct hptiop_hba {
u32 max_sg_descriptors;
u32 req_size; /* host-allocated request buffer size */
- int initialized;
- int msg_done;
+
+ int iopintf_v2: 1;
+ int initialized: 1;
+ int msg_done: 1;
struct hptiop_request * req_list;
struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 4275d1b04ce..1a924e9b027 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -460,13 +460,6 @@ module_param(boot_options, charp, 0);
module_param_array(io_port, int, NULL, 0);
module_param_array(scsi_id, int, NULL, 0);
-#if 0 /* FIXME: No longer exist? --RR */
-MODULE_PARM(display, "1i");
-MODULE_PARM(adisplay, "1i");
-MODULE_PARM(normal, "1i");
-MODULE_PARM(ansi, "1i");
-#endif
-
MODULE_LICENSE("GPL");
#endif
/*counter of concurrent disk read/writes, to turn on/off disk led */
@@ -1693,6 +1686,7 @@ static int __devexit ibmmca_remove(struct device *dev)
scsi_remove_host(shpnt);
release_region(shpnt->io_port, shpnt->n_io_port);
free_irq(shpnt->irq, dev);
+ scsi_host_put(shpnt);
return 0;
}
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index f67d9efc7a9..6ac0633d545 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,9 +1,7 @@
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
-ifndef CONFIG_PPC_PSERIES
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
-endif
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5ecc63d1b43..cda0cc3d182 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -70,11 +70,13 @@
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <asm/firmware.h>
#include <asm/vio.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_srp.h>
#include "ibmvscsi.h"
/* The values below are somewhat arbitrary default values, but
@@ -87,8 +89,12 @@ static int max_channel = 3;
static int init_timeout = 5;
static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
+static struct scsi_transport_template *ibmvscsi_transport_template;
+
#define IBMVSCSI_VERSION "1.5.8"
+static struct ibmvscsi_ops *ibmvscsi_ops;
+
MODULE_DESCRIPTION("IBM Virtual SCSI");
MODULE_AUTHOR("Dave Boutcher");
MODULE_LICENSE("GPL");
@@ -506,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
- (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+ if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
(vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
atomic_set(&hostdata->request_limit, -1);
dev_err(hostdata->dev, "error after reset\n");
@@ -612,7 +618,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
}
if ((rc =
- ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+ ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
list_del(&evt_struct->list);
del_timer(&evt_struct->timer);
@@ -1211,8 +1217,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
case 0x01: /* Initialization message */
dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
- if ((rc = ibmvscsi_send_crq(hostdata,
- 0xC002000000000000LL, 0)) == 0) {
+ if ((rc = ibmvscsi_ops->send_crq(hostdata,
+ 0xC002000000000000LL, 0)) == 0) {
/* Now login */
send_srp_login(hostdata);
} else {
@@ -1237,10 +1243,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
purge_requests(hostdata, DID_REQUEUE);
- if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
+ if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
dev_err(hostdata->dev, "error after enable\n");
@@ -1250,10 +1256,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
crq->format);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
+ if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
dev_err(hostdata->dev, "error after reset\n");
@@ -1553,6 +1559,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct ibmvscsi_host_data *hostdata;
struct Scsi_Host *host;
struct device *dev = &vdev->dev;
+ struct srp_rport_identifiers ids;
+ struct srp_rport *rport;
unsigned long wait_switch = 0;
int rc;
@@ -1565,6 +1573,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto scsi_host_alloc_failed;
}
+ host->transportt = ibmvscsi_transport_template;
hostdata = shost_priv(host);
memset(hostdata, 0x00, sizeof(*hostdata));
INIT_LIST_HEAD(&hostdata->sent);
@@ -1573,7 +1582,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
atomic_set(&hostdata->request_limit, -1);
hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
- rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+ rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
if (rc != 0 && rc != H_RESOURCE) {
dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
goto init_crq_failed;
@@ -1590,11 +1599,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
if (scsi_add_host(hostdata->host, hostdata->dev))
goto add_host_failed;
+ /* we don't have a proper target_port_id so let's use the fake one */
+ memcpy(ids.port_id, hostdata->madapter_info.partition_name,
+ sizeof(ids.port_id));
+ ids.roles = SRP_RPORT_ROLE_TARGET;
+ rport = srp_rport_add(host, &ids);
+ if (IS_ERR(rport))
+ goto add_srp_port_failed;
+
/* Try to send an initialization message. Note that this is allowed
* to fail if the other end is not acive. In that case we don't
* want to scan
*/
- if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+ if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
|| rc == H_RESOURCE) {
/*
* Wait around max init_timeout secs for the adapter to finish
@@ -1617,10 +1634,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = hostdata;
return 0;
+ add_srp_port_failed:
+ scsi_remove_host(hostdata->host);
add_host_failed:
release_event_pool(&hostdata->pool, hostdata);
init_pool_failed:
- ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
init_crq_failed:
scsi_host_put(host);
scsi_host_alloc_failed:
@@ -1631,9 +1650,10 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
{
struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
release_event_pool(&hostdata->pool, hostdata);
- ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
- max_requests);
-
+ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
+ max_requests);
+
+ srp_remove_host(hostdata->host);
scsi_remove_host(hostdata->host);
scsi_host_put(hostdata->host);
@@ -1660,14 +1680,35 @@ static struct vio_driver ibmvscsi_driver = {
}
};
+static struct srp_function_template ibmvscsi_transport_functions = {
+};
+
int __init ibmvscsi_module_init(void)
{
- return vio_register_driver(&ibmvscsi_driver);
+ int ret;
+
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ ibmvscsi_ops = &iseriesvscsi_ops;
+ else if (firmware_has_feature(FW_FEATURE_VIO))
+ ibmvscsi_ops = &rpavscsi_ops;
+ else
+ return -ENODEV;
+
+ ibmvscsi_transport_template =
+ srp_attach_transport(&ibmvscsi_transport_functions);
+ if (!ibmvscsi_transport_template)
+ return -ENOMEM;
+
+ ret = vio_register_driver(&ibmvscsi_driver);
+ if (ret)
+ srp_release_transport(ibmvscsi_transport_template);
+ return ret;
}
void __exit ibmvscsi_module_exit(void)
{
vio_unregister_driver(&ibmvscsi_driver);
+ srp_release_transport(ibmvscsi_transport_template);
}
module_init(ibmvscsi_module_init);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index b19c2e26c2a..46e850e302c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -98,21 +98,25 @@ struct ibmvscsi_host_data {
};
/* routines for managing a command/response queue */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests);
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests);
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata);
-
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata);
-
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct ibmvscsi_host_data *hostdata);
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
- u64 word1, u64 word2);
+
+struct ibmvscsi_ops {
+ int (*init_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests);
+ void (*release_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests);
+ int (*reset_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata);
+ int (*reenable_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata);
+ int (*send_crq)(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2);
+};
+
+extern struct ibmvscsi_ops iseriesvscsi_ops;
+extern struct ibmvscsi_ops rpavscsi_ops;
#endif /* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 8ba7dd09d01..82bcab688b4 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_srp.h>
#include <scsi/scsi_tgt.h>
#include <scsi/libsrp.h>
#include <asm/hvcall.h>
@@ -68,9 +69,12 @@ struct vio_port {
unsigned long liobn;
unsigned long riobn;
struct srp_target *target;
+
+ struct srp_rport *rport;
};
static struct workqueue_struct *vtgtd;
+static struct scsi_transport_template *ibmvstgt_transport_template;
/*
* These are fixed for the system and come from the Open Firmware device tree.
@@ -188,6 +192,7 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
static void handle_cmd_queue(struct srp_target *target)
{
struct Scsi_Host *shost = target->shost;
+ struct srp_rport *rport = target_to_port(target)->rport;
struct iu_entry *iue;
struct srp_cmd *cmd;
unsigned long flags;
@@ -200,7 +205,8 @@ retry:
if (!test_and_set_bit(V_FLYING, &iue->flags)) {
spin_unlock_irqrestore(&target->lock, flags);
cmd = iue->sbuf->buf;
- err = srp_cmd_queue(shost, cmd, iue, 0);
+ err = srp_cmd_queue(shost, cmd, iue,
+ (unsigned long)rport, 0);
if (err) {
eprintk("cannot queue cmd %p %d\n", cmd, err);
srp_iu_put(iue);
@@ -359,6 +365,16 @@ static void process_login(struct iu_entry *iue)
union viosrp_iu *iu = vio_iu(iue);
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
uint64_t tag = iu->srp.rsp.tag;
+ struct Scsi_Host *shost = iue->target->shost;
+ struct srp_target *target = host_to_srp_target(shost);
+ struct vio_port *vport = target_to_port(target);
+ struct srp_rport_identifiers ids;
+
+ memset(&ids, 0, sizeof(ids));
+ sprintf(ids.port_id, "%x", vport->dma_dev->unit_address);
+ ids.roles = SRP_RPORT_ROLE_INITIATOR;
+ if (!vport->rport)
+ vport->rport = srp_rport_add(shost, &ids);
/* TODO handle case that requested size is wrong and
* buffer format is wrong
@@ -412,7 +428,9 @@ static int process_tsk_mgmt(struct iu_entry *iue)
fn = 0;
}
if (fn)
- scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
+ scsi_tgt_tsk_mgmt_request(iue->target->shost,
+ (unsigned long)iue->target->shost,
+ fn,
iu->srp.tsk_mgmt.task_tag,
(struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
iue);
@@ -721,7 +739,8 @@ static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
return 0;
}
-static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
+static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost,
+ u64 itn_id, u64 mid, int result)
{
struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
union viosrp_iu *iu = vio_iu(iue);
@@ -747,6 +766,20 @@ static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
return 0;
}
+static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id,
+ int result)
+{
+ struct srp_target *target = host_to_srp_target(shost);
+ struct vio_port *vport = target_to_port(target);
+
+ if (result) {
+ eprintk("%p %d\n", shost, result);
+ srp_rport_del(vport->rport);
+ vport->rport = NULL;
+ }
+ return 0;
+}
+
static ssize_t system_id_show(struct class_device *cdev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
@@ -785,9 +818,9 @@ static struct scsi_host_template ibmvstgt_sht = {
.max_sectors = DEFAULT_MAX_SECTORS,
.transfer_response = ibmvstgt_cmd_done,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
- .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.shost_attrs = ibmvstgt_attrs,
.proc_name = TGT_NAME,
+ .supported_mode = MODE_TARGET,
};
static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
@@ -804,6 +837,7 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
if (!shost)
goto free_vport;
+ shost->transportt = ibmvstgt_transport_template;
err = scsi_tgt_alloc_queue(shost);
if (err)
goto put_host;
@@ -837,8 +871,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
err = scsi_add_host(shost, target->dev);
if (err)
goto destroy_queue;
- return 0;
+ return 0;
destroy_queue:
crq_queue_destroy(target);
free_srp_target:
@@ -857,6 +891,7 @@ static int ibmvstgt_remove(struct vio_dev *dev)
struct vio_port *vport = target->ldata;
crq_queue_destroy(target);
+ srp_remove_host(shost);
scsi_remove_host(shost);
scsi_tgt_free_queue(shost);
srp_target_free(target);
@@ -909,15 +944,25 @@ static int get_system_info(void)
return 0;
}
+static struct srp_function_template ibmvstgt_transport_functions = {
+ .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
+ .it_nexus_response = ibmvstgt_it_nexus_response,
+};
+
static int ibmvstgt_init(void)
{
int err = -ENOMEM;
printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
+ ibmvstgt_transport_template =
+ srp_attach_transport(&ibmvstgt_transport_functions);
+ if (!ibmvstgt_transport_template)
+ return err;
+
vtgtd = create_workqueue("ibmvtgtd");
if (!vtgtd)
- return err;
+ goto release_transport;
err = get_system_info();
if (err)
@@ -928,9 +973,10 @@ static int ibmvstgt_init(void)
goto destroy_wq;
return 0;
-
destroy_wq:
destroy_workqueue(vtgtd);
+release_transport:
+ srp_release_transport(ibmvstgt_transport_template);
return err;
}
@@ -940,6 +986,7 @@ static void ibmvstgt_exit(void)
destroy_workqueue(vtgtd);
vio_unregister_driver(&ibmvstgt_driver);
+ srp_release_transport(ibmvstgt_transport_template);
}
MODULE_DESCRIPTION("IBM Virtual SCSI Target");
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
index 6aeb5f003c3..0775fdee5fa 100644
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -53,7 +53,7 @@ struct srp_lp_event {
/**
* standard interface for handling logical partition events.
*/
-static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
{
struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
@@ -74,9 +74,9 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
/* ------------------------------------------------------------
* Routines for driver initialization
*/
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
int rc;
@@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
goto viopath_open_failed;
}
- rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+ rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
if (rc < 0) {
printk("vio_setHandler failed with rc %d in open_event_path\n",
rc);
@@ -102,9 +102,9 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
return -1;
}
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
vio_clearHandler(viomajorsubtype_scsi);
viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
@@ -117,8 +117,8 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
*
* no-op for iSeries
*/
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
return 0;
}
@@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
*
* no-op for iSeries
*/
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
return 0;
}
/**
- * ibmvscsi_send_crq: - Send a CRQ
+ * iseriesvscsi_send_crq: - Send a CRQ
* @hostdata: the adapter
* @word1: the first 64 bits of the data
* @word2: the second 64 bits of the data
*/
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2)
{
single_host_data = hostdata;
return HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
VIOVERSION << 16, word1, word2, 0,
0);
}
+
+struct ibmvscsi_ops iseriesvscsi_ops = {
+ .init_crq_queue = iseriesvscsi_init_crq_queue,
+ .release_crq_queue = iseriesvscsi_release_crq_queue,
+ .reset_crq_queue = iseriesvscsi_reset_crq_queue,
+ .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
+ .send_crq = iseriesvscsi_send_crq,
+};
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 9c14e789df5..182146100dc 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -42,14 +42,14 @@ static unsigned int partition_number = -1;
* Routines for managing the command/response queue
*/
/**
- * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * rpavscsi_handle_event: - Interrupt handler for crq events
* @irq: number of irq to handle, not used
* @dev_instance: ibmvscsi_host_data of host that received interrupt
*
* Disables interrupts and schedules srp_task
* Always returns IRQ_HANDLED
*/
-static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
+static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance)
{
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)dev_instance;
@@ -66,9 +66,9 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
* Frees irq, deallocates a page for messages, unmaps dma, and unregisters
* the crq with the hypervisor.
*/
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static void rpavscsi_release_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
long rc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
}
/**
- * ibmvscsi_send_crq: - Send a CRQ
+ * rpavscsi_send_crq: - Send a CRQ
* @hostdata: the adapter
* @word1: the first 64 bits of the data
* @word2: the second 64 bits of the data
*/
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2)
{
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
}
/**
- * ibmvscsi_task: - Process srps asynchronously
+ * rpavscsi_task: - Process srps asynchronously
* @data: ibmvscsi_host_data of host
*/
-static void ibmvscsi_task(void *data)
+static void rpavscsi_task(void *data)
{
struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -190,6 +191,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
}
/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue: crq_queue to initialize and register
+ * @hostdata: ibmvscsi_host_data of host
+ *
+ */
+static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
+{
+ int rc;
+ struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+ /* Close the CRQ */
+ do {
+ rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+ } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
+
+ /* Clean out the queue */
+ memset(queue->msgs, 0x00, PAGE_SIZE);
+ queue->cur = 0;
+
+ set_adapter_info(hostdata);
+
+ /* And re-open it again */
+ rc = plpar_hcall_norets(H_REG_CRQ,
+ vdev->unit_address,
+ queue->msg_token, PAGE_SIZE);
+ if (rc == 2) {
+ /* Adapter is good, but other end is not ready */
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
+ } else if (rc != 0) {
+ dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
+ }
+ return rc;
+}
+
+/**
* initialize_crq_queue: - Initializes and registers CRQ with hypervisor
* @queue: crq_queue to initialize and register
* @hostdata: ibmvscsi_host_data of host
@@ -198,9 +235,9 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
* the crq with the hypervisor.
* Returns zero on success.
*/
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static int rpavscsi_init_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
int rc;
int retrc;
@@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
queue->msg_token, PAGE_SIZE);
if (rc == H_RESOURCE)
/* maybe kexecing and resource is busy. try a reset */
- rc = ibmvscsi_reset_crq_queue(queue,
+ rc = rpavscsi_reset_crq_queue(queue,
hostdata);
if (rc == 2) {
@@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
}
if (request_irq(vdev->irq,
- ibmvscsi_handle_event,
+ rpavscsi_handle_event,
0, "ibmvscsi", (void *)hostdata) != 0) {
dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
vdev->irq);
@@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
queue->cur = 0;
spin_lock_init(&queue->lock);
- tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+ tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task,
(unsigned long)hostdata);
return retrc;
@@ -281,8 +318,8 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
* @hostdata: ibmvscsi_host_data of host
*
*/
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
int rc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
return rc;
}
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue: crq_queue to initialize and register
- * @hostdata: ibmvscsi_host_data of host
- *
- */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
-{
- int rc;
- struct vio_dev *vdev = to_vio_dev(hostdata->dev);
-
- /* Close the CRQ */
- do {
- rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
- } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
-
- /* Clean out the queue */
- memset(queue->msgs, 0x00, PAGE_SIZE);
- queue->cur = 0;
-
- set_adapter_info(hostdata);
-
- /* And re-open it again */
- rc = plpar_hcall_norets(H_REG_CRQ,
- vdev->unit_address,
- queue->msg_token, PAGE_SIZE);
- if (rc == 2) {
- /* Adapter is good, but other end is not ready */
- dev_warn(hostdata->dev, "Partner adapter not ready\n");
- } else if (rc != 0) {
- dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
- }
- return rc;
-}
+struct ibmvscsi_ops rpavscsi_ops = {
+ .init_crq_queue = rpavscsi_init_crq_queue,
+ .release_crq_queue = rpavscsi_release_crq_queue,
+ .reset_crq_queue = rpavscsi_reset_crq_queue,
+ .reenable_crq_queue = rpavscsi_reenable_crq_queue,
+ .send_crq = rpavscsi_send_crq,
+};
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1cc01acc280..d81bb076a15 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -82,14 +82,12 @@ typedef struct idescsi_pc_s {
*/
#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */
#define PC_WRITING 1 /* Data direction */
-#define PC_TRANSFORM 2 /* transform SCSI commands */
#define PC_TIMEDOUT 3 /* command timed out */
#define PC_DMA_OK 4 /* Use DMA */
/*
* SCSI command transformation layer
*/
-#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */
#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */
/*
@@ -175,7 +173,8 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+ if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+ scsi_sg_count(pc->scsi_cmd)) {
printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
idescsi_discard_data (drive, bcount);
return;
@@ -210,7 +209,8 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+ if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+ scsi_sg_count(pc->scsi_cmd)) {
printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
idescsi_output_zeros (drive, bcount);
return;
@@ -239,77 +239,6 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
}
}
-/*
- * Most of the SCSI commands are supported directly by ATAPI devices.
- * idescsi_transform_pc handles the few exceptions.
- */
-static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
- u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
- char *atapi_buf;
-
- if (!test_bit(PC_TRANSFORM, &pc->flags))
- return;
- if (drive->media == ide_cdrom || drive->media == ide_optical) {
- if (c[0] == READ_6 || c[0] == WRITE_6) {
- c[8] = c[4]; c[5] = c[3]; c[4] = c[2];
- c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
- c[0] += (READ_10 - READ_6);
- }
- if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
- unsigned short new_len;
- if (!scsi_buf)
- return;
- if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
- return;
- memset(atapi_buf, 0, pc->buffer_size + 4);
- memset (c, 0, 12);
- c[0] = sc[0] | 0x40;
- c[1] = sc[1];
- c[2] = sc[2];
- new_len = sc[4] + 4;
- c[8] = new_len;
- c[7] = new_len >> 8;
- c[9] = sc[5];
- if (c[0] == MODE_SELECT_10) {
- atapi_buf[1] = scsi_buf[0]; /* Mode data length */
- atapi_buf[2] = scsi_buf[1]; /* Medium type */
- atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */
- atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */
- memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
- }
- pc->buffer = atapi_buf;
- pc->request_transfer += 4;
- pc->buffer_size += 4;
- }
- }
-}
-
-static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
- u8 *atapi_buf = pc->buffer;
- u8 *sc = pc->scsi_cmd->cmnd;
- u8 *scsi_buf = pc->scsi_cmd->request_buffer;
-
- if (!test_bit(PC_TRANSFORM, &pc->flags))
- return;
- if (drive->media == ide_cdrom || drive->media == ide_optical) {
- if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
- scsi_buf[0] = atapi_buf[1]; /* Mode data length */
- scsi_buf[1] = atapi_buf[2]; /* Medium type */
- scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */
- scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */
- memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
- }
- if (pc->c[0] == INQUIRY) {
- scsi_buf[2] |= 2; /* ansi_revision */
- scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
- }
- }
- if (atapi_buf && atapi_buf != scsi_buf)
- kfree(atapi_buf);
-}
-
static void hexdump(u8 *x, int len)
{
int i;
@@ -393,7 +322,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
struct Scsi_Host *host;
- u8 *scsi_buf;
int errors = rq->errors;
unsigned long flags;
@@ -434,15 +362,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
} else {
pc->scsi_cmd->result = DID_OK << 16;
- idescsi_transform_pc2 (drive, pc);
- if (log) {
- printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
- if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
- printk(", rst = ");
- scsi_buf = pc->scsi_cmd->request_buffer;
- hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen));
- } else printk("\n");
- }
}
host = pc->scsi_cmd->device->host;
spin_lock_irqsave(host->host_lock, flags);
@@ -637,19 +556,14 @@ static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc)
return 1;
sg = hwif->sg_table;
- scsi_sg = pc->scsi_cmd->request_buffer;
- segments = pc->scsi_cmd->use_sg;
+ scsi_sg = scsi_sglist(pc->scsi_cmd);
+ segments = scsi_sg_count(pc->scsi_cmd);
if (segments > hwif->sg_max_nents)
return 1;
- if (!segments) {
- hwif->sg_nents = 1;
- sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer);
- } else {
- hwif->sg_nents = segments;
- memcpy(sg, scsi_sg, sizeof(*sg) * segments);
- }
+ hwif->sg_nents = segments;
+ memcpy(sg, scsi_sg, sizeof(*sg) * segments);
return 0;
}
@@ -744,7 +658,6 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
{
if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
- set_bit(IDESCSI_TRANSFORM, &scsi->transform);
clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
#if IDESCSI_DEBUG_LOG
set_bit(IDESCSI_LOG_CMD, &scsi->log);
@@ -758,6 +671,7 @@ static void ide_scsi_remove(ide_drive_t *drive)
struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
struct gendisk *g = scsi->disk;
+ scsi_remove_host(scsihost);
ide_proc_unregister_driver(drive, scsi->driver);
ide_unregister_region(g);
@@ -766,7 +680,6 @@ static void ide_scsi_remove(ide_drive_t *drive)
g->private_data = NULL;
put_disk(g);
- scsi_remove_host(scsihost);
ide_scsi_put(scsi);
}
@@ -838,6 +751,8 @@ static struct block_device_operations idescsi_ops = {
static int idescsi_slave_configure(struct scsi_device * sdp)
{
/* Configure detected device */
+ sdp->use_10_for_rw = 1;
+ sdp->use_10_for_ms = 1;
scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
return 0;
}
@@ -862,24 +777,6 @@ static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg)
return -EINVAL;
}
-static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd)
-{
- idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
- /* this was a layering violation and we can't support it
- anymore, sorry. */
-#if 0
- struct gendisk *disk = cmd->request->rq_disk;
-
- if (disk) {
- struct struct scsi_device_Template **p = disk->private_data;
- if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
- return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
- }
-#endif
- return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
-}
-
static int idescsi_queue (struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -905,23 +802,14 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
pc->flags = 0;
pc->rq = rq;
memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
- if (cmd->use_sg) {
- pc->buffer = NULL;
- pc->sg = cmd->request_buffer;
- } else {
- pc->buffer = cmd->request_buffer;
- pc->sg = NULL;
- }
+ pc->buffer = NULL;
+ pc->sg = scsi_sglist(cmd);
pc->b_count = 0;
- pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
+ pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
pc->scsi_cmd = cmd;
pc->done = done;
pc->timeout = jiffies + cmd->timeout_per_command;
- if (should_transform(drive, cmd))
- set_bit(PC_TRANSFORM, &pc->flags);
- idescsi_transform_pc1 (drive, pc);
-
if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
hexdump(cmd->cmnd, cmd->cmd_len);
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 005d2b05f32..74cdc1f0a78 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -740,10 +740,6 @@ static void imm_interrupt(struct work_struct *work)
struct Scsi_Host *host = cmd->device->host;
unsigned long flags;
- if (!cmd) {
- printk("IMM: bug in imm_interrupt\n");
- return;
- }
if (imm_engine(dev, cmd)) {
schedule_delayed_work(&dev->imm_tq, 1);
return;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 312190a6938..ab7cbf3449c 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -343,7 +343,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
instance = cmd->device->host;
hostdata = (struct IN2000_hostdata *) instance->hostdata;
- DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->pid))
+ DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number))
/* Set up a few fields in the Scsi_Cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
@@ -427,7 +427,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
in2000_execute(cmd->device->host);
- DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+ DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
return 0;
}
@@ -703,7 +703,7 @@ static void in2000_execute(struct Scsi_Host *instance)
* to search the input_Q again...
*/
- DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+ DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
}
@@ -1147,7 +1147,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+ DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
hostdata->state = S_CONNECTED;
break;
@@ -1189,7 +1189,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
switch (msg) {
case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+ DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
@@ -1327,7 +1327,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+ DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_3393(hostdata, WD_TARGET_LUN);
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1348,7 +1348,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
in2000_execute(instance);
} else {
- printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid);
+ printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number);
}
break;
@@ -1415,7 +1415,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
spin_unlock_irqrestore(instance->host_lock, flags);
return IRQ_HANDLED;
}
- DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
@@ -1440,7 +1440,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
*/
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
@@ -1573,7 +1573,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
} else
hostdata->state = S_CONNECTED;
- DB(DB_INTR, printk("-%ld", cmd->pid))
+ DB(DB_INTR, printk("-%ld", cmd->serial_number))
break;
default:
@@ -1702,7 +1702,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
prev->host_scribble = cmd->host_scribble;
cmd->host_scribble = NULL;
cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid);
+ printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number);
cmd->scsi_done(cmd);
return SUCCESS;
}
@@ -1723,7 +1723,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
if (hostdata->connected == cmd) {
- printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid);
+ printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number);
printk("sending wd33c93 ABORT command - ");
write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
@@ -2268,7 +2268,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *) hd->connected;
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
@@ -2276,7 +2276,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
@@ -2285,7 +2285,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eafb6fc..b41dfb53902 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
/**
* ipr_sata_reset - Reset the SATA port
- * @ap: SATA port to reset
+ * @link: SATA link to reset
* @classes: class of the attached device
*
- * This function issues a SATA phy reset to the affected ATA port.
+ * This function issues a SATA phy reset to the affected ATA link.
*
* 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_link *link, unsigned int *classes,
unsigned long deadline)
{
- struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_sata_port *sata_port = link->ap->private_data;
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
struct ipr_resource_entry *res;
unsigned long lock_flags = 0;
@@ -4981,22 +4981,22 @@ static void ipr_ata_phy_reset(struct ata_port *ap)
rc = ipr_device_reset(ioa_cfg, res);
if (rc) {
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
goto out_unlock;
}
switch(res->cfgte.proto) {
case IPR_PROTO_SATA:
case IPR_PROTO_SAS_STP:
- ap->device[0].class = ATA_DEV_ATA;
+ ap->link.device[0].class = ATA_DEV_ATA;
break;
case IPR_PROTO_SATA_ATAPI:
case IPR_PROTO_SAS_STP_ATAPI:
- ap->device[0].class = ATA_DEV_ATAPI;
+ ap->link.device[0].class = ATA_DEV_ATAPI;
break;
default:
- ap->device[0].class = ATA_DEV_UNKNOWN;
- ap->ops->port_disable(ap);
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
+ ata_port_disable(ap);
break;
};
@@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap)
}
static struct ata_port_operations ipr_sata_ops = {
- .port_disable = ata_port_disable,
.check_status = ipr_ata_check_status,
.check_altstatus = ipr_ata_check_altstatus,
.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 492a51bd6aa..2ed099e2c20 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -204,8 +204,8 @@ module_param(ips, charp, 0);
/*
* DRIVER_VER
*/
-#define IPS_VERSION_HIGH "7.12"
-#define IPS_VERSION_LOW ".05 "
+#define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING
+#define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " "
#if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
#warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
@@ -656,6 +656,8 @@ ips_release(struct Scsi_Host *sh)
METHOD_TRACE("ips_release", 1);
+ scsi_remove_host(sh);
+
for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
if (i == IPS_MAX_ADAPTERS) {
@@ -707,7 +709,6 @@ ips_release(struct Scsi_Host *sh)
/* free IRQ */
free_irq(ha->irq, ha);
- scsi_remove_host(sh);
scsi_host_put(sh);
ips_released_controllers++;
@@ -6946,7 +6947,7 @@ module_exit(ips_module_exit);
static int __devinit
ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
{
- int index;
+ int uninitialized_var(index);
int rc;
METHOD_TRACE("ips_insert_device", 1);
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 24123d537c5..3bcbd9ff056 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -1172,12 +1172,13 @@ typedef struct {
*************************************************************************/
#define IPS_VER_MAJOR 7
-#define IPS_VER_MAJOR_STRING "7"
+#define IPS_VER_MAJOR_STRING __stringify(IPS_VER_MAJOR)
#define IPS_VER_MINOR 12
-#define IPS_VER_MINOR_STRING "12"
-#define IPS_VER_BUILD 02
-#define IPS_VER_BUILD_STRING "02"
-#define IPS_VER_STRING "7.12.02"
+#define IPS_VER_MINOR_STRING __stringify(IPS_VER_MINOR)
+#define IPS_VER_BUILD 05
+#define IPS_VER_BUILD_STRING __stringify(IPS_VER_BUILD)
+#define IPS_VER_STRING IPS_VER_MAJOR_STRING "." \
+ IPS_VER_MINOR_STRING "." IPS_VER_BUILD_STRING
#define IPS_RELEASE_ID 0x00020000
#define IPS_BUILD_IDENT 761
#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5e573efcf0a..0829b55c64d 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap)
switch (dev->sata_dev.command_set) {
case ATA_COMMAND_SET:
SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
- ap->device[0].class = ATA_DEV_ATA;
+ ap->link.device[0].class = ATA_DEV_ATA;
break;
case ATAPI_COMMAND_SET:
SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
- ap->device[0].class = ATA_DEV_ATAPI;
+ ap->link.device[0].class = ATA_DEV_ATAPI;
break;
default:
SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
__FUNCTION__,
dev->sata_dev.command_set);
- ap->device[0].class = ATA_DEV_UNKNOWN;
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
break;
}
@@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
dev->sata_dev.serror = val;
break;
case SCR_ACTIVE:
- dev->sata_dev.ap->sactive = val;
+ dev->sata_dev.ap->link.sactive = val;
break;
default:
return -EINVAL;
@@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
*val = dev->sata_dev.serror;
return 0;
case SCR_ACTIVE:
- *val = dev->sata_dev.ap->sactive;
+ *val = dev->sata_dev.ap->link.sactive;
return 0;
default:
return -EINVAL;
@@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
}
static struct ata_port_operations sas_sata_ops = {
- .port_disable = ata_port_disable,
.check_status = sas_ata_check_status,
.check_altstatus = sas_ata_check_status,
.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 732446e6396..2ad0a27dbaa 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -392,7 +392,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
}
int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
- u64 addr)
+ u64 itn_id, u64 addr)
{
enum dma_data_direction dir;
struct scsi_cmnd *sc;
@@ -428,7 +428,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
sc->request_bufflen = len;
sc->request_buffer = (void *) (unsigned long) addr;
sc->tag = tag;
- err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+ err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
+ cmd->tag);
if (err)
scsi_host_put_command(shost, sc);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 2e3c01bebed..149fdd25f8e 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -43,7 +43,6 @@
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_version.h"
-#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
#ifdef CONFIG_LPFC_DEBUG_FS
@@ -902,7 +901,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
}
- vport->disc_trc = kmalloc(
+ vport->disc_trc = kmzlloc(
(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
GFP_KERNEL);
@@ -913,8 +912,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
goto debug_failed;
}
atomic_set(&vport->disc_trc_cnt, 0);
- memset(vport->disc_trc, 0,
- (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
snprintf(name, sizeof(name), "discovery_trace");
vport->debug_disc_trc =
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 414350ab584..ecebdfa0047 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -43,7 +43,6 @@
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_version.h"
-#include "lpfc_vport.h"
static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
@@ -1266,11 +1265,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
uint32_t *HashWorking;
uint32_t *pwwnn = (uint32_t *) phba->wwnn;
- HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
+ HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL);
if (!HashWorking)
return;
- memset(HashWorking, 0, (80 * sizeof(uint32_t)));
HashWorking[0] = HashWorking[78] = *pwwnn++;
HashWorking[1] = HashWorking[79] = *pwwnn;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 17d7dc05149..cd674938ccd 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
dma_addr_t pdma_phys;
uint16_t iotag;
- psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+ psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
if (!psb)
return NULL;
- memset(psb, 0, sizeof (struct lpfc_scsi_buf));
/*
* Get memory from the pci pool to map the virt space to pci bus space
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index ce5ff2bccba..e5337ad4121 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -675,7 +675,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
uint32_t hbqno;
hbqno = tag >> 16;
- if (hbqno > LPFC_MAX_HBQS)
+ if (hbqno >= LPFC_MAX_HBQS)
return NULL;
list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index da56163c30a..e7e11f282c8 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4416,8 +4416,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scmd = &adapter->int_scmd;
memset(scmd, 0, sizeof(Scsi_Cmnd));
- sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
- memset(sdev, 0, sizeof(struct scsi_device));
+ sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
scmd->device = sdev;
scmd->device->host = adapter->host;
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
index 1bdddad4857..b264b499d98 100644
--- a/drivers/scsi/mvme16x_scsi.c
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -48,13 +48,12 @@ mvme16x_probe(struct device *dev)
goto out;
}
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
if (hostdata == NULL) {
printk(KERN_ERR "mvme16x-scsi: "
"Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)0xfff47000UL;
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 030ba49f33f..016c462bc77 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8143,12 +8143,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd)
unsigned long flags;
struct scsi_cmnd *done_list;
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
- printk("ncr53c8xx_abort: pid=%lu serial_number=%ld\n",
- cmd->pid, cmd->serial_number);
-#else
- printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
-#endif
+ printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number);
NCR_LOCK_NCB(np, flags);
@@ -8528,18 +8523,15 @@ struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt,
}
-int ncr53c8xx_release(struct Scsi_Host *host)
+void ncr53c8xx_release(struct Scsi_Host *host)
{
- struct host_data *host_data;
+ struct host_data *host_data = shost_priv(host);
#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx: release\n");
#endif
- if (!host)
- return 1;
- host_data = (struct host_data *)host->hostdata;
- if (host_data && host_data->ncb)
+ if (host_data->ncb)
ncr_detach(host_data->ncb);
- return 1;
+ scsi_host_put(host);
}
static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index b39357d9af8..0e008dacf67 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -1321,7 +1321,7 @@ struct ncr_device {
};
extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
-extern int ncr53c8xx_release(struct Scsi_Host *host);
+extern void ncr53c8xx_release(struct Scsi_Host *host);
irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
extern int ncr53c8xx_init(void);
extern void ncr53c8xx_exit(void);
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 08060fb478b..331b789937c 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -3298,7 +3298,7 @@ static ssize_t osst_write(struct file * filp, const char __user * buf, size_t co
char * name = tape_name(STp);
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return (-ERESTARTSYS);
/*
@@ -3600,7 +3600,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
out:
if (SRpnt != NULL) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -3619,7 +3619,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
char * name = tape_name(STp);
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return (-ERESTARTSYS);
/*
@@ -3785,7 +3785,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
out:
if (SRpnt != NULL) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -4852,7 +4852,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
char * name = tape_name(STp);
void __user * p = (void __user *)arg;
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
#if DEBUG
@@ -5163,14 +5163,14 @@ static int osst_ioctl(struct inode * inode,struct file * file,
}
if (SRpnt) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return scsi_ioctl(STp->device, cmd_in, p);
out:
if (SRpnt) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -5778,13 +5778,12 @@ static int osst_probe(struct device *dev)
dev_num = i;
/* allocate a struct osst_tape for this device */
- tpnt = kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
- if (tpnt == NULL) {
+ tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
+ if (!tpnt) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
goto out_put_disk;
}
- memset(tpnt, 0, sizeof(struct osst_tape));
/* allocate a buffer for this device */
i = SDp->host->sg_tablesize;
@@ -5866,7 +5865,7 @@ static int osst_probe(struct device *dev)
tpnt->modes[2].defined = 1;
tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
- init_MUTEX(&tpnt->lock);
+ mutex_init(&tpnt->lock);
osst_nr_dev++;
write_unlock(&os_scsi_tapes_lock);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 2cc7b5a1606..5aa22740b5d 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -4,6 +4,7 @@
#include <asm/byteorder.h>
#include <linux/completion.h>
+#include <linux/mutex.h>
/* FIXME - rename and use the following two types or delete them!
* and the types really should go to st.h anyway...
@@ -532,7 +533,7 @@ struct osst_tape {
struct scsi_driver *driver;
unsigned capacity;
struct scsi_device *device;
- struct semaphore lock; /* for serialization */
+ struct mutex lock; /* for serialization */
struct completion wait; /* for SCSI commands */
struct osst_buffer * buffer;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 445cfbbca9b..a45d89b1414 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -25,8 +25,6 @@
***********************************************************************/
-/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */
-
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -59,7 +57,7 @@
#include "nsp_cs.h"
MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
-MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
@@ -83,10 +81,6 @@ static struct scsi_host_template nsp_driver_template = {
.proc_name = "nsp_cs",
.proc_info = nsp_proc_info,
.name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
- .detect = nsp_detect_old,
- .release = nsp_release_old,
-#endif
.info = nsp_info,
.queuecommand = nsp_queuecommand,
/* .eh_abort_handler = nsp_eh_abort,*/
@@ -97,9 +91,6 @@ static struct scsi_host_template nsp_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
- .use_new_eh_code = 1,
-#endif
};
static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
@@ -1313,11 +1304,7 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
nsp_hw_data *data_b = &nsp_data_base, *data;
nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
-#else
- host = scsi_register(sht, sizeof(nsp_hw_data));
-#endif
if (host == NULL) {
nsp_dbg(NSP_DEBUG_INIT, "host failed");
return NULL;
@@ -1354,37 +1341,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
return host; /* detect done. */
}
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int nsp_detect_old(struct scsi_host_template *sht)
-{
- if (nsp_detect(sht) == NULL) {
- return 0;
- } else {
- //MOD_INC_USE_COUNT;
- return 1;
- }
-}
-
-
-static int nsp_release_old(struct Scsi_Host *shpnt)
-{
- //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
-
- /* PCMCIA Card Service dose same things below. */
- /* So we do nothing. */
- //if (shpnt->irq) {
- // free_irq(shpnt->irq, data->ScsiInfo);
- //}
- //if (shpnt->io_port) {
- // release_region(shpnt->io_port, shpnt->n_io_port);
- //}
-
- //MOD_DEC_USE_COUNT;
-
- return 0;
-}
-#endif
-
/*----------------------------------------------------------------*/
/* return info string */
/*----------------------------------------------------------------*/
@@ -1403,19 +1359,9 @@ static const char *nsp_info(struct Scsi_Host *shpnt)
nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
} \
} while(0)
-static int
-nsp_proc_info(
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host,
-#endif
- char *buffer,
- char **start,
- off_t offset,
- int length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- int hostno,
-#endif
- int inout)
+
+static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
int id;
char *pos = buffer;
@@ -1423,24 +1369,13 @@ nsp_proc_info(
int speed;
unsigned long flags;
nsp_hw_data *data;
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host;
-#else
int hostno;
-#endif
+
if (inout) {
return -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
hostno = host->host_no;
-#else
- /* search this HBA host */
- host = scsi_host_hn_get(hostno);
- if (host == NULL) {
- return -ESRCH;
- }
-#endif
data = (nsp_hw_data *)host->hostdata;
@@ -1675,10 +1610,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
cistpl_cftable_entry_t dflt = { 0 };
struct Scsi_Host *host;
nsp_hw_data *data = &nsp_data_base;
-#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
- struct scsi_device *dev;
- dev_node_t **tail, *node;
-#endif
nsp_dbg(NSP_DEBUG_INIT, "in");
@@ -1811,17 +1742,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
goto cs_failed;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
host = nsp_detect(&nsp_driver_template);
-#else
- scsi_register_host(&nsp_driver_template);
- for (host = scsi_host_get_next(NULL); host != NULL;
- host = scsi_host_get_next(host)) {
- if (host->hostt == &nsp_driver_template) {
- break;
- }
- }
-#endif
if (host == NULL) {
nsp_dbg(NSP_DEBUG_INIT, "detect failed");
@@ -1829,7 +1750,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
ret = scsi_add_host (host, NULL);
if (ret)
goto cs_failed;
@@ -1840,52 +1760,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
link->dev_node = &info->node;
info->host = host;
-#else
- nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
- tail = &link->dev_node;
- info->ndev = 0;
-
- nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-
- for (dev = host->host_queue; dev != NULL; dev = dev->next) {
- unsigned long id;
- id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) +
- ((dev->channel & 0x0f) << 8) +
- ((dev->host->host_no & 0x0f) << 12);
- node = &info->node[info->ndev];
- node->minor = 0;
- switch (dev->type) {
- case TYPE_TAPE:
- node->major = SCSI_TAPE_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
- break;
- case TYPE_DISK:
- case TYPE_MOD:
- node->major = SCSI_DISK0_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
- break;
- case TYPE_ROM:
- case TYPE_WORM:
- node->major = SCSI_CDROM_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
- break;
- default:
- node->major = SCSI_GENERIC_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
- break;
- }
- *tail = node; tail = &node->next;
- info->ndev++;
- info->host = dev->host;
- }
-
- *tail = NULL;
- if (info->ndev == 0) {
- nsp_msg(KERN_INFO, "no SCSI devices found");
- }
- nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-#endif
-
/* Finally, report what we've done */
printk(KERN_INFO "nsp_cs: index 0x%02x: ",
link->conf.ConfigIndex);
@@ -1938,13 +1812,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
/* Unlink the device chain */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
if (info->host != NULL) {
scsi_remove_host(info->host);
}
-#else
- scsi_unregister_host(&nsp_driver_template);
-#endif
link->dev_node = NULL;
if (link->win) {
@@ -1954,11 +1824,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
}
pcmcia_disable_device(link);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
if (info->host != NULL) {
scsi_host_put(info->host);
}
-#endif
} /* nsp_cs_release */
static int nsp_cs_suspend(struct pcmcia_device *link)
@@ -2005,7 +1873,6 @@ static int nsp_cs_resume(struct pcmcia_device *link)
/*======================================================================*
* module entry point
*====================================================================*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
static struct pcmcia_device_id nsp_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
@@ -2029,28 +1896,12 @@ static struct pcmcia_driver nsp_driver = {
.suspend = nsp_cs_suspend,
.resume = nsp_cs_resume,
};
-#endif
static int __init nsp_cs_init(void)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
nsp_msg(KERN_INFO, "loading...");
return pcmcia_register_driver(&nsp_driver);
-#else
- servinfo_t serv;
-
- nsp_msg(KERN_INFO, "loading...");
- pcmcia_get_card_services_info(&serv);
- if (serv.Revision != CS_RELEASE_CODE) {
- nsp_msg(KERN_DEBUG, "Card Services release does not match!");
- return -EINVAL;
- }
- register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
-
- nsp_dbg(NSP_DEBUG_INIT, "out");
- return 0;
-#endif
}
static void __exit nsp_cs_exit(void)
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 9102cbdf135..b7f0fa24641 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -10,8 +10,6 @@
=========================================================*/
-/* $Id: nsp_cs.h,v 1.19 2003/08/18 11:09:19 elca Exp $ */
-
#ifndef __nsp_cs__
#define __nsp_cs__
@@ -227,13 +225,7 @@
typedef struct scsi_info_t {
struct pcmcia_device *p_dev;
struct Scsi_Host *host;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
dev_node_t node;
-#else
- int ndev;
- dev_node_t node[8];
- struct bus_operations *bus;
-#endif
int stop;
} scsi_info_t;
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index d953d43fe2e..0363c1cd68c 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -111,13 +111,12 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
#endif
return 0;
}
- fcs = kmalloc(sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
+ fcs = kcalloc(fcscount, sizeof (struct ctrl_inquiry), GFP_DMA);
if (!fcs) {
printk ("PLUTO: Not enough memory to probe\n");
return 0;
}
- memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
memset (&dev, 0, sizeof(dev));
atomic_set (&fcss, fcscount);
@@ -161,7 +160,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->request->cmd_flags &= ~REQ_STARTED;
- SCpnt->done = pluto_detect_done;
SCpnt->request_bufflen = 256;
SCpnt->request_buffer = fcs[i].inquiry;
PLD(("set up %d %08lx\n", i, (long)SCpnt))
@@ -196,7 +194,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt = &(fcs[i].cmd);
/* Let FC mid-level free allocated resources */
- SCpnt->done (SCpnt);
+ pluto_detect_scsi_done(SCpnt);
if (!SCpnt->result) {
struct pluto_inquiry *inq;
@@ -211,7 +209,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
char *p;
long *ages;
- ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
+ ages = kcalloc((inq->channels + 1) * inq->targets, sizeof(long), GFP_KERNEL);
if (!ages) continue;
host = scsi_register (tpnt, sizeof (struct pluto));
@@ -238,7 +236,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
fc->channels = inq->channels + 1;
fc->targets = inq->targets;
fc->ages = ages;
- memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
pluto->fc = fc;
memcpy (pluto->rev_str, inq->revision, 4);
@@ -260,7 +257,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
} else
fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
}
- kfree((char *)fcs);
+ kfree(fcs);
if (nplutos)
printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
return nplutos;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index b50f1e14f2a..0f43d1d046d 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -100,16 +100,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
struct scatterlist *sgpnt;
unsigned int buflen;
- buflen = cmd->request_bufflen;
+ buflen = scsi_bufflen(cmd);
if (!buflen)
return 0;
- if (!cmd->request_buffer)
+ if (!scsi_sglist(cmd))
return -1;
- sgpnt = cmd->request_buffer;
active = 1;
- for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ req_len = act_len = 0;
+ scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
if (active) {
kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
len = sgpnt->length;
@@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
}
req_len += sgpnt->length;
}
- cmd->resid = req_len - act_len;
+ scsi_set_resid(cmd, req_len - act_len);
return 0;
}
@@ -138,15 +138,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
struct scatterlist *sgpnt;
unsigned int buflen;
- buflen = cmd->request_bufflen;
+ buflen = scsi_bufflen(cmd);
if (!buflen)
return 0;
- if (!cmd->request_buffer)
+ if (!scsi_sglist(cmd))
return -1;
- sgpnt = cmd->request_buffer;
- for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ req_len = fin = 0;
+ scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
len = sgpnt->length;
if ((req_len + len) > buflen) {
@@ -177,12 +177,12 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
atapi_cmnd.pktlen = 12;
atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
- atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+ atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd);
atapi_cmnd.buffer = dev->bounce_lpar;
switch (cmd->sc_data_direction) {
case DMA_FROM_DEVICE:
- if (cmd->request_bufflen >= CD_FRAMESIZE)
+ if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
atapi_cmnd.proto = DMA_PROTO;
else
atapi_cmnd.proto = PIO_DATA_IN_PROTO;
@@ -190,7 +190,7 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
break;
case DMA_TO_DEVICE:
- if (cmd->request_bufflen >= CD_FRAMESIZE)
+ if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
atapi_cmnd.proto = DMA_PROTO;
else
atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 54d8bdf8685..fba8aa8a81b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4086,7 +4086,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd)
} */
printk(" tag=%d, transfersize=0x%x \n",
cmd->tag, cmd->transfersize);
- printk(" Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd));
+ printk(" Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd));
printk(" underflow size = 0x%x, direction=0x%x\n",
cmd->underflow, cmd->sc_data_direction);
}
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 0f2a9f5d801..05fa7796a55 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -18,7 +18,7 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
char *rbuf = (char *)ha->fw_dump;
@@ -39,7 +39,7 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int reading;
@@ -89,7 +89,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int size = ha->nvram_size;
char *nvram_cache = ha->nvram;
@@ -112,7 +112,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
unsigned long flags;
uint16_t cnt;
@@ -146,7 +146,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
- ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base,
count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -170,15 +170,15 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (ha->optrom_state != QLA_SREADING)
return 0;
- if (off > ha->optrom_size)
+ if (off > ha->optrom_region_size)
return 0;
- if (off + count > ha->optrom_size)
- count = ha->optrom_size - off;
+ if (off + count > ha->optrom_region_size)
+ count = ha->optrom_region_size - off;
memcpy(buf, &ha->optrom_buffer[off], count);
@@ -190,15 +190,15 @@ qla2x00_sysfs_write_optrom(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (ha->optrom_state != QLA_SWRITING)
return -EINVAL;
- if (off > ha->optrom_size)
+ if (off > ha->optrom_region_size)
return -ERANGE;
- if (off + count > ha->optrom_size)
- count = ha->optrom_size - off;
+ if (off + count > ha->optrom_region_size)
+ count = ha->optrom_region_size - off;
memcpy(&ha->optrom_buffer[off], buf, count);
@@ -220,14 +220,18 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
- int val;
+ uint32_t start = 0;
+ uint32_t size = ha->optrom_size;
+ int val, valid;
if (off)
return 0;
- if (sscanf(buf, "%d", &val) != 1)
+ if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
+ return -EINVAL;
+ if (start > ha->optrom_size)
return -EINVAL;
switch (val) {
@@ -237,6 +241,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
break;
ha->optrom_state = QLA_SWAITING;
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Freeing flash region allocation -- 0x%x bytes.\n",
+ ha->optrom_region_size));
+
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
break;
@@ -244,44 +253,107 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
if (ha->optrom_state != QLA_SWAITING)
break;
+ if (start & 0xfff) {
+ qla_printk(KERN_WARNING, ha,
+ "Invalid start region 0x%x/0x%x.\n", start, size);
+ return -EINVAL;
+ }
+
+ ha->optrom_region_start = start;
+ ha->optrom_region_size = start + size > ha->optrom_size ?
+ ha->optrom_size - start : size;
+
ha->optrom_state = QLA_SREADING;
- ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+ ha->optrom_buffer = vmalloc(ha->optrom_region_size);
if (ha->optrom_buffer == NULL) {
qla_printk(KERN_WARNING, ha,
"Unable to allocate memory for optrom retrieval "
- "(%x).\n", ha->optrom_size);
+ "(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return count;
}
- memset(ha->optrom_buffer, 0, ha->optrom_size);
- ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
- ha->optrom_size);
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Reading flash region -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ memset(ha->optrom_buffer, 0, ha->optrom_region_size);
+ ha->isp_ops->read_optrom(ha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
break;
case 2:
if (ha->optrom_state != QLA_SWAITING)
break;
+ /*
+ * We need to be more restrictive on which FLASH regions are
+ * allowed to be updated via user-space. Regions accessible
+ * via this method include:
+ *
+ * ISP21xx/ISP22xx/ISP23xx type boards:
+ *
+ * 0x000000 -> 0x020000 -- Boot code.
+ *
+ * ISP2322/ISP24xx type boards:
+ *
+ * 0x000000 -> 0x07ffff -- Boot code.
+ * 0x080000 -> 0x0fffff -- Firmware.
+ *
+ * ISP25xx type boards:
+ *
+ * 0x000000 -> 0x07ffff -- Boot code.
+ * 0x080000 -> 0x0fffff -- Firmware.
+ * 0x120000 -> 0x12ffff -- VPD and HBA parameters.
+ */
+ valid = 0;
+ if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+ valid = 1;
+ else if (start == (FA_BOOT_CODE_ADDR*4) ||
+ start == (FA_RISC_CODE_ADDR*4))
+ valid = 1;
+ else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))
+ valid = 1;
+ if (!valid) {
+ qla_printk(KERN_WARNING, ha,
+ "Invalid start region 0x%x/0x%x.\n", start, size);
+ return -EINVAL;
+ }
+
+ ha->optrom_region_start = start;
+ ha->optrom_region_size = start + size > ha->optrom_size ?
+ ha->optrom_size - start : size;
+
ha->optrom_state = QLA_SWRITING;
- ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+ ha->optrom_buffer = vmalloc(ha->optrom_region_size);
if (ha->optrom_buffer == NULL) {
qla_printk(KERN_WARNING, ha,
"Unable to allocate memory for optrom update "
- "(%x).\n", ha->optrom_size);
+ "(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return count;
}
- memset(ha->optrom_buffer, 0, ha->optrom_size);
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Staging flash region write -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break;
case 3:
if (ha->optrom_state != QLA_SWRITING)
break;
- ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
- ha->optrom_size);
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Writing flash region -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ ha->isp_ops->write_optrom(ha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
break;
+ default:
+ count = -EINVAL;
}
return count;
}
@@ -300,7 +372,7 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int size = ha->vpd_size;
char *vpd_cache = ha->vpd;
@@ -323,7 +395,7 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
unsigned long flags;
@@ -354,7 +426,7 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
uint16_t iter, addr, offset;
int rval;
@@ -459,7 +531,7 @@ qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_fw_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
char fw_str[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -469,7 +541,7 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_serial_num_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
uint32_t sn;
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
@@ -480,14 +552,14 @@ qla2x00_serial_num_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_isp_name_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
}
static ssize_t
qla2x00_isp_id_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
@@ -496,14 +568,14 @@ qla2x00_isp_id_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_model_name_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
}
static ssize_t
qla2x00_model_desc_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n",
ha->model_desc ? ha->model_desc: "");
}
@@ -511,7 +583,7 @@ qla2x00_model_desc_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_pci_info_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
char pci_info[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -521,7 +593,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_state_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
@@ -559,7 +631,7 @@ qla2x00_state_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_zio_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
switch (ha->zio_mode) {
@@ -576,7 +648,7 @@ qla2x00_zio_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
uint16_t zio_mode;
@@ -602,7 +674,7 @@ qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
static ssize_t
qla2x00_zio_timer_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
}
@@ -611,7 +683,7 @@ static ssize_t
qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
uint16_t zio_timer;
@@ -629,7 +701,7 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
static ssize_t
qla2x00_beacon_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
if (ha->beacon_blink_led)
@@ -643,7 +715,7 @@ static ssize_t
qla2x00_beacon_store(struct class_device *cdev, const char *buf,
size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
int rval;
@@ -673,7 +745,7 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
static ssize_t
qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
ha->bios_revision[0]);
@@ -682,7 +754,7 @@ qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
ha->efi_revision[0]);
@@ -691,7 +763,7 @@ qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
ha->fcode_revision[0]);
@@ -700,7 +772,7 @@ qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
@@ -757,7 +829,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
static void
qla2x00_get_host_port_id(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
@@ -766,7 +838,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost)
static void
qla2x00_get_host_speed(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
uint32_t speed = 0;
switch (ha->link_data_rate) {
@@ -786,7 +858,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
static void
qla2x00_get_host_port_type(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
uint32_t port_type = FC_PORTTYPE_UNKNOWN;
switch (ha->current_topology) {
@@ -810,7 +882,7 @@ static void
qla2x00_get_starget_node_name(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
u64 node_name = 0;
@@ -828,7 +900,7 @@ static void
qla2x00_get_starget_port_name(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
u64 port_name = 0;
@@ -846,7 +918,7 @@ static void
qla2x00_get_starget_port_id(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
uint32_t port_id = ~0U;
@@ -865,7 +937,7 @@ static void
qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
{
struct Scsi_Host *host = rport_to_shost(rport);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
}
@@ -874,7 +946,7 @@ static void
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
struct Scsi_Host *host = rport_to_shost(rport);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
if (timeout)
ha->port_down_retry_count = timeout;
@@ -887,7 +959,7 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
static int
qla2x00_issue_lip(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
return 0;
@@ -896,7 +968,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
static struct fc_host_statistics *
qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
int rval;
uint16_t mb_stat[1];
link_stat_t stat_buf;
@@ -934,7 +1006,7 @@ done:
static void
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
}
@@ -942,7 +1014,7 @@ qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
static void
qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
}
@@ -950,7 +1022,7 @@ qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
static void
qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
u64 node_name;
if (ha->device_flags & SWITCH_FOUND)
@@ -964,7 +1036,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
static void
qla2x00_get_host_port_state(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
if (!ha->flags.online)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
@@ -978,7 +1050,7 @@ static int
qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
{
int ret = 0;
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
ret = qla24xx_vport_create_req_sanity_check(fc_vport);
@@ -1047,7 +1119,7 @@ vport_create_failed_2:
int
qla24xx_vport_delete(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha = fc_vport->dd_data;
qla24xx_disable_vp(vha);
@@ -1178,6 +1250,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
- fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+ fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;;
fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index c6680348b64..eaa04dabcdf 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -38,7 +38,7 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
}
static int
-qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
uint32_t cram_size, uint32_t *ext_mem, void **nxt)
{
int rval;
@@ -152,6 +152,103 @@ qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
return rval;
}
+static uint32_t *
+qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
+ uint32_t count, uint32_t *buf)
+{
+ uint32_t __iomem *dmp_reg;
+
+ WRT_REG_DWORD(&reg->iobase_addr, iobase);
+ dmp_reg = &reg->iobase_window;
+ while (count--)
+ *buf++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ return buf;
+}
+
+static inline int
+qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
+{
+ int rval = QLA_SUCCESS;
+ uint32_t cnt;
+
+ if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
+ return rval;
+
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+ for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ return rval;
+}
+
+static int
+qla24xx_soft_reset(scsi_qla_host_t *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint32_t cnt;
+ uint16_t mb0, wd;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ /* Reset RISC. */
+ WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
+ break;
+
+ udelay(10);
+ }
+
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+ udelay(100);
+ /* Wait for firmware to complete NVRAM accesses. */
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
+ udelay(5);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ barrier();
+ }
+
+ /* Wait for soft-reset to complete. */
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_ISP_SOFT_RESET) == 0)
+ break;
+
+ udelay(10);
+ }
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
+
+ for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ return rval;
+}
+
+static inline void
+qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
+ uint16_t *buf)
+{
+ uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;
+
+ while (count--)
+ *buf++ = htons(RD_REG_WORD(dmp_reg++));
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -214,88 +311,61 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
}
if (rval == QLA_SUCCESS) {
- dmp_reg = (uint16_t __iomem *)(reg + 0);
+ dmp_reg = &reg->flash_address;
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+ dmp_reg = &reg->u.isp2300.req_q_in;
for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
+ dmp_reg = &reg->u.isp2300.mailbox0;
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++)
- fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x50);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 48, fw->dma_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+ dmp_reg = &reg->risc_hw;
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
WRT_REG_WORD(&reg->pcr, 0x2200);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
WRT_REG_WORD(&reg->pcr, 0x2400);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
WRT_REG_WORD(&reg->pcr, 0x2600);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
WRT_REG_WORD(&reg->pcr, 0x2800);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
WRT_REG_WORD(&reg->pcr, 0x2A00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
WRT_REG_WORD(&reg->pcr, 0x2C00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
WRT_REG_WORD(&reg->pcr, 0x2E00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x10);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] =
- htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x20);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x30);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
/* Reset RISC. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -567,83 +637,59 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
rval = QLA_FUNCTION_TIMEOUT;
}
if (rval == QLA_SUCCESS) {
- dmp_reg = (uint16_t __iomem *)(reg + 0);
+ dmp_reg = &reg->flash_address;
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+ dmp_reg = &reg->u.isp2100.mailbox0;
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
- if (cnt == 8) {
- dmp_reg = (uint16_t __iomem *)
- ((uint8_t __iomem *)reg + 0xe0);
- }
+ if (cnt == 8)
+ dmp_reg = &reg->u_end.isp2200.mailbox8;
+
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
}
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
+ dmp_reg = &reg->u.isp2100.unused_2[0];
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+ dmp_reg = &reg->risc_hw;
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
WRT_REG_WORD(&reg->pcr, 0x2100);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
WRT_REG_WORD(&reg->pcr, 0x2200);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
WRT_REG_WORD(&reg->pcr, 0x2300);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
WRT_REG_WORD(&reg->pcr, 0x2400);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
WRT_REG_WORD(&reg->pcr, 0x2500);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
WRT_REG_WORD(&reg->pcr, 0x2600);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
WRT_REG_WORD(&reg->pcr, 0x2700);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x10);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] =
- htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x20);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x30);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
/* Reset the ISP. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -750,7 +796,6 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
int rval;
uint32_t cnt;
uint32_t risc_address;
- uint16_t mb0, wd;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
@@ -782,547 +827,198 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
fw = &ha->fw_dump->isp.isp24;
qla2xxx_prep_dump(ha, ha->fw_dump);
- rval = QLA_SUCCESS;
fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
- if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
- HCCRX_CLR_HOST_INT);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
- for (cnt = 30000;
- (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Host interface registers. */
- dmp_reg = (uint32_t __iomem *)(reg + 0);
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Disable interrupts. */
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
-
- /* Shadow registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- RD_REG_DWORD(&reg->iobase_addr);
- WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- /* Mailbox registers. */
- mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
- /* Transfer sequence registers. */
- iter_reg = fw->xseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
- fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive sequence registers. */
- iter_reg = fw->rseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
- fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Command DMA registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Queues. */
- iter_reg = fw->req0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->resp0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->req1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Transmit DMA registers. */
- iter_reg = fw->xmt0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt2_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt3_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt4_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] =
- htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive DMA registers. */
- iter_reg = fw->rcvt0_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rcvt1_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* RISC registers. */
- iter_reg = fw->risc_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Local memory controller registers. */
- iter_reg = fw->lmc_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Fibre Protocol Module registers. */
- iter_reg = fw->fpm_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Frame Buffer registers. */
- iter_reg = fw->fb_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Reset RISC. */
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_DMA_ACTIVE) == 0)
- break;
-
- udelay(10);
- }
-
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
- udelay(100);
- /* Wait for firmware to complete NVRAM accesses. */
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb0; cnt--) {
- udelay(5);
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- barrier();
- }
-
- /* Wait for soft-reset to complete. */
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_ISP_SOFT_RESET) == 0)
- break;
-
- udelay(10);
- }
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- }
-
- for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
-
- if (rval == QLA_SUCCESS)
- rval = qla2xxx_dump_memory(ha, fw->code_ram,
- sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
- if (rval == QLA_SUCCESS) {
- nxt = qla2xxx_copy_queues(ha, nxt);
- if (ha->eft)
- memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
- }
-
+ rval = qla24xx_pause_risc(reg);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ /* Host interface registers. */
+ dmp_reg = &reg->flash_addr;
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg);
+ qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg);
+ qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+ qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+ /* Command DMA registers. */
+ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+ iter_reg = fw->xmt1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+ iter_reg = fw->xmt2_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+ iter_reg = fw->xmt3_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+ iter_reg = fw->xmt4_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+ qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+ qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+ qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+
+ rval = qla24xx_soft_reset(ha);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+ fw->ext_mem, &nxt);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla24xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -1346,7 +1042,6 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
int rval;
uint32_t cnt;
uint32_t risc_address;
- uint16_t mb0, wd;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
@@ -1377,655 +1072,260 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
}
fw = &ha->fw_dump->isp.isp25;
qla2xxx_prep_dump(ha, ha->fw_dump);
+ ha->fw_dump->version = __constant_htonl(2);
- rval = QLA_SUCCESS;
fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
- if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
- HCCRX_CLR_HOST_INT);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
- for (cnt = 30000;
- (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Host interface registers. */
- dmp_reg = (uint32_t __iomem *)(reg + 0);
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Disable interrupts. */
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
-
- /* Shadow registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- RD_REG_DWORD(&reg->iobase_addr);
- WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
- fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
- fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
- fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
- fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- /* RISC I/O register. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
- RD_REG_DWORD(&reg->iobase_addr);
- fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
-
- /* Mailbox registers. */
- mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
- /* Transfer sequence registers. */
- iter_reg = fw->xseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive sequence registers. */
- iter_reg = fw->rseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Auxiliary sequence registers. */
- iter_reg = fw->aseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->aseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
- fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
- fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Command DMA registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Queues. */
- iter_reg = fw->req0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->resp0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->req1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Transmit DMA registers. */
- iter_reg = fw->xmt0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt2_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt3_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt4_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] =
- htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive DMA registers. */
- iter_reg = fw->rcvt0_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rcvt1_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* RISC registers. */
- iter_reg = fw->risc_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Local memory controller registers. */
- iter_reg = fw->lmc_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Fibre Protocol Module registers. */
- iter_reg = fw->fpm_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Frame Buffer registers. */
- iter_reg = fw->fb_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Reset RISC. */
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_DMA_ACTIVE) == 0)
- break;
-
- udelay(10);
- }
-
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
- udelay(100);
- /* Wait for firmware to complete NVRAM accesses. */
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb0; cnt--) {
- udelay(5);
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- barrier();
- }
-
- /* Wait for soft-reset to complete. */
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_ISP_SOFT_RESET) == 0)
- break;
-
- udelay(10);
- }
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- }
-
- for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
-
- if (rval == QLA_SUCCESS)
- rval = qla2xxx_dump_memory(ha, fw->code_ram,
- sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
- if (rval == QLA_SUCCESS) {
- nxt = qla2xxx_copy_queues(ha, nxt);
- if (ha->eft)
- memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
- }
-
+ rval = qla24xx_pause_risc(reg);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ /* Host/Risc registers. */
+ iter_reg = fw->host_risc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7010, 16, iter_reg);
+
+ /* PCIe registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_window, 0x01);
+ dmp_reg = &reg->iobase_c4;
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
+ fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
+ WRT_REG_DWORD(&reg->iobase_window, 0x00);
+ RD_REG_DWORD(&reg->iobase_window);
+
+ /* Host interface registers. */
+ dmp_reg = &reg->flash_addr;
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+ fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+ fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+ fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+ fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* RISC I/O register. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+ fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+ iter_reg = fw->xseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+ iter_reg = fw->rseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+ qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+ /* Auxiliary sequence registers. */
+ iter_reg = fw->aseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB070, 16, iter_reg);
+
+ iter_reg = fw->aseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
+ qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
+
+ /* Command DMA registers. */
+ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+ iter_reg = fw->xmt1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+ iter_reg = fw->xmt2_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+ iter_reg = fw->xmt3_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+ iter_reg = fw->xmt4_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+ qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+ qla24xx_read_window(reg, 0x3070, 16, iter_reg);
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+
+ rval = qla24xx_soft_reset(ha);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+ fw->ext_mem, &nxt);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla25xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -2102,7 +1402,7 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
struct scsi_qla_host *ha;
srb_t *sp;
- ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
+ ha = shost_priv(cmd->device->host);
sp = (srb_t *) cmd->SCp.ptr;
printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index cca4b0d8253..a50ecf0b7c8 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -215,6 +215,8 @@ struct qla24xx_fw_dump {
struct qla25xx_fw_dump {
uint32_t host_status;
+ uint32_t host_risc_reg[32];
+ uint32_t pcie_regs[4];
uint32_t host_reg[32];
uint32_t shadow_reg[11];
uint32_t risc_io_reg;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c1964866a42..1900fbf6cd7 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
+#include <linux/aer.h>
#include <asm/semaphore.h>
#include <scsi/scsi.h>
@@ -184,8 +185,6 @@
* SCSI Request Block
*/
typedef struct srb {
- struct list_head list;
-
struct scsi_qla_host *ha; /* HA the SP is queued on */
struct fc_port *fcport;
@@ -316,7 +315,9 @@ struct device_reg_2xxx {
} u;
uint16_t fpm_diag_config;
- uint16_t unused_5[0x6]; /* Gap */
+ uint16_t unused_5[0x4]; /* Gap */
+ uint16_t risc_hw;
+ uint16_t unused_5_1; /* Gap */
uint16_t pcr; /* Processor Control Register. */
uint16_t unused_6[0x5]; /* Gap */
uint16_t mctr; /* Memory Configuration and Timing. */
@@ -1702,7 +1703,7 @@ struct ct_fdmi_hba_attributes {
/*
* Port attribute types.
*/
-#define FDMI_PORT_ATTR_COUNT 5
+#define FDMI_PORT_ATTR_COUNT 6
#define FDMI_PORT_FC4_TYPES 1
#define FDMI_PORT_SUPPORT_SPEED 2
#define FDMI_PORT_CURRENT_SPEED 3
@@ -2476,6 +2477,8 @@ typedef struct scsi_qla_host {
#define QLA_SWAITING 0
#define QLA_SREADING 1
#define QLA_SWRITING 2
+ uint32_t optrom_region_start;
+ uint32_t optrom_region_size;
/* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0
@@ -2529,7 +2532,7 @@ typedef struct scsi_qla_host {
#define VP_ERR_FAB_NORESOURCES 3
#define VP_ERR_FAB_LOGOUT 4
#define VP_ERR_ADAP_NORESOURCES 5
- int max_npiv_vports; /* 63 or 125 per topoloty */
+ uint16_t max_npiv_vports; /* 63 or 125 per topoloty */
int cur_vport_count;
} scsi_qla_host_t;
@@ -2542,8 +2545,6 @@ typedef struct scsi_qla_host {
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
atomic_read(&ha->loop_state) == LOOP_DOWN)
-#define to_qla_host(x) ((scsi_qla_host_t *) (x)->hostdata)
-
#define qla_printk(level, ha, format, arg...) \
dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 99fe49618d6..25364b1aaf1 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -779,6 +779,8 @@ struct device_reg_24xx {
#define FA_NVRAM_VPD_SIZE 0x200
#define FA_NVRAM_VPD0_ADDR 0x00
#define FA_NVRAM_VPD1_ADDR 0x100
+
+#define FA_BOOT_CODE_ADDR 0x00000
/*
* RISC code begins at offset 512KB
* within flash. Consisting of two
@@ -940,7 +942,9 @@ struct device_reg_24xx {
uint16_t mailbox31;
uint32_t iobase_window;
- uint32_t unused_4[8]; /* Gap. */
+ uint32_t iobase_c4;
+ uint32_t iobase_c8;
+ uint32_t unused_4_1[6]; /* Gap. */
uint32_t iobase_q;
uint32_t unused_5[2]; /* Gap. */
uint32_t iobase_select;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index aa1e4115228..09cb2a90805 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -134,6 +134,9 @@ extern int
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
extern int
+qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+
+extern int
qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
extern void
@@ -212,8 +215,8 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
- uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
+ uint16_t *, uint16_t *, uint16_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -302,6 +305,8 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
+extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+ uint32_t, uint32_t);
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index a7e23583f89..eb0784c9ff8 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1517,7 +1517,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Attributes */
ct_req->req.rpa.attrs.count =
- __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
+ __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1);
entries = ct_req->req.rpa.port_name;
/* FC4 types. */
@@ -1600,7 +1600,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* OS device name. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
- sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no);
+ strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME);
alen = strlen(eiter->a.os_dev_name);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
@@ -1611,6 +1611,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Hostname. */
if (strlen(fc_host_system_hostname(ha->host))) {
+ ct_req->req.rpa.attrs.count =
+ __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 1a058ec9bd0..191dafd89be 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -849,7 +849,8 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
return;
/* Retrieve IOCB counts available to the firmware. */
- rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
+ rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt,
+ &ha->max_npiv_vports);
if (rval)
return;
/* No point in continuing if current settings are sufficient. */
@@ -916,9 +917,15 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
ha->flags.npiv_supported = 0;
- if (IS_QLA24XX(ha) &&
- (ha->fw_attributes & BIT_2))
+ if ((IS_QLA24XX(ha) || IS_QLA25XX(ha)) &&
+ (ha->fw_attributes & BIT_2)) {
ha->flags.npiv_supported = 1;
+ if ((!ha->max_npiv_vports) ||
+ ((ha->max_npiv_vports + 1) %
+ MAX_MULTI_ID_FABRIC))
+ ha->max_npiv_vports =
+ MAX_NUM_VPORT_FABRIC;
+ }
if (ql2xallocfwdump)
qla2x00_alloc_fw_dump(ha);
@@ -1155,8 +1162,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
- mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
- ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+ mid_init_cb->count = ha->max_npiv_vports;
rval = qla2x00_init_firmware(ha, ha->init_cb_size);
if (rval) {
@@ -1786,12 +1792,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
{
fc_port_t *fcport;
- fcport = kmalloc(sizeof(fc_port_t), flags);
- if (fcport == NULL)
- return (fcport);
+ fcport = kzalloc(sizeof(fc_port_t), flags);
+ if (!fcport)
+ return NULL;
/* Setup fcport template structure. */
- memset(fcport, 0, sizeof (fc_port_t));
fcport->ha = ha;
fcport->vp_idx = ha->vp_idx;
fcport->port_type = FCT_UNKNOWN;
@@ -1801,7 +1806,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
fcport->supported_classes = FC_COS_UNSPECIFIED;
spin_lock_init(&fcport->rport_lock);
- return (fcport);
+ return fcport;
}
/*
@@ -2127,15 +2132,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
if (!IS_IIDMA_CAPABLE(ha))
return;
- if (fcport->fp_speed == PORT_SPEED_UNKNOWN) {
- DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
- "unsupported FM port operating speed.\n",
- ha->host_no, fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7]));
+ if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
+ fcport->fp_speed > ha->link_data_rate)
return;
- }
rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed,
mb);
@@ -2473,13 +2472,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
rval = QLA_SUCCESS;
/* Try GID_PT to get device list, else GAN. */
- swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
- if (swl == NULL) {
+ swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC);
+ if (!swl) {
/*EMPTY*/
DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
"on GA_NXT\n", ha->host_no));
} else {
- memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
kfree(swl);
swl = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 3a5e78cb6b3..7f6a89bd94f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -308,7 +308,7 @@ qla2x00_start_scsi(srb_t *sp)
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
- if (ha->outstanding_cmds[handle] == 0)
+ if (!ha->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
@@ -711,7 +711,7 @@ qla24xx_start_scsi(srb_t *sp)
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
- if (ha->outstanding_cmds[handle] == 0)
+ if (!ha->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index eecae9905ec..c4768c4f399 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -6,6 +6,7 @@
*/
#include "qla_def.h"
+#include <linux/delay.h>
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
@@ -34,6 +35,7 @@ qla2100_intr_handler(int irq, void *dev_id)
int status;
unsigned long flags;
unsigned long iter;
+ uint16_t hccr;
uint16_t mb[4];
ha = (scsi_qla_host_t *) dev_id;
@@ -48,7 +50,23 @@ qla2100_intr_handler(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
for (iter = 50; iter--; ) {
- if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
+ hccr = RD_REG_WORD(&reg->hccr);
+ if (hccr & HCCR_RISC_PAUSE) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
+ /*
+ * Issue a "HARD" reset in order for the RISC interrupt
+ * bit to be cleared. Schedule a big hammmer to get
+ * out of the RISC PAUSED state.
+ */
+ WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+ RD_REG_WORD(&reg->hccr);
+
+ ha->isp_ops->fw_dump(ha, 1);
+ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ break;
+ } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
break;
if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
@@ -127,6 +145,9 @@ qla2300_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
if (stat & HSR_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_WORD(&reg->hccr);
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
qla_printk(KERN_INFO, ha, "Parity error -- "
@@ -1464,6 +1485,52 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);
}
+static void
+qla2xxx_check_risc_status(scsi_qla_host_t *ha)
+{
+ int rval;
+ uint32_t cnt;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ if (!IS_QLA25XX(ha))
+ return;
+
+ rval = QLA_SUCCESS;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+ for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt) {
+ WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+ udelay(10);
+ } else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+ if (rval == QLA_SUCCESS)
+ goto next_test;
+
+ WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+ for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt) {
+ WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+ udelay(10);
+ } else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+ if (rval != QLA_SUCCESS)
+ goto done;
+
+next_test:
+ if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
+ qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+
+done:
+ WRT_REG_DWORD(&reg->iobase_window, 0x0000);
+ RD_REG_DWORD(&reg->iobase_window);
+}
+
/**
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
@@ -1499,10 +1566,16 @@ qla24xx_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
+
+ qla2xxx_check_risc_status(ha);
+
ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
@@ -1606,7 +1679,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
qla24xx_process_response_queue(ha);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD_RELAXED(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1620,7 +1692,6 @@ qla24xx_msix_default(int irq, void *dev_id)
struct device_reg_24xx __iomem *reg;
int status;
unsigned long flags;
- unsigned long iter;
uint32_t stat;
uint32_t hccr;
uint16_t mb[4];
@@ -1630,13 +1701,19 @@ qla24xx_msix_default(int irq, void *dev_id)
status = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (iter = 50; iter--; ) {
+ do {
stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
+
+ qla2xxx_check_risc_status(ha);
+
ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
@@ -1669,8 +1746,7 @@ qla24xx_msix_default(int irq, void *dev_id)
break;
}
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD_RELAXED(&reg->hccr);
- }
+ } while (0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d3746ec80a8..c53ec67c47f 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -391,7 +391,8 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
- mcp->out_mb |= MBX_3|MBX_2|MBX_1;
+ mcp->mb[4] = 0;
+ mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
mcp->in_mb |= MBX_1;
} else {
mcp->mb[1] = LSW(risc_addr);
@@ -1919,7 +1920,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
*/
int
qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
- uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt)
+ uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
+ uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports)
{
int rval;
mbx_cmd_t mc;
@@ -1929,7 +1931,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
- mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
@@ -1940,9 +1942,9 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
ha->host_no, mcp->mb[0]));
} else {
DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
- "mb7=%x mb10=%x.\n", __func__, ha->host_no,
+ "mb7=%x mb10=%x mb11=%x.\n", __func__, ha->host_no,
mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7],
- mcp->mb[10]));
+ mcp->mb[10], mcp->mb[11]));
if (cur_xchg_cnt)
*cur_xchg_cnt = mcp->mb[3];
@@ -1952,6 +1954,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
*cur_iocb_cnt = mcp->mb[7];
if (orig_iocb_cnt)
*orig_iocb_cnt = mcp->mb[10];
+ if (max_npiv_vports)
+ *max_npiv_vports = mcp->mb[11];
}
return (rval);
@@ -2980,3 +2984,51 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
return rval;
}
+
+int
+qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr,
+ uint32_t size)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ if (MSW(addr) || IS_FWI2_CAPABLE(ha)) {
+ mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
+ mcp->mb[8] = MSW(addr);
+ mcp->out_mb = MBX_8|MBX_0;
+ } else {
+ mcp->mb[0] = MBC_DUMP_RISC_RAM;
+ mcp->out_mb = MBX_0;
+ }
+ mcp->mb[1] = LSW(addr);
+ mcp->mb[2] = MSW(req_dma);
+ mcp->mb[3] = LSW(req_dma);
+ mcp->mb[6] = MSW(MSD(req_dma));
+ mcp->mb[7] = LSW(MSD(req_dma));
+ mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
+ if (IS_FWI2_CAPABLE(ha)) {
+ mcp->mb[4] = MSW(size);
+ mcp->mb[5] = LSW(size);
+ mcp->out_mb |= MBX_5|MBX_4;
+ } else {
+ mcp->mb[4] = LSW(size);
+ mcp->out_mb |= MBX_4;
+ }
+
+ mcp->in_mb = MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+ ha->host_no, rval, mcp->mb[0]));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 54dc415d8b5..821ee74aadc 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -104,7 +104,7 @@ qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
*
* Context:
*/
-void
+static void
qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
{
fc_port_t *fcport;
@@ -179,37 +179,7 @@ enable_failed:
return 1;
}
-/**
- * qla24xx_modify_vport() - Modifies the virtual fabric port's configuration
- * @ha: HA context
- * @vp: pointer to buffer of virtual port parameters.
- * @ret_code: return error code:
- *
- * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
- */
-uint32_t
-qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
-{
- scsi_qla_host_t *vha;
-
- vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
- if (!vha) {
- *vp_id = MAX_NUM_VPORT_LOOP;
- return VP_RET_CODE_WWPN;
- }
-
- if (qla24xx_enable_vp(vha)) {
- scsi_host_put(vha->host);
- qla2x00_mem_free(vha);
- *vp_id = MAX_NUM_VPORT_LOOP;
- return VP_RET_CODE_RESOURCES;
- }
-
- *vp_id = vha->vp_idx;
- return VP_RET_CODE_OK;
-}
-
-void
+static void
qla24xx_configure_vp(scsi_qla_host_t *vha)
{
struct fc_vport *fc_vport;
@@ -363,7 +333,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
int
qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
uint8_t port_name[WWN_SIZE];
@@ -397,7 +367,7 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
scsi_qla_host_t *
qla24xx_create_vhost(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
struct Scsi_Host *host;
@@ -409,7 +379,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
return(NULL);
}
- vha = (scsi_qla_host_t *)host->hostdata;
+ vha = shost_priv(host);
/* clone the parent hba */
memcpy(vha, ha, sizeof (scsi_qla_host_t));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index acca898ce0a..a6bb8d0ecf1 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -379,12 +379,17 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
static int
qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
@@ -440,13 +445,18 @@ qc_fail_command:
static int
qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
scsi_qla_host_t *pha = to_qla_parent(ha);
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc24_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
@@ -653,7 +663,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
static int
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
srb_t *sp;
int ret, i;
unsigned int id, lun;
@@ -793,7 +803,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
static int
qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
unsigned int id, lun;
@@ -922,7 +932,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
@@ -982,7 +992,7 @@ eh_bus_reset_done:
static int
qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
unsigned int id, lun;
@@ -1132,7 +1142,7 @@ qla2xxx_slave_alloc(struct scsi_device *sdev)
static int
qla2xxx_slave_configure(struct scsi_device *sdev)
{
- scsi_qla_host_t *ha = to_qla_host(sdev->host);
+ scsi_qla_host_t *ha = shost_priv(sdev->host);
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
@@ -1384,7 +1394,7 @@ static struct isp_operations qla25xx_isp_ops = {
.beacon_on = qla24xx_beacon_on,
.beacon_off = qla24xx_beacon_off,
.beacon_blink = qla24xx_beacon_blink,
- .read_optrom = qla24xx_read_optrom_data,
+ .read_optrom = qla25xx_read_optrom_data,
.write_optrom = qla24xx_write_optrom_data,
.get_flash_version = qla24xx_get_flash_version,
};
@@ -1533,7 +1543,7 @@ iospace_error_exit:
static void
qla2xxx_scan_start(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -1543,7 +1553,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
static int
qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(shost);
if (!ha->host)
return 1;
@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (pci_enable_device(pdev))
goto probe_out;
+ if (pci_find_aer_capability(pdev))
+ if (pci_enable_pcie_error_reporting(pdev))
+ goto probe_out;
+
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
@@ -1586,7 +1600,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Clear our data area */
- ha = (scsi_qla_host_t *)host->hostdata;
+ ha = shost_priv(host);
memset(ha, 0, sizeof(scsi_qla_host_t));
ha->pdev = pdev;
@@ -2423,7 +2437,6 @@ qla2x00_do_dpc(void *data)
if (atomic_read(&fcport->state) != FCS_ONLINE &&
fcport->login_retry) {
- fcport->login_retry--;
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags &
FCF_TAPE_PRESENT)
@@ -2439,6 +2452,7 @@ qla2x00_do_dpc(void *data)
qla2x00_local_device_login(
ha, fcport);
+ fcport->login_retry--;
if (status == QLA_SUCCESS) {
fcport->old_loop_id = fcport->loop_id;
@@ -2456,6 +2470,8 @@ qla2x00_do_dpc(void *data)
} else {
fcport->login_retry = 0;
}
+ if (fcport->login_retry == 0)
+ fcport->loop_id = FC_NO_LOOP_ID;
}
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2814,6 +2830,105 @@ qla2x00_release_firmware(void)
up(&qla_fw_lock);
}
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ switch (state) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ pci_disable_device(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ qla2x00_remove_one(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ int risc_paused = 0;
+ uint32_t stat;
+ unsigned long flags;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+ stat = RD_REG_DWORD(&reg->hccr);
+ if (stat & HCCR_RISC_PAUSE)
+ risc_paused = 1;
+ } else if (IS_QLA23XX(ha)) {
+ stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+ if (stat & HSR_RISC_PAUSED)
+ risc_paused = 1;
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ stat = RD_REG_DWORD(&reg24->host_status);
+ if (stat & HSRX_RISC_PAUSED)
+ risc_paused = 1;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (risc_paused) {
+ qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+ "Dumping firmware!\n");
+ ha->isp_ops->fw_dump(ha, 0);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+ } else
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+ pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+ if (pci_enable_device(pdev)) {
+ qla_printk(KERN_WARNING, ha,
+ "Can't re-enable PCI device after reset.\n");
+
+ return ret;
+ }
+ pci_set_master(pdev);
+
+ if (ha->isp_ops->pci_config(ha))
+ return ret;
+
+ set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+ ret = PCI_ERS_RESULT_RECOVERED;
+ clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+ return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ int ret;
+
+ ret = qla2x00_wait_for_hba_online(ha);
+ if (ret != QLA_SUCCESS) {
+ qla_printk(KERN_ERR, ha,
+ "the device failed to resume I/O "
+ "from slot/link_reset");
+ }
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+ .error_detected = qla2xxx_pci_error_detected,
+ .mmio_enabled = qla2xxx_pci_mmio_enabled,
+ .slot_reset = qla2xxx_pci_slot_reset,
+ .resume = qla2xxx_pci_resume,
+};
+
static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2839,6 +2954,7 @@ static struct pci_driver qla2xxx_pci_driver = {
.id_table = qla2xxx_pci_tbl,
.probe = qla2x00_probe_one,
.remove = __devexit_p(qla2x00_remove_one),
+ .err_handler = &qla2xxx_err_handler,
};
/**
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index a925a3f179f..40b059fc198 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -425,6 +425,9 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat)
/* Flash Manipulation Routines */
/*****************************************************************************/
+#define OPTROM_BURST_SIZE 0x1000
+#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
+
static inline uint32_t
flash_conf_to_access_addr(uint32_t faddr)
{
@@ -544,41 +547,59 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
int ret;
- uint32_t liter;
- uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask;
+ uint32_t liter, miter;
+ uint32_t sec_mask, rest_addr, conf_addr;
uint32_t fdata, findex ;
uint8_t man_id, flash_id;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ dma_addr_t optrom_dma;
+ void *optrom = NULL;
+ uint32_t *s, *d;
ret = QLA_SUCCESS;
+ /* Prepare burst-capable write on supported ISPs. */
+ if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&
+ dwords > OPTROM_BURST_DWORDS) {
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ qla_printk(KERN_DEBUG, ha,
+ "Unable to allocate memory for optrom burst write "
+ "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+ }
+ }
+
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
ha->host_no, man_id, flash_id));
- sec_end_mask = 0;
conf_addr = flash_conf_to_access_addr(0x03d8);
switch (man_id) {
case 0xbf: /* STT flash. */
- rest_addr = 0x1fff;
- sec_mask = 0x3e000;
+ if (flash_id == 0x8e) {
+ rest_addr = 0x3fff;
+ sec_mask = 0x7c000;
+ } else {
+ rest_addr = 0x1fff;
+ sec_mask = 0x7e000;
+ }
if (flash_id == 0x80)
conf_addr = flash_conf_to_access_addr(0x0352);
break;
case 0x13: /* ST M25P80. */
rest_addr = 0x3fff;
- sec_mask = 0x3c000;
+ sec_mask = 0x7c000;
break;
case 0x1f: // Atmel 26DF081A
- rest_addr = 0x0fff;
- sec_mask = 0xff000;
- sec_end_mask = 0x003ff;
+ rest_addr = 0x3fff;
+ sec_mask = 0x7c000;
conf_addr = flash_conf_to_access_addr(0x0320);
break;
default:
/* Default to 64 kb sector size. */
rest_addr = 0x3fff;
- sec_mask = 0x3c000;
+ sec_mask = 0x7c000;
break;
}
@@ -592,56 +613,81 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
/* Some flash parts need an additional zero-write to clear bits.*/
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
- do { /* Loop once to provide quick error exit. */
- for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
- if (man_id == 0x1f) {
- findex = faddr << 2;
- fdata = findex & sec_mask;
- } else {
- findex = faddr;
- fdata = (findex & sec_mask) << 2;
- }
+ for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
+ if (man_id == 0x1f) {
+ findex = faddr << 2;
+ fdata = findex & sec_mask;
+ } else {
+ findex = faddr;
+ fdata = (findex & sec_mask) << 2;
+ }
- /* Are we at the beginning of a sector? */
- if ((findex & rest_addr) == 0) {
- /*
- * Do sector unprotect at 4K boundry for Atmel
- * part.
- */
- if (man_id == 0x1f)
- qla24xx_write_flash_dword(ha,
- flash_conf_to_access_addr(0x0339),
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
- ret = qla24xx_write_flash_dword(ha, conf_addr,
- (fdata & 0xff00) |((fdata << 16) &
+ /* Are we at the beginning of a sector? */
+ if ((findex & rest_addr) == 0) {
+ /* Do sector unprotect at 4K boundry for Atmel part. */
+ if (man_id == 0x1f)
+ qla24xx_write_flash_dword(ha,
+ flash_conf_to_access_addr(0x0339),
+ (fdata & 0xff00) | ((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff));
- if (ret != QLA_SUCCESS) {
- DEBUG9(printk("%s(%ld) Unable to flash "
- "sector: address=%x.\n", __func__,
- ha->host_no, faddr));
- break;
- }
+ ret = qla24xx_write_flash_dword(ha, conf_addr,
+ (fdata & 0xff00) |((fdata << 16) &
+ 0xff0000) | ((fdata >> 16) & 0xff));
+ if (ret != QLA_SUCCESS) {
+ DEBUG9(printk("%s(%ld) Unable to flash "
+ "sector: address=%x.\n", __func__,
+ ha->host_no, faddr));
+ break;
}
- ret = qla24xx_write_flash_dword(ha,
+ }
+
+ /* Go with burst-write. */
+ if (optrom && (liter + OPTROM_BURST_DWORDS) < dwords) {
+ /* Copy data to DMA'ble buffer. */
+ for (miter = 0, s = optrom, d = dwptr;
+ miter < OPTROM_BURST_DWORDS; miter++, s++, d++)
+ *s = cpu_to_le32(*d);
+
+ ret = qla2x00_load_ram(ha, optrom_dma,
flash_data_to_access_addr(faddr),
- cpu_to_le32(*dwptr));
+ OPTROM_BURST_DWORDS);
if (ret != QLA_SUCCESS) {
- DEBUG9(printk("%s(%ld) Unable to program flash "
- "address=%x data=%x.\n", __func__,
- ha->host_no, faddr, *dwptr));
- break;
+ qla_printk(KERN_WARNING, ha,
+ "Unable to burst-write optrom segment "
+ "(%x/%x/%llx).\n", ret,
+ flash_data_to_access_addr(faddr),
+ optrom_dma);
+ qla_printk(KERN_WARNING, ha,
+ "Reverting to slow-write.\n");
+
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+ optrom = NULL;
+ } else {
+ liter += OPTROM_BURST_DWORDS - 1;
+ faddr += OPTROM_BURST_DWORDS - 1;
+ dwptr += OPTROM_BURST_DWORDS - 1;
+ continue;
}
+ }
- /* Do sector protect at 4K boundry for Atmel part. */
- if (man_id == 0x1f &&
- ((faddr & sec_end_mask) == 0x3ff))
- qla24xx_write_flash_dword(ha,
- flash_conf_to_access_addr(0x0336),
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
+ ret = qla24xx_write_flash_dword(ha,
+ flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr));
+ if (ret != QLA_SUCCESS) {
+ DEBUG9(printk("%s(%ld) Unable to program flash "
+ "address=%x data=%x.\n", __func__,
+ ha->host_no, faddr, *dwptr));
+ break;
}
- } while (0);
+
+ /* Do sector protect at 4K boundry for Atmel part. */
+ if (man_id == 0x1f &&
+ ((faddr & rest_addr) == rest_addr))
+ qla24xx_write_flash_dword(ha,
+ flash_conf_to_access_addr(0x0336),
+ (fdata & 0xff00) | ((fdata << 16) &
+ 0xff0000) | ((fdata >> 16) & 0xff));
+ }
/* Enable flash write-protection. */
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
@@ -651,6 +697,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
+ if (optrom)
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+
return ret;
}
@@ -1728,7 +1778,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */
@@ -1736,7 +1785,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
- ha->isp_ops->enable_intrs(ha);
scsi_unblock_requests(ha->host);
return buf;
@@ -1750,7 +1798,6 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with write. */
@@ -1767,6 +1814,70 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
return rval;
}
+uint8_t *
+qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
+ uint32_t offset, uint32_t length)
+{
+ int rval;
+ dma_addr_t optrom_dma;
+ void *optrom;
+ uint8_t *pbuf;
+ uint32_t faddr, left, burst;
+
+ if (offset & 0xfff)
+ goto slow_read;
+ if (length < OPTROM_BURST_SIZE)
+ goto slow_read;
+
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ qla_printk(KERN_DEBUG, ha,
+ "Unable to allocate memory for optrom burst read "
+ "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+
+ goto slow_read;
+ }
+
+ pbuf = buf;
+ faddr = offset >> 2;
+ left = length >> 2;
+ burst = OPTROM_BURST_DWORDS;
+ while (left != 0) {
+ if (burst > left)
+ burst = left;
+
+ rval = qla2x00_dump_ram(ha, optrom_dma,
+ flash_data_to_access_addr(faddr), burst);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to burst-read optrom segment "
+ "(%x/%x/%llx).\n", rval,
+ flash_data_to_access_addr(faddr), optrom_dma);
+ qla_printk(KERN_WARNING, ha,
+ "Reverting to slow-read.\n");
+
+ dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ optrom, optrom_dma);
+ goto slow_read;
+ }
+
+ memcpy(pbuf, optrom, burst * 4);
+
+ left -= burst;
+ faddr += burst;
+ pbuf += burst * 4;
+ }
+
+ dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+ optrom_dma);
+
+ return buf;
+
+slow_read:
+ return qla24xx_read_optrom_data(ha, buf, offset, length);
+}
+
/**
* qla2x00_get_fcode_version() - Determine an FCODE image's version.
* @ha: HA context
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 18095b9b76f..2d551a3006f 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.00-k3"
+#define QLA2XXX_VERSION "8.02.00-k4"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 94baca840ef..1e874f1fb5c 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -166,6 +166,7 @@ static int qlogicfas_release(struct Scsi_Host *shost)
{
struct qlogicfas408_priv *priv = get_priv_by_host(shost);
+ scsi_remove_host(shost);
if (shost->irq) {
qlogicfas408_disable_ints(priv);
free_irq(shost->irq, shost);
@@ -174,7 +175,6 @@ static int qlogicfas_release(struct Scsi_Host *shost)
free_dma(shost->dma_channel);
if (shost->io_port && shost->n_io_port)
release_region(shost->io_port, shost->n_io_port);
- scsi_remove_host(shost);
scsi_host_put(shost);
return 0;
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 594887205b0..e93f80316a1 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -310,8 +310,6 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
}
qpti->dev_param[i].device_enable = 1;
}
- /* this is very important to set! */
- qpti->sbits = 1 << qpti->scsi_id;
}
static int qlogicpti_reset_hardware(struct Scsi_Host *host)
@@ -951,153 +949,35 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int
host->sg_tablesize = QLOGICPTI_MAX_SG(num_free);
}
-static unsigned int scsi_rbuf_get(struct scsi_cmnd *cmd, unsigned char **buf_out)
+static int qlogicpti_slave_configure(struct scsi_device *sdev)
{
- unsigned char *buf;
- unsigned int buflen;
-
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ struct qlogicpti *qpti = shost_priv(sdev->host);
+ int tgt = sdev->id;
+ u_short param[6];
- sg = (struct scatterlist *) cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- buflen = sg->length;
+ /* tags handled in midlayer */
+ /* enable sync mode? */
+ if (sdev->sdtr) {
+ qpti->dev_param[tgt].device_flags |= 0x10;
} else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
+ qpti->dev_param[tgt].synchronous_offset = 0;
+ qpti->dev_param[tgt].synchronous_period = 0;
}
-
- *buf_out = buf;
- return buflen;
-}
-
-static void scsi_rbuf_put(struct scsi_cmnd *cmd, unsigned char *buf)
-{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
-}
-
-/*
- * Until we scan the entire bus with inquiries, go throught this fella...
- */
-static void ourdone(struct scsi_cmnd *Cmnd)
-{
- struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
- int tgt = Cmnd->device->id;
- void (*done) (struct scsi_cmnd *);
-
- /* This grot added by DaveM, blame him for ugliness.
- * The issue is that in the 2.3.x driver we use the
- * host_scribble portion of the scsi command as a
- * completion linked list at interrupt service time,
- * so we have to store the done function pointer elsewhere.
- */
- done = (void (*)(struct scsi_cmnd *))
- (((unsigned long) Cmnd->SCp.Message)
-#ifdef __sparc_v9__
- | ((unsigned long) Cmnd->SCp.Status << 32UL)
-#endif
- );
-
- if ((qpti->sbits & (1 << tgt)) == 0) {
- int ok = host_byte(Cmnd->result) == DID_OK;
- if (Cmnd->cmnd[0] == 0x12 && ok) {
- unsigned char *iqd;
- unsigned int iqd_len;
-
- iqd_len = scsi_rbuf_get(Cmnd, &iqd);
-
- /* tags handled in midlayer */
- /* enable sync mode? */
- if (iqd[7] & 0x10) {
- qpti->dev_param[tgt].device_flags |= 0x10;
- } else {
- qpti->dev_param[tgt].synchronous_offset = 0;
- qpti->dev_param[tgt].synchronous_period = 0;
- }
- /* are we wide capable? */
- if (iqd[7] & 0x20) {
- qpti->dev_param[tgt].device_flags |= 0x20;
- }
-
- scsi_rbuf_put(Cmnd, iqd);
-
- qpti->sbits |= (1 << tgt);
- } else if (!ok) {
- qpti->sbits |= (1 << tgt);
- }
- }
- done(Cmnd);
-}
-
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *));
-
-static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd,
- void (*done)(struct scsi_cmnd *))
-{
- struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
-
- /*
- * done checking this host adapter?
- * If not, then rewrite the command
- * to finish through ourdone so we
- * can peek at Inquiry data results.
- */
- if (qpti->sbits && qpti->sbits != 0xffff) {
- /* See above about in ourdone this ugliness... */
- Cmnd->SCp.Message = ((unsigned long)done) & 0xffffffff;
-#ifdef CONFIG_SPARC64
- Cmnd->SCp.Status = ((unsigned long)done >> 32UL) & 0xffffffff;
-#endif
- return qlogicpti_queuecommand(Cmnd, ourdone);
- }
-
- /*
- * We've peeked at all targets for this bus- time
- * to set parameters for devices for real now.
- */
- if (qpti->sbits == 0xffff) {
- int i;
- for(i = 0; i < MAX_TARGETS; i++) {
- u_short param[6];
- param[0] = MBOX_SET_TARGET_PARAMS;
- param[1] = (i << 8);
- param[2] = (qpti->dev_param[i].device_flags << 8);
- if (qpti->dev_param[i].device_flags & 0x10) {
- param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
- qpti->dev_param[i].synchronous_period;
- } else {
- param[3] = 0;
- }
- (void) qlogicpti_mbox_command(qpti, param, 0);
- }
- /*
- * set to zero so any traverse through ourdone
- * doesn't start the whole process again,
- */
- qpti->sbits = 0;
- }
-
- /* check to see if we're done with all adapters... */
- for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
- if (qpti->sbits) {
- break;
- }
+ /* are we wide capable? */
+ if (sdev->wdtr)
+ qpti->dev_param[tgt].device_flags |= 0x20;
+
+ param[0] = MBOX_SET_TARGET_PARAMS;
+ param[1] = (tgt << 8);
+ param[2] = (qpti->dev_param[tgt].device_flags << 8);
+ if (qpti->dev_param[tgt].device_flags & 0x10) {
+ param[3] = (qpti->dev_param[tgt].synchronous_offset << 8) |
+ qpti->dev_param[tgt].synchronous_period;
+ } else {
+ param[3] = 0;
}
-
- /*
- * if we hit the end of the chain w/o finding adapters still
- * capability-configuring, then we're done with all adapters
- * and can rock on..
- */
- if (qpti == NULL)
- Cmnd->device->host->hostt->queuecommand = qlogicpti_queuecommand;
-
- return qlogicpti_queuecommand(Cmnd, done);
+ qlogicpti_mbox_command(qpti, param, 0);
+ return 0;
}
/*
@@ -1390,7 +1270,8 @@ static struct scsi_host_template qpti_template = {
.module = THIS_MODULE,
.name = "qlogicpti",
.info = qlogicpti_info,
- .queuecommand = qlogicpti_queuecommand_slow,
+ .queuecommand = qlogicpti_queuecommand,
+ .slave_configure = qlogicpti_slave_configure,
.eh_abort_handler = qlogicpti_abort,
.eh_bus_reset_handler = qlogicpti_reset,
.can_queue = QLOGICPTI_REQ_QUEUE_LEN,
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index 6cd1c0771d2..ef6da2df584 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -380,8 +380,7 @@ struct qlogicpti {
unsigned char swsreg;
unsigned int
gotirq : 1, /* this instance got an irq */
- is_pti : 1, /* Non-zero if this is a PTI board. */
- sbits : 16; /* syncmode known bits */
+ is_pti : 1; /* Non-zero if this is a PTI board. */
};
/* How to twiddle them bits... */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a5de1a829a7..19294882245 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -59,6 +59,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
@@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd)
scsi_print_command(cmd);
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
- " done = 0x%p, queuecommand 0x%p\n",
+ " queuecommand 0x%p\n",
scsi_sglist(cmd), scsi_bufflen(cmd),
- cmd->done,
cmd->device->host->hostt->queuecommand);
}
@@ -442,7 +442,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
#endif
/*
- * Assign a serial number and pid to the request for error recovery
+ * Assign a serial number to the request for error recovery
* and debugging purposes. Protected by the Host_Lock of host.
*/
static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
@@ -450,10 +450,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
cmd->serial_number = host->cmd_serial_number++;
if (cmd->serial_number == 0)
cmd->serial_number = host->cmd_serial_number++;
-
- cmd->pid = host->cmd_pid++;
- if (cmd->pid == 0)
- cmd->pid = host->cmd_pid++;
}
/*
@@ -658,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd)
blk_complete_request(rq);
}
+/* Move this to a header if it becomes more generally useful */
+static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+{
+ return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+}
+
/*
* Function: scsi_finish_command
*
@@ -669,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
{
struct scsi_device *sdev = cmd->device;
struct Scsi_Host *shost = sdev->host;
+ struct scsi_driver *drv;
+ unsigned int good_bytes;
scsi_device_unbusy(sdev);
@@ -694,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- cmd->done(cmd);
+ good_bytes = cmd->request_bufflen;
+ if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+ drv = scsi_cmd_to_driver(cmd);
+ if (drv->done)
+ good_bytes = drv->done(cmd);
+ }
+ scsi_io_completion(cmd, good_bytes);
}
EXPORT_SYMBOL(scsi_finish_command);
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index e2ea739e33d..348cc5a6e3c 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -214,6 +214,7 @@ static struct {
{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"Promise", "", NULL, BLIST_SPARSELUN},
+ {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
{"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8a525abda30..d29f8464b74 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -37,6 +37,7 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+#include "scsi_transport_api.h"
#define SENSE_TIMEOUT (10*HZ)
@@ -589,39 +590,23 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
}
/**
- * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory
* @scmd: SCSI command structure to hijack
- * @cmnd: CDB to send
+ * @ses: structure to save restore information
+ * @cmnd: CDB to send. Can be NULL if no new cmnd is needed
* @cmnd_size: size in bytes of @cmnd
- * @timeout: timeout for this request
- * @copy_sense: request sense data if set to 1
- *
- * This function is used to send a scsi command down to a target device
- * as part of the error recovery process. If @copy_sense is 0 the command
- * sent must be one that does not transfer any data. If @copy_sense is 1
- * the command must be REQUEST_SENSE and this functions copies out the
- * sense buffer it got into @scmd->sense_buffer.
+ * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
*
- * Return value:
- * SUCCESS or FAILED or NEEDS_RETRY
+ * This function is used to save a scsi command information before re-execution
+ * as part of the error recovery process. If @sense_bytes is 0 the command
+ * sent must be one that does not transfer any data. If @sense_bytes != 0
+ * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
+ * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
**/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
- int cmnd_size, int timeout, int copy_sense)
+void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+ unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
{
struct scsi_device *sdev = scmd->device;
- struct Scsi_Host *shost = sdev->host;
- int old_result = scmd->result;
- DECLARE_COMPLETION_ONSTACK(done);
- unsigned long timeleft;
- unsigned long flags;
- struct scatterlist sgl;
- unsigned char old_cmnd[MAX_COMMAND_SIZE];
- enum dma_data_direction old_data_direction;
- unsigned short old_use_sg;
- unsigned char old_cmd_len;
- unsigned old_bufflen;
- void *old_buffer;
- int rtn;
/*
* We need saved copies of a number of fields - this is because
@@ -630,35 +615,42 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
* we will need to restore these values prior to running the actual
* command.
*/
- old_buffer = scmd->request_buffer;
- old_bufflen = scmd->request_bufflen;
- memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
- old_data_direction = scmd->sc_data_direction;
- old_cmd_len = scmd->cmd_len;
- old_use_sg = scmd->use_sg;
-
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
- memcpy(scmd->cmnd, cmnd, cmnd_size);
-
- if (copy_sense) {
- sg_init_one(&sgl, scmd->sense_buffer,
- sizeof(scmd->sense_buffer));
-
+ ses->cmd_len = scmd->cmd_len;
+ memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ ses->data_direction = scmd->sc_data_direction;
+ ses->bufflen = scmd->request_bufflen;
+ ses->buffer = scmd->request_buffer;
+ ses->use_sg = scmd->use_sg;
+ ses->resid = scmd->resid;
+ ses->result = scmd->result;
+
+ if (sense_bytes) {
+ scmd->request_bufflen = min_t(unsigned,
+ sizeof(scmd->sense_buffer), sense_bytes);
+ sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
+ scmd->request_bufflen);
+ scmd->request_buffer = &ses->sense_sgl;
scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->request_bufflen = sgl.length;
- scmd->request_buffer = &sgl;
scmd->use_sg = 1;
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ scmd->cmnd[0] = REQUEST_SENSE;
+ scmd->cmnd[4] = scmd->request_bufflen;
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
} else {
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
scmd->sc_data_direction = DMA_NONE;
scmd->use_sg = 0;
+ if (cmnd) {
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ memcpy(scmd->cmnd, cmnd, cmnd_size);
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+ }
}
scmd->underflow = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- if (sdev->scsi_level <= SCSI_2)
+ if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
(sdev->lun << 5 & 0xe0);
@@ -667,7 +659,58 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
* untransferred sense data should be interpreted as being zero.
*/
memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+}
+EXPORT_SYMBOL(scsi_eh_prep_cmnd);
+
+/**
+ * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
+ * @scmd: SCSI command structure to restore
+ * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd
+ *
+ * Undo any damage done by above scsi_prep_eh_cmnd().
+ **/
+void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
+{
+ /*
+ * Restore original data
+ */
+ scmd->cmd_len = ses->cmd_len;
+ memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+ scmd->sc_data_direction = ses->data_direction;
+ scmd->request_bufflen = ses->bufflen;
+ scmd->request_buffer = ses->buffer;
+ scmd->use_sg = ses->use_sg;
+ scmd->resid = ses->resid;
+ scmd->result = ses->result;
+}
+EXPORT_SYMBOL(scsi_eh_restore_cmnd);
+/**
+ * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * @scmd: SCSI command structure to hijack
+ * @cmnd: CDB to send
+ * @cmnd_size: size in bytes of @cmnd
+ * @timeout: timeout for this request
+ * @sense_bytes: size of sense data to copy or 0
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
+ *
+ * Return value:
+ * SUCCESS or FAILED or NEEDS_RETRY
+ **/
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+ int cmnd_size, int timeout, unsigned sense_bytes)
+{
+ struct scsi_device *sdev = scmd->device;
+ struct Scsi_Host *shost = sdev->host;
+ DECLARE_COMPLETION_ONSTACK(done);
+ unsigned long timeleft;
+ unsigned long flags;
+ struct scsi_eh_save ses;
+ int rtn;
+
+ scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
shost->eh_action = &done;
spin_lock_irqsave(shost->host_lock, flags);
@@ -711,17 +754,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
rtn = FAILED;
}
-
- /*
- * Restore original data
- */
- scmd->request_buffer = old_buffer;
- scmd->request_bufflen = old_bufflen;
- memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
- scmd->sc_data_direction = old_data_direction;
- scmd->cmd_len = old_cmd_len;
- scmd->use_sg = old_use_sg;
- scmd->result = old_result;
+ scsi_eh_restore_cmnd(scmd, &ses);
return rtn;
}
@@ -736,10 +769,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
**/
static int scsi_request_sense(struct scsi_cmnd *scmd)
{
- static unsigned char generic_sense[6] =
- {REQUEST_SENSE, 0, 0, 0, 252, 0};
-
- return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
+ return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
}
/**
@@ -1136,9 +1166,8 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
struct scsi_cmnd *scmd, *next;
list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
- sdev_printk(KERN_INFO, scmd->device,
- "scsi: Device offlined - not"
- " ready after error recovery\n");
+ sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
+ "not ready after error recovery\n");
scsi_device_set_state(scmd->device, SDEV_OFFLINE);
if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) {
/*
@@ -1671,7 +1700,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
scmd->scsi_done = scsi_reset_provider_done_command;
- scmd->done = NULL;
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
@@ -1681,12 +1709,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
init_timer(&scmd->eh_timeout);
- /*
- * Sometimes the command can get back into the timer chain,
- * so use the pid as an identifier.
- */
- scmd->pid = 0;
-
spin_lock_irqsave(shost->host_lock, flags);
shost->tmf_in_progress = 1;
spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 604f4d71793..207f1aa0886 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -288,7 +288,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
{
struct request_queue *q = rq->q;
int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
- unsigned int data_len = 0, len, bytes, off;
+ unsigned int data_len = bufflen, len, bytes, off;
struct page *page;
struct bio *bio = NULL;
int i, err, nr_vecs = 0;
@@ -297,10 +297,15 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
page = sgl[i].page;
off = sgl[i].offset;
len = sgl[i].length;
- data_len += len;
- while (len > 0) {
+ while (len > 0 && data_len > 0) {
+ /*
+ * sg sends a scatterlist that is larger than
+ * the data_len it wants transferred for certain
+ * IO sizes
+ */
bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+ bytes = min(bytes, data_len);
if (!bio) {
nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
@@ -332,12 +337,13 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
page++;
len -= bytes;
+ data_len -=bytes;
off = 0;
}
}
rq->buffer = rq->data = NULL;
- rq->data_len = data_len;
+ rq->data_len = bufflen;
return 0;
free_bios:
@@ -430,6 +436,7 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
{
cmd->serial_number = 0;
+ cmd->resid = 0;
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
@@ -924,11 +931,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break;
}
}
- if (!(req->cmd_flags & REQ_QUIET)) {
- scmd_printk(KERN_INFO, cmd,
- "Device not ready: ");
- scsi_print_sense_hdr("", &sshdr);
- }
+ if (!(req->cmd_flags & REQ_QUIET))
+ scsi_cmd_print_sense_hdr(cmd,
+ "Device not ready",
+ &sshdr);
+
scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
@@ -962,7 +969,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
scsi_end_request(cmd, 0, this_count, !result);
}
-EXPORT_SYMBOL(scsi_io_completion);
/*
* Function: scsi_init_io()
@@ -1019,9 +1025,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);
- /* release the command and kill it */
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
return BLKPREP_KILL;
}
@@ -1046,21 +1049,13 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
return cmd;
}
-static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
-{
- BUG_ON(!blk_pc_request(cmd->request));
- /*
- * This will complete the whole command with uptodate=1 so
- * as far as the block layer is concerned the command completed
- * successfully. Since this is a REQ_BLOCK_PC command the
- * caller should check the request's errors value
- */
- scsi_io_completion(cmd, cmd->request_bufflen);
-}
-
-static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
+ int ret = scsi_prep_state_check(sdev, req);
+
+ if (ret != BLKPREP_OK)
+ return ret;
cmd = scsi_get_cmd_from_req(sdev, req);
if (unlikely(!cmd))
@@ -1103,21 +1098,22 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
cmd->transfersize = req->data_len;
cmd->allowed = req->retries;
cmd->timeout_per_command = req->timeout;
- cmd->done = scsi_blk_pc_done;
return BLKPREP_OK;
}
+EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
/*
* Setup a REQ_TYPE_FS command. These are simple read/write request
* from filesystems that still need to be translated to SCSI CDBs from
* the ULD.
*/
-static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
- struct scsi_driver *drv;
- int ret;
+ int ret = scsi_prep_state_check(sdev, req);
+ if (ret != BLKPREP_OK)
+ return ret;
/*
* Filesystem requests must transfer data.
*/
@@ -1127,26 +1123,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
- ret = scsi_init_io(cmd);
- if (unlikely(ret))
- return ret;
-
- /*
- * Initialize the actual SCSI command for this request.
- */
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
- }
-
- return BLKPREP_OK;
+ return scsi_init_io(cmd);
}
+EXPORT_SYMBOL(scsi_setup_fs_cmnd);
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
{
- struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_OK;
/*
@@ -1192,35 +1174,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
ret = BLKPREP_KILL;
break;
}
-
- if (ret != BLKPREP_OK)
- goto out;
}
+ return ret;
+}
+EXPORT_SYMBOL(scsi_prep_state_check);
- switch (req->cmd_type) {
- case REQ_TYPE_BLOCK_PC:
- ret = scsi_setup_blk_pc_cmnd(sdev, req);
- break;
- case REQ_TYPE_FS:
- ret = scsi_setup_fs_cmnd(sdev, req);
- break;
- default:
- /*
- * All other command types are not supported.
- *
- * Note that these days the SCSI subsystem does not use
- * REQ_TYPE_SPECIAL requests anymore. These are only used
- * (directly or via blk_insert_request) by non-SCSI drivers.
- */
- blk_dump_rq_flags(req, "SCSI bad req");
- ret = BLKPREP_KILL;
- break;
- }
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
+{
+ struct scsi_device *sdev = q->queuedata;
- out:
switch (ret) {
case BLKPREP_KILL:
req->errors = DID_NO_CONNECT << 16;
+ /* release the command and kill it */
+ if (req->special) {
+ struct scsi_cmnd *cmd = req->special;
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ req->special = NULL;
+ }
break;
case BLKPREP_DEFER:
/*
@@ -1237,6 +1209,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
return ret;
}
+EXPORT_SYMBOL(scsi_prep_return);
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+ struct scsi_device *sdev = q->queuedata;
+ int ret = BLKPREP_KILL;
+
+ if (req->cmd_type == REQ_TYPE_BLOCK_PC)
+ ret = scsi_setup_blk_pc_cmnd(sdev, req);
+ return scsi_prep_return(q, req, ret);
+}
/*
* scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index ee8efe849bf..eff00595189 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -68,6 +68,7 @@ extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_next_command(struct scsi_cmnd *cmd);
+extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
extern void scsi_free_queue(struct request_queue *q);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a86e62f4b3b..b53c5f67e37 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -85,7 +85,7 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
static unsigned int max_scsi_luns = 1;
#endif
-module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(max_luns,
"last scsi LUN (should be between 1 and 2^32-1)");
@@ -109,18 +109,19 @@ MODULE_PARM_DESC(scan, "sync, async or none");
*/
static unsigned int max_scsi_report_luns = 511;
-module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(max_report_luns,
"REPORT LUNS maximum number of LUNS received (should be"
" between 1 and 16384)");
static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
-module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(inq_timeout,
"Timeout (in seconds) waiting for devices to answer INQUIRY."
" Default is 5. Some non-compliant devices need more.");
+/* This lock protects only this list */
static DEFINE_SPINLOCK(async_scan_lock);
static LIST_HEAD(scanning_hosts);
@@ -1466,14 +1467,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (strncmp(scsi_scan_type, "none", 4) == 0)
return ERR_PTR(-ENODEV);
- if (!shost->async_scan)
- scsi_complete_async_scans();
-
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return ERR_PTR(-ENOMEM);
mutex_lock(&shost->scan_mutex);
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
if (scsi_host_scan_allowed(shost))
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
mutex_unlock(&shost->scan_mutex);
@@ -1586,10 +1587,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
if (strncmp(scsi_scan_type, "none", 4) == 0)
return;
+ mutex_lock(&shost->scan_mutex);
if (!shost->async_scan)
scsi_complete_async_scans();
- mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
__scsi_scan_target(parent, channel, id, lun, rescan);
mutex_unlock(&shost->scan_mutex);
@@ -1634,15 +1635,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
"%s: <%u:%u:%u>\n",
__FUNCTION__, channel, id, lun));
- if (!shost->async_scan)
- scsi_complete_async_scans();
-
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
return -EINVAL;
mutex_lock(&shost->scan_mutex);
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
if (scsi_host_scan_allowed(shost)) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
@@ -1661,7 +1662,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, shost) {
- if (scsi_sysfs_add_sdev(sdev) != 0)
+ if (!scsi_host_scan_allowed(shost) ||
+ scsi_sysfs_add_sdev(sdev) != 0)
scsi_destroy_sdev(sdev);
}
}
@@ -1679,6 +1681,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
{
struct async_scan_data *data;
+ unsigned long flags;
if (strncmp(scsi_scan_type, "sync", 4) == 0)
return NULL;
@@ -1698,8 +1701,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
goto err;
init_completion(&data->prev_finished);
- spin_lock(&async_scan_lock);
+ mutex_lock(&shost->scan_mutex);
+ spin_lock_irqsave(shost->host_lock, flags);
shost->async_scan = 1;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ mutex_unlock(&shost->scan_mutex);
+
+ spin_lock(&async_scan_lock);
if (list_empty(&scanning_hosts))
complete(&data->prev_finished);
list_add_tail(&data->list, &scanning_hosts);
@@ -1723,11 +1731,15 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
static void scsi_finish_async_scan(struct async_scan_data *data)
{
struct Scsi_Host *shost;
+ unsigned long flags;
if (!data)
return;
shost = data->shost;
+
+ mutex_lock(&shost->scan_mutex);
+
if (!shost->async_scan) {
printk("%s called twice for host %d", __FUNCTION__,
shost->host_no);
@@ -1739,8 +1751,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
scsi_sysfs_add_devices(shost);
- spin_lock(&async_scan_lock);
+ spin_lock_irqsave(shost->host_lock, flags);
shost->async_scan = 0;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ mutex_unlock(&shost->scan_mutex);
+
+ spin_lock(&async_scan_lock);
list_del(&data->list);
if (!list_empty(&scanning_hosts)) {
struct async_scan_data *next = list_entry(scanning_hosts.next,
@@ -1782,6 +1799,7 @@ static int do_scan_async(void *_data)
**/
void scsi_scan_host(struct Scsi_Host *shost)
{
+ struct task_struct *p;
struct async_scan_data *data;
if (strncmp(scsi_scan_type, "none", 4) == 0)
@@ -1793,7 +1811,9 @@ void scsi_scan_host(struct Scsi_Host *shost)
return;
}
- kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+ p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+ if (unlikely(IS_ERR(p)))
+ do_scan_async(data);
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 34cdce6738a..daed37df00b 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -190,6 +190,46 @@ show_shost_state(struct class_device *class_dev, char *buf)
static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
+static ssize_t
+show_shost_mode(unsigned int mode, char *buf)
+{
+ ssize_t len = 0;
+
+ if (mode & MODE_INITIATOR)
+ len = sprintf(buf, "%s", "Initiator");
+
+ if (mode & MODE_TARGET)
+ len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target");
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t show_shost_supported_mode(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+
+ if (shost->hostt->supported_mode == MODE_UNKNOWN)
+ return snprintf(buf, 20, "unknown\n");
+ else
+ return show_shost_mode(shost->hostt->supported_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
+
+static ssize_t show_shost_active_mode(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+
+ if (shost->active_mode == MODE_UNKNOWN)
+ return snprintf(buf, 20, "unknown\n");
+ else
+ return show_shost_mode(shost->active_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
+
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -208,6 +248,8 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_proc_name,
&class_device_attr_scan,
&class_device_attr_state,
+ &class_device_attr_supported_mode,
+ &class_device_attr_active_mode,
NULL
};
@@ -277,16 +319,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct scsi_device *sdev = to_scsi_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
return 0;
}
@@ -576,24 +613,31 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
/* Default template for device attributes. May NOT be modified */
-static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
- &dev_attr_device_blocked,
- &dev_attr_queue_depth,
- &dev_attr_queue_type,
- &dev_attr_type,
- &dev_attr_scsi_level,
- &dev_attr_vendor,
- &dev_attr_model,
- &dev_attr_rev,
- &dev_attr_rescan,
- &dev_attr_delete,
- &dev_attr_state,
- &dev_attr_timeout,
- &dev_attr_iocounterbits,
- &dev_attr_iorequest_cnt,
- &dev_attr_iodone_cnt,
- &dev_attr_ioerr_cnt,
- &dev_attr_modalias,
+static struct attribute *scsi_sdev_attrs[] = {
+ &dev_attr_device_blocked.attr,
+ &dev_attr_type.attr,
+ &dev_attr_scsi_level.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_model.attr,
+ &dev_attr_rev.attr,
+ &dev_attr_rescan.attr,
+ &dev_attr_delete.attr,
+ &dev_attr_state.attr,
+ &dev_attr_timeout.attr,
+ &dev_attr_iocounterbits.attr,
+ &dev_attr_iorequest_cnt.attr,
+ &dev_attr_iodone_cnt.attr,
+ &dev_attr_ioerr_cnt.attr,
+ &dev_attr_modalias.attr,
+ NULL
+};
+
+static struct attribute_group scsi_sdev_attr_group = {
+ .attrs = scsi_sdev_attrs,
+};
+
+static struct attribute_group *scsi_sdev_attr_groups[] = {
+ &scsi_sdev_attr_group,
NULL
};
@@ -655,56 +699,6 @@ static struct device_attribute sdev_attr_queue_type_rw =
__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
sdev_store_queue_type_rw);
-static struct device_attribute *attr_changed_internally(
- struct Scsi_Host *shost,
- struct device_attribute * attr)
-{
- if (!strcmp("queue_depth", attr->attr.name)
- && shost->hostt->change_queue_depth)
- return &sdev_attr_queue_depth_rw;
- else if (!strcmp("queue_type", attr->attr.name)
- && shost->hostt->change_queue_type)
- return &sdev_attr_queue_type_rw;
- return attr;
-}
-
-
-static struct device_attribute *attr_overridden(
- struct device_attribute **attrs,
- struct device_attribute *attr)
-{
- int i;
-
- if (!attrs)
- return NULL;
- for (i = 0; attrs[i]; i++)
- if (!strcmp(attrs[i]->attr.name, attr->attr.name))
- return attrs[i];
- return NULL;
-}
-
-static int attr_add(struct device *dev, struct device_attribute *attr)
-{
- struct device_attribute *base_attr;
-
- /*
- * Spare the caller from having to copy things it's not interested in.
- */
- base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr);
- if (base_attr) {
- /* extend permissions */
- attr->attr.mode |= base_attr->attr.mode;
-
- /* override null show/store with default */
- if (!attr->show)
- attr->show = base_attr->show;
- if (!attr->store)
- attr->store = base_attr->store;
- }
-
- return device_create_file(dev, attr);
-}
-
/**
* scsi_sysfs_add_sdev - add scsi device to sysfs
* @sdev: scsi_device to add
@@ -736,6 +730,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
* released by the sdev_class .release */
get_device(&sdev->sdev_gendev);
+ /* create queue files, which may be writable, depending on the host */
+ if (sdev->host->hostt->change_queue_depth)
+ error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
+ else
+ error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
+ if (error) {
+ __scsi_remove_device(sdev);
+ goto out;
+ }
+ if (sdev->host->hostt->change_queue_type)
+ error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
+ else
+ error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
+ if (error) {
+ __scsi_remove_device(sdev);
+ goto out;
+ }
+
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
if (error)
@@ -746,9 +758,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
* nothing went wrong */
error = 0;
+ /* add additional host specific attributes */
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
- error = attr_add(&sdev->sdev_gendev,
+ error = device_create_file(&sdev->sdev_gendev,
sdev->host->hostt->sdev_attrs[i]);
if (error) {
__scsi_remove_device(sdev);
@@ -756,20 +769,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
}
-
- for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) {
- if (!attr_overridden(sdev->host->hostt->sdev_attrs,
- scsi_sysfs_sdev_attrs[i])) {
- struct device_attribute * attr =
- attr_changed_internally(sdev->host,
- scsi_sysfs_sdev_attrs[i]);
- error = device_create_file(&sdev->sdev_gendev, attr);
- if (error) {
- __scsi_remove_device(sdev);
- goto out;
- }
- }
- }
transport_add_device(&sdev->sdev_gendev);
out:
@@ -956,6 +955,12 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
return 0;
}
+static struct device_type scsi_dev_type = {
+ .name = "scsi_device",
+ .release = scsi_device_dev_release,
+ .groups = scsi_sdev_attr_groups,
+};
+
void scsi_sysfs_device_initialize(struct scsi_device *sdev)
{
unsigned long flags;
@@ -964,7 +969,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
device_initialize(&sdev->sdev_gendev);
sdev->sdev_gendev.bus = &scsi_bus_type;
- sdev->sdev_gendev.release = scsi_device_dev_release;
+ sdev->sdev_gendev.type = &scsi_dev_type;
sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id,
sdev->lun);
@@ -985,7 +990,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
int scsi_is_sdev_device(const struct device *dev)
{
- return dev->release == scsi_device_dev_release;
+ return dev->type == &scsi_dev_type;
}
EXPORT_SYMBOL(scsi_is_sdev_device);
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index ca22ddf8174..9815a1a2db2 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -102,7 +102,8 @@ static int tgt_uspace_send_event(u32 type, struct tgt_event *p)
return 0;
}
-int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag)
+int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
+ struct scsi_lun *lun, u64 tag)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct tgt_event ev;
@@ -110,6 +111,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
memset(&ev, 0, sizeof(ev));
ev.p.cmd_req.host_no = shost->host_no;
+ ev.p.cmd_req.itn_id = itn_id;
ev.p.cmd_req.data_len = cmd->request_bufflen;
memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
@@ -127,7 +129,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
return err;
}
-int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct tgt_event ev;
@@ -135,6 +137,7 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
memset(&ev, 0, sizeof(ev));
ev.p.cmd_done.host_no = shost->host_no;
+ ev.p.cmd_done.itn_id = itn_id;
ev.p.cmd_done.tag = tag;
ev.p.cmd_done.result = cmd->result;
@@ -149,14 +152,15 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
return err;
}
-int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
- struct scsi_lun *scsilun, void *data)
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function,
+ u64 tag, struct scsi_lun *scsilun, void *data)
{
struct tgt_event ev;
int err;
memset(&ev, 0, sizeof(ev));
ev.p.tsk_mgmt_req.host_no = host_no;
+ ev.p.tsk_mgmt_req.itn_id = itn_id;
ev.p.tsk_mgmt_req.function = function;
ev.p.tsk_mgmt_req.tag = tag;
memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
@@ -172,6 +176,29 @@ int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
return err;
}
+int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id,
+ int function, char *initiator_id)
+{
+ struct tgt_event ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.p.it_nexus_req.host_no = host_no;
+ ev.p.it_nexus_req.function = function;
+ ev.p.it_nexus_req.itn_id = itn_id;
+ if (initiator_id)
+ strncpy(ev.p.it_nexus_req.initiator_id, initiator_id,
+ sizeof(ev.p.it_nexus_req.initiator_id));
+
+ dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id);
+
+ err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev);
+ if (err)
+ eprintk("tx buf is full, could not send\n");
+
+ return err;
+}
+
static int event_recv_msg(struct tgt_event *ev)
{
int err = 0;
@@ -179,6 +206,7 @@ static int event_recv_msg(struct tgt_event *ev)
switch (ev->hdr.type) {
case TGT_UEVENT_CMD_RSP:
err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
+ ev->p.cmd_rsp.itn_id,
ev->p.cmd_rsp.result,
ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.uaddr,
@@ -189,9 +217,15 @@ static int event_recv_msg(struct tgt_event *ev)
break;
case TGT_UEVENT_TSK_MGMT_RSP:
err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
+ ev->p.tsk_mgmt_rsp.itn_id,
ev->p.tsk_mgmt_rsp.mid,
ev->p.tsk_mgmt_rsp.result);
break;
+ case TGT_UEVENT_IT_NEXUS_RSP:
+ err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no,
+ ev->p.it_nexus_rsp.itn_id,
+ ev->p.it_nexus_rsp.result);
+ break;
default:
eprintk("unknown type %d\n", ev->hdr.type);
err = -EINVAL;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 371b69c110b..66c692ffa30 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -27,6 +27,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
#include <scsi/scsi_tgt.h>
#include "scsi_tgt_priv.h"
@@ -46,6 +47,7 @@ struct scsi_tgt_cmd {
struct list_head hash_list;
struct request *rq;
+ u64 itn_id;
u64 tag;
};
@@ -185,12 +187,13 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
}
static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
- u64 tag)
+ u64 itn_id, u64 tag)
{
struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
unsigned long flags;
struct list_head *head;
+ tcmd->itn_id = itn_id;
tcmd->tag = tag;
tcmd->bio = NULL;
INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
@@ -234,7 +237,7 @@ int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
* command as is recvd to userspace. uspace can then make
* sure we do not overload the HBA
*/
- q->nr_requests = shost->hostt->can_queue;
+ q->nr_requests = shost->can_queue;
/*
* We currently only support software LLDs so this does
* not matter for now. Do we need this for the cards we support?
@@ -301,14 +304,14 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
* @scsilun: scsi lun
* @tag: unique value to identify this command for tmf
*/
-int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
- u64 tag)
+int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,
+ struct scsi_lun *scsilun, u64 tag)
{
struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
int err;
- init_scsi_tgt_cmd(cmd->request, tcmd, tag);
- err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag);
+ init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag);
+ err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag);
if (err)
cmd_hashlist_del(cmd);
@@ -326,7 +329,7 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
- scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+ scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
if (cmd->request_buffer)
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
@@ -459,7 +462,7 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
return rq;
}
-int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
unsigned long uaddr, u32 len, unsigned long sense_uaddr,
u32 sense_len, u8 rw)
{
@@ -541,21 +544,22 @@ done:
return err;
}
-int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
- struct scsi_lun *scsilun, void *data)
+int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id,
+ int function, u64 tag, struct scsi_lun *scsilun,
+ void *data)
{
int err;
/* TODO: need to retry if this fails. */
- err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
- tag, scsilun, data);
+ err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id,
+ function, tag, scsilun, data);
if (err < 0)
eprintk("The task management request lost!\n");
return err;
}
EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
-int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
+int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result)
{
struct Scsi_Host *shost;
int err = -EINVAL;
@@ -573,7 +577,60 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
goto done;
}
- err = shost->hostt->tsk_mgmt_response(mid, result);
+ err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result);
+done:
+ scsi_host_put(shost);
+ return err;
+}
+
+int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0,
+ initiator);
+ if (err < 0)
+ eprintk("The i_t_neuxs request lost, %d %llx!\n",
+ shost->host_no, (unsigned long long)itn_id);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create);
+
+int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no,
+ itn_id, 1, NULL);
+ if (err < 0)
+ eprintk("The i_t_neuxs request lost, %d %llx!\n",
+ shost->host_no, (unsigned long long)itn_id);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy);
+
+int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
+{
+ struct Scsi_Host *shost;
+ int err = -EINVAL;
+
+ dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %d\n", host_no);
+ return err;
+ }
+
+ if (!shost->uspace_req_q) {
+ printk(KERN_ERR "Not target scsi host %d\n", host_no);
+ goto done;
+ }
+
+ err = shost->transportt->it_nexus_response(shost, itn_id, result);
done:
scsi_host_put(shost);
return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index e9e6db1c417..cb92888948f 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -15,12 +15,18 @@ do { \
extern void scsi_tgt_if_exit(void);
extern int scsi_tgt_if_init(void);
-extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
- u64 tag);
-extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
- unsigned long uaddr, u32 len, unsigned long sense_uaddr,
- u32 sense_len, u8 rw);
-extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id,
+ struct scsi_lun *lun, u64 tag);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id,
+ u64 tag);
+extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag,
+ unsigned long uaddr, u32 len,
+ unsigned long sense_uaddr, u32 sense_len, u8 rw);
+extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id,
+ int function, u64 tag,
struct scsi_lun *scsilun, void *data);
-extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
+extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id,
+ u64 mid, int result);
+extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id,
+ int function, char *initiator);
+extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 47057254850..7a7cfe583b2 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -36,6 +36,7 @@
#include <net/netlink.h>
#include <scsi/scsi_netlink_fc.h>
#include "scsi_priv.h"
+#include "scsi_transport_fc_internal.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
@@ -473,7 +474,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class,
*/
static unsigned int fc_dev_loss_tmo = 60; /* seconds */
-module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dev_loss_tmo,
"Maximum number of seconds that the FC transport should"
" insulate the loss of a remote port. Once this value is"
@@ -1956,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
return 0;
}
+static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+ int result)
+{
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ return i->f->it_nexus_response(shost, nexus, result);
+}
+
struct scsi_transport_template *
fc_attach_transport(struct fc_function_template *ft)
{
@@ -1999,6 +2013,10 @@ fc_attach_transport(struct fc_function_template *ft)
i->t.user_scan = fc_user_scan;
+ /* target-mode drivers' functions */
+ i->t.tsk_mgmt_response = fc_tsk_mgmt_response;
+ i->t.it_nexus_response = fc_it_nexus_response;
+
/*
* Setup SCSI Target Attributes.
*/
@@ -2756,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport *rport)
spin_unlock_irqrestore(shost->host_lock, flags);
+ if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR &&
+ shost->active_mode & MODE_TARGET)
+ fc_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
scsi_target_block(&rport->dev);
/* see if we need to kill io faster than waiting for device loss */
@@ -2796,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
int create = 0;
+ int ret;
spin_lock_irqsave(shost->host_lock, flags);
if (roles & FC_PORT_ROLE_FCP_TARGET) {
@@ -2804,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
create = 1;
} else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
create = 1;
+ } else if (shost->active_mode & MODE_TARGET) {
+ ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport,
+ (char *)&rport->node_name);
+ if (ret)
+ printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n",
+ ret);
}
rport->roles = roles;
@@ -2988,10 +3017,12 @@ fc_scsi_scan_rport(struct work_struct *work)
struct fc_rport *rport =
container_of(work, struct fc_rport, scan_work);
struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
unsigned long flags;
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
- (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
+ (rport->roles & FC_PORT_ROLE_FCP_TARGET) &&
+ !(i->f->disable_target_scan)) {
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
diff --git a/drivers/scsi/scsi_transport_fc_internal.h b/drivers/scsi/scsi_transport_fc_internal.h
new file mode 100644
index 00000000000..e7bfbe751c1
--- /dev/null
+++ b/drivers/scsi/scsi_transport_fc_internal.h
@@ -0,0 +1,26 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_FC_TGT_ATTRS
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+#else
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return 0;
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return 0;
+}
+
+#endif
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
new file mode 100644
index 00000000000..44a340bd937
--- /dev/null
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -0,0 +1,381 @@
+/*
+ * SCSI RDMA (SRP) transport class
+ *
+ * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_srp.h>
+#include "scsi_transport_srp_internal.h"
+
+struct srp_host_attrs {
+ atomic_t next_port_id;
+};
+#define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data)
+
+#define SRP_HOST_ATTRS 0
+#define SRP_RPORT_ATTRS 2
+
+struct srp_internal {
+ struct scsi_transport_template t;
+ struct srp_function_template *f;
+
+ struct class_device_attribute *host_attrs[SRP_HOST_ATTRS + 1];
+
+ struct class_device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1];
+ struct class_device_attribute private_rport_attrs[SRP_RPORT_ATTRS];
+ struct transport_container rport_attr_cont;
+};
+
+#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
+
+#define dev_to_rport(d) container_of(d, struct srp_rport, dev)
+#define transport_class_to_srp_rport(cdev) dev_to_rport((cdev)->dev)
+
+static int srp_host_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ struct srp_host_attrs *srp_host = to_srp_host_attrs(shost);
+
+ atomic_set(&srp_host->next_port_id, 0);
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup,
+ NULL, NULL);
+
+static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports",
+ NULL, NULL, NULL);
+
+#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm) \
+ i->private_##attrb[count] = class_device_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ if (ro_test) { \
+ i->private_##attrb[count].attr.mode = ro_perm; \
+ i->private_##attrb[count].store = NULL; \
+ } \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
+
+#define SETUP_RPORT_ATTRIBUTE_RD(field) \
+ SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0)
+
+#define SETUP_RPORT_ATTRIBUTE_RW(field) \
+ SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR, \
+ 1, 1, S_IRUGO)
+
+#define SRP_PID(p) \
+ (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \
+ (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \
+ (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \
+ (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15]
+
+#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+
+static ssize_t
+show_srp_rport_id(struct class_device *cdev, char *buf)
+{
+ struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+ return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport));
+}
+
+static CLASS_DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL);
+
+static const struct {
+ u32 value;
+ char *name;
+} srp_rport_role_names[] = {
+ {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"},
+ {SRP_RPORT_ROLE_TARGET, "SRP Target"},
+};
+
+static ssize_t
+show_srp_rport_roles(struct class_device *cdev, char *buf)
+{
+ struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++)
+ if (srp_rport_role_names[i].value == rport->roles) {
+ name = srp_rport_role_names[i].name;
+ break;
+ }
+ return sprintf(buf, "%s\n", name ? : "unknown");
+}
+
+static CLASS_DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL);
+
+static void srp_rport_release(struct device *dev)
+{
+ struct srp_rport *rport = dev_to_rport(dev);
+
+ put_device(dev->parent);
+ kfree(rport);
+}
+
+static int scsi_is_srp_rport(const struct device *dev)
+{
+ return dev->release == srp_rport_release;
+}
+
+static int srp_rport_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct srp_internal *i;
+
+ if (!scsi_is_srp_rport(dev))
+ return 0;
+
+ shost = dev_to_shost(dev->parent);
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+ return 0;
+
+ i = to_srp_internal(shost->transportt);
+ return &i->rport_attr_cont.ac == cont;
+}
+
+static int srp_host_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct srp_internal *i;
+
+ if (!scsi_is_host_device(dev))
+ return 0;
+
+ shost = dev_to_shost(dev);
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+ return 0;
+
+ i = to_srp_internal(shost->transportt);
+ return &i->t.host_attrs.ac == cont;
+}
+
+/**
+ * srp_rport_add - add a SRP remote port to the device hierarchy
+ *
+ * @shost: scsi host the remote port is connected to.
+ * @ids: The port id for the remote port.
+ *
+ * publishes a port to the rest of the system
+ */
+struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
+ struct srp_rport_identifiers *ids)
+{
+ struct srp_rport *rport;
+ struct device *parent = &shost->shost_gendev;
+ int id, ret;
+
+ rport = kzalloc(sizeof(*rport), GFP_KERNEL);
+ if (!rport)
+ return ERR_PTR(-ENOMEM);
+
+ device_initialize(&rport->dev);
+
+ rport->dev.parent = get_device(parent);
+ rport->dev.release = srp_rport_release;
+
+ memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id));
+ rport->roles = ids->roles;
+
+ id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
+ sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id);
+
+ transport_setup_device(&rport->dev);
+
+ ret = device_add(&rport->dev);
+ if (ret) {
+ transport_destroy_device(&rport->dev);
+ put_device(&rport->dev);
+ return ERR_PTR(ret);
+ }
+
+ if (shost->active_mode & MODE_TARGET &&
+ ids->roles == SRP_RPORT_ROLE_INITIATOR) {
+ ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport,
+ rport->port_id);
+ if (ret) {
+ device_del(&rport->dev);
+ transport_destroy_device(&rport->dev);
+ put_device(&rport->dev);
+ return ERR_PTR(ret);
+ }
+ }
+
+ transport_add_device(&rport->dev);
+ transport_configure_device(&rport->dev);
+
+ return rport;
+}
+EXPORT_SYMBOL_GPL(srp_rport_add);
+
+/**
+ * srp_rport_del -- remove a SRP remote port
+ * @port: SRP remote port to remove
+ *
+ * Removes the specified SRP remote port.
+ */
+void srp_rport_del(struct srp_rport *rport)
+{
+ struct device *dev = &rport->dev;
+ struct Scsi_Host *shost = dev_to_shost(dev->parent);
+
+ if (shost->active_mode & MODE_TARGET &&
+ rport->roles == SRP_RPORT_ROLE_INITIATOR)
+ srp_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(srp_rport_del);
+
+static int do_srp_rport_del(struct device *dev, void *data)
+{
+ srp_rport_del(dev_to_rport(dev));
+ return 0;
+}
+
+/**
+ * srp_remove_host -- tear down a Scsi_Host's SRP data structures
+ * @shost: Scsi Host that is torn down
+ *
+ * Removes all SRP remote ports for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SRP HBAs.
+ */
+void srp_remove_host(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del);
+}
+EXPORT_SYMBOL_GPL(srp_remove_host);
+
+static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+ int result)
+{
+ struct srp_internal *i = to_srp_internal(shost->transportt);
+ return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+ struct srp_internal *i = to_srp_internal(shost->transportt);
+ return i->f->it_nexus_response(shost, nexus, result);
+}
+
+/**
+ * srp_attach_transport -- instantiate SRP transport template
+ * @ft: SRP transport class function template
+ */
+struct scsi_transport_template *
+srp_attach_transport(struct srp_function_template *ft)
+{
+ int count;
+ struct srp_internal *i;
+
+ i = kzalloc(sizeof(*i), GFP_KERNEL);
+ if (!i)
+ return NULL;
+
+ i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
+ i->t.it_nexus_response = srp_it_nexus_response;
+
+ i->t.host_size = sizeof(struct srp_host_attrs);
+ i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+ i->t.host_attrs.ac.class = &srp_host_class.class;
+ i->t.host_attrs.ac.match = srp_host_match;
+ i->host_attrs[0] = NULL;
+ transport_container_register(&i->t.host_attrs);
+
+ i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+ i->rport_attr_cont.ac.class = &srp_rport_class.class;
+ i->rport_attr_cont.ac.match = srp_rport_match;
+ transport_container_register(&i->rport_attr_cont);
+
+ count = 0;
+ SETUP_RPORT_ATTRIBUTE_RD(port_id);
+ SETUP_RPORT_ATTRIBUTE_RD(roles);
+ i->rport_attrs[count] = NULL;
+
+ i->f = ft;
+
+ return &i->t;
+}
+EXPORT_SYMBOL_GPL(srp_attach_transport);
+
+/**
+ * srp_release_transport -- release SRP transport template instance
+ * @t: transport template instance
+ */
+void srp_release_transport(struct scsi_transport_template *t)
+{
+ struct srp_internal *i = to_srp_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+ transport_container_unregister(&i->rport_attr_cont);
+
+ kfree(i);
+}
+EXPORT_SYMBOL_GPL(srp_release_transport);
+
+static __init int srp_transport_init(void)
+{
+ int ret;
+
+ ret = transport_class_register(&srp_host_class);
+ if (ret)
+ return ret;
+ ret = transport_class_register(&srp_rport_class);
+ if (ret)
+ goto unregister_host_class;
+
+ return 0;
+unregister_host_class:
+ transport_class_unregister(&srp_host_class);
+ return ret;
+}
+
+static void __exit srp_transport_exit(void)
+{
+ transport_class_unregister(&srp_host_class);
+ transport_class_unregister(&srp_rport_class);
+}
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("SRP Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(srp_transport_init);
+module_exit(srp_transport_exit);
diff --git a/drivers/scsi/scsi_transport_srp_internal.h b/drivers/scsi/scsi_transport_srp_internal.h
new file mode 100644
index 00000000000..8a79747f9f3
--- /dev/null
+++ b/drivers/scsi/scsi_transport_srp_internal.h
@@ -0,0 +1,25 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_SRP_TGT_ATTRS
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+
+#else
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return 0;
+}
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116fd457..0a3a528212c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -86,6 +86,19 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
+static int sd_revalidate_disk(struct gendisk *);
+static int sd_probe(struct device *);
+static int sd_remove(struct device *);
+static void sd_shutdown(struct device *);
+static int sd_suspend(struct device *, pm_message_t state);
+static int sd_resume(struct device *);
+static void sd_rescan(struct device *);
+static int sd_done(struct scsi_cmnd *);
+static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
+static void scsi_disk_release(struct class_device *cdev);
+static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
+static void sd_print_result(struct scsi_disk *, int);
+
static DEFINE_IDR(sd_index_idr);
static DEFINE_SPINLOCK(sd_index_lock);
@@ -240,7 +253,7 @@ static struct scsi_driver sd_template = {
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
- .init_command = sd_init_command,
+ .done = sd_done,
};
/*
@@ -331,14 +344,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
-static int sd_init_command(struct scsi_cmnd * SCpnt)
+static int sd_prep_fn(struct request_queue *q, struct request *rq)
{
- struct scsi_device *sdp = SCpnt->device;
- struct request *rq = SCpnt->request;
+ struct scsi_cmnd *SCpnt;
+ struct scsi_device *sdp = q->queuedata;
struct gendisk *disk = rq->rq_disk;
sector_t block = rq->sector;
- unsigned int this_count = SCpnt->request_bufflen >> 9;
+ unsigned int this_count = rq->nr_sectors;
unsigned int timeout = sdp->timeout;
+ int ret;
+
+ if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+ ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+ goto out;
+ } else if (rq->cmd_type != REQ_TYPE_FS) {
+ ret = BLKPREP_KILL;
+ goto out;
+ }
+ ret = scsi_setup_fs_cmnd(sdp, rq);
+ if (ret != BLKPREP_OK)
+ goto out;
+ SCpnt = rq->special;
+
+ /* from here on until we're complete, any goto out
+ * is used for a killable error condition */
+ ret = BLKPREP_KILL;
SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
"sd_init_command: block=%llu, "
@@ -353,7 +383,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
"Retry with 0x%p\n", SCpnt));
- return 0;
+ goto out;
}
if (sdp->changed) {
@@ -362,8 +392,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* the changed bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
- return 0;
+ goto out;
}
+
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
(unsigned long long)block));
@@ -382,7 +413,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 1) || (rq->nr_sectors & 1)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 1;
this_count = this_count >> 1;
@@ -392,7 +423,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 3) || (rq->nr_sectors & 3)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 2;
this_count = this_count >> 2;
@@ -402,7 +433,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 7) || (rq->nr_sectors & 7)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 3;
this_count = this_count >> 3;
@@ -410,7 +441,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (rq_data_dir(rq) == WRITE) {
if (!sdp->writeable) {
- return 0;
+ goto out;
}
SCpnt->cmnd[0] = WRITE_6;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
@@ -419,7 +450,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
- return 0;
+ goto out;
}
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
@@ -470,7 +501,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
scmd_printk(KERN_ERR, SCpnt,
"FUA write on READ/WRITE(6) drive\n");
- return 0;
+ goto out;
}
SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
@@ -492,16 +523,12 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->timeout_per_command = timeout;
/*
- * This is the completion routine we use. This is matched in terms
- * of capability to this function.
- */
- SCpnt->done = sd_rw_intr;
-
- /*
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ ret = BLKPREP_OK;
+ out:
+ return scsi_prep_return(q, rq, ret);
}
/**
@@ -889,13 +916,13 @@ static struct block_device_operations sd_fops = {
};
/**
- * sd_rw_intr - bottom half handler: called when the lower level
+ * sd_done - bottom half handler: called when the lower level
* driver has completed (successfully or otherwise) a scsi command.
* @SCpnt: mid-level's per command structure.
*
* Note: potentially run from within an ISR. Must not block.
**/
-static void sd_rw_intr(struct scsi_cmnd * SCpnt)
+static int sd_done(struct scsi_cmnd *SCpnt)
{
int result = SCpnt->result;
unsigned int xfer_size = SCpnt->request_bufflen;
@@ -916,7 +943,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
if (sense_valid) {
SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
- "sd_rw_intr: sb[respc,sk,asc,"
+ "sd_done: sb[respc,sk,asc,"
"ascq]=%x,%x,%x,%x\n",
sshdr.response_code,
sshdr.sense_key, sshdr.asc,
@@ -988,7 +1015,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
break;
}
out:
- scsi_io_completion(SCpnt, good_bytes);
+ return good_bytes;
}
static int media_not_present(struct scsi_disk *sdkp,
@@ -1669,6 +1696,7 @@ static int sd_probe(struct device *dev)
sd_revalidate_disk(gd);
+ blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
gd->driverfs_dev = &sdp->sdev_gendev;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 85d38940a6c..f6f5fc7d0ce 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -43,6 +43,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/poll.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
+#include <linux/idr.h>
#include <linux/seq_file.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -99,12 +100,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
-#define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */
-
static int sg_add(struct class_device *, struct class_interface *);
static void sg_remove(struct class_device *, struct class_interface *);
-static DEFINE_RWLOCK(sg_dev_arr_lock); /* Also used to lock
+static DEFINE_IDR(sg_index_idr);
+static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
file descriptor list for device */
static struct class_interface sg_interface = {
@@ -114,7 +114,7 @@ static struct class_interface sg_interface = {
typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+ unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
unsigned bufflen; /* Size of (aggregate) data buffer */
unsigned b_malloc_len; /* actual len malloc'ed in buffer */
struct scatterlist *buffer;/* scatter list */
@@ -162,6 +162,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
struct scsi_device *device;
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
+ u32 index; /* device index number */
Sg_fd *headfp; /* first open fd belonging to this device */
volatile char detached; /* 0->attached, 1->detached pending removal */
volatile char exclude; /* opened for exclusive access */
@@ -209,10 +210,6 @@ static Sg_device *sg_get_dev(int dev);
static int sg_last_dev(void);
#endif
-static Sg_device **sg_dev_arr = NULL;
-static int sg_dev_max;
-static int sg_nr_dev;
-
#define SZ_SG_HEADER sizeof(struct sg_header)
#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
#define SZ_SG_IOVEC sizeof(sg_iovec_t)
@@ -1331,40 +1328,35 @@ static struct class *sg_sysfs_class;
static int sg_sysfs_valid = 0;
-static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
+static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
{
struct request_queue *q = scsidp->request_queue;
Sg_device *sdp;
unsigned long iflags;
- void *old_sg_dev_arr = NULL;
- int k, error;
+ int error;
+ u32 k;
sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
if (!sdp) {
printk(KERN_WARNING "kmalloc Sg_device failure\n");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
+ }
+ error = -ENOMEM;
+ if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) {
+ printk(KERN_WARNING "idr expansion Sg_device failure\n");
+ goto out;
}
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- if (unlikely(sg_nr_dev >= sg_dev_max)) { /* try to resize */
- Sg_device **tmp_da;
- int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
- tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
- if (unlikely(!tmp_da))
- goto expand_failed;
+ write_lock_irqsave(&sg_index_lock, iflags);
+ error = idr_get_new(&sg_index_idr, sdp, &k);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
- old_sg_dev_arr = sg_dev_arr;
- sg_dev_arr = tmp_da;
- sg_dev_max = tmp_dev_max;
+ if (error) {
+ printk(KERN_WARNING "idr allocation Sg_device failure: %d\n",
+ error);
+ goto out;
}
- for (k = 0; k < sg_dev_max; k++)
- if (!sg_dev_arr[k])
- break;
if (unlikely(k >= SG_MAX_DEVS))
goto overflow;
@@ -1375,25 +1367,17 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
sdp->device = scsidp;
init_waitqueue_head(&sdp->o_excl_wait);
sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
+ sdp->index = k;
- sg_nr_dev++;
- sg_dev_arr[k] = sdp;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- error = k;
-
+ error = 0;
out:
- if (error < 0)
+ if (error) {
kfree(sdp);
- kfree(old_sg_dev_arr);
- return error;
-
- expand_failed:
- printk(KERN_WARNING "sg_alloc: device array cannot be resized\n");
- error = -ENOMEM;
- goto out;
+ return ERR_PTR(error);
+ }
+ return sdp;
overflow:
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
sdev_printk(KERN_WARNING, scsidp,
"Unable to attach sg device type=%d, minor "
"number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1);
@@ -1408,7 +1392,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
struct gendisk *disk;
Sg_device *sdp = NULL;
struct cdev * cdev = NULL;
- int error, k;
+ int error;
unsigned long iflags;
disk = alloc_disk(1);
@@ -1427,15 +1411,15 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
cdev->owner = THIS_MODULE;
cdev->ops = &sg_fops;
- error = sg_alloc(disk, scsidp);
- if (error < 0) {
+ sdp = sg_alloc(disk, scsidp);
+ if (IS_ERR(sdp)) {
printk(KERN_WARNING "sg_alloc failed\n");
+ error = PTR_ERR(sdp);
goto out;
}
- k = error;
- sdp = sg_dev_arr[k];
- error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
+ class_set_devdata(cl_dev, sdp);
+ error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
if (error)
goto cdev_add_err;
@@ -1444,8 +1428,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
struct class_device * sg_class_member;
sg_class_member = class_device_create(sg_sysfs_class, NULL,
- MKDEV(SCSI_GENERIC_MAJOR, k),
- cl_dev->dev, "%s",
+ MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
+ cl_dev->dev, "%s",
disk->disk_name);
if (IS_ERR(sg_class_member))
printk(KERN_WARNING "sg_add: "
@@ -1455,21 +1439,21 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
&sg_class_member->kobj, "generic");
if (error)
printk(KERN_ERR "sg_add: unable to make symlink "
- "'generic' back to sg%d\n", k);
+ "'generic' back to sg%d\n", sdp->index);
} else
- printk(KERN_WARNING "sg_add: sg_sys INvalid\n");
+ printk(KERN_WARNING "sg_add: sg_sys Invalid\n");
sdev_printk(KERN_NOTICE, scsidp,
- "Attached scsi generic sg%d type %d\n", k,scsidp->type);
+ "Attached scsi generic sg%d type %d\n", sdp->index,
+ scsidp->type);
return 0;
cdev_add_err:
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- kfree(sg_dev_arr[k]);
- sg_dev_arr[k] = NULL;
- sg_nr_dev--;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
+ idr_remove(&sg_index_idr, sdp->index);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
+ kfree(sdp);
out:
put_disk(disk);
@@ -1482,64 +1466,56 @@ static void
sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
{
struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
- Sg_device *sdp = NULL;
+ Sg_device *sdp = class_get_devdata(cl_dev);
unsigned long iflags;
Sg_fd *sfp;
Sg_fd *tsfp;
Sg_request *srp;
Sg_request *tsrp;
- int k, delay;
+ int delay;
- if (NULL == sg_dev_arr)
+ if (!sdp)
return;
+
delay = 0;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- for (k = 0; k < sg_dev_max; k++) {
- sdp = sg_dev_arr[k];
- if ((NULL == sdp) || (sdp->device != scsidp))
- continue; /* dirty but lowers nesting */
- if (sdp->headfp) {
- sdp->detached = 1;
- for (sfp = sdp->headfp; sfp; sfp = tsfp) {
- tsfp = sfp->nextfp;
- for (srp = sfp->headrp; srp; srp = tsrp) {
- tsrp = srp->nextrp;
- if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
- sg_finish_rem_req(srp);
- }
- if (sfp->closed) {
- scsi_device_put(sdp->device);
- __sg_remove_sfp(sdp, sfp);
- } else {
- delay = 1;
- wake_up_interruptible(&sfp->read_wait);
- kill_fasync(&sfp->async_qp, SIGPOLL,
- POLL_HUP);
- }
+ write_lock_irqsave(&sg_index_lock, iflags);
+ if (sdp->headfp) {
+ sdp->detached = 1;
+ for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+ tsfp = sfp->nextfp;
+ for (srp = sfp->headrp; srp; srp = tsrp) {
+ tsrp = srp->nextrp;
+ if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
+ sg_finish_rem_req(srp);
}
- SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k));
- if (NULL == sdp->headfp) {
- sg_dev_arr[k] = NULL;
+ if (sfp->closed) {
+ scsi_device_put(sdp->device);
+ __sg_remove_sfp(sdp, sfp);
+ } else {
+ delay = 1;
+ wake_up_interruptible(&sfp->read_wait);
+ kill_fasync(&sfp->async_qp, SIGPOLL,
+ POLL_HUP);
}
- } else { /* nothing active, simple case */
- SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k));
- sg_dev_arr[k] = NULL;
}
- sg_nr_dev--;
- break;
- }
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
- if (sdp) {
- sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
- class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
- cdev_del(sdp->cdev);
- sdp->cdev = NULL;
- put_disk(sdp->disk);
- sdp->disk = NULL;
- if (NULL == sdp->headfp)
- kfree((char *) sdp);
- }
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index));
+ if (NULL == sdp->headfp) {
+ idr_remove(&sg_index_idr, sdp->index);
+ }
+ } else { /* nothing active, simple case */
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index));
+ idr_remove(&sg_index_idr, sdp->index);
+ }
+ write_unlock_irqrestore(&sg_index_lock, iflags);
+
+ sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+ class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
+ cdev_del(sdp->cdev);
+ sdp->cdev = NULL;
+ put_disk(sdp->disk);
+ sdp->disk = NULL;
+ if (NULL == sdp->headfp)
+ kfree(sdp);
if (delay)
msleep(10); /* dirty detach so delay device destruction */
@@ -1609,9 +1585,7 @@ exit_sg(void)
sg_sysfs_valid = 0;
unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
SG_MAX_DEVS);
- kfree((char *)sg_dev_arr);
- sg_dev_arr = NULL;
- sg_dev_max = 0;
+ idr_destroy(&sg_index_idr);
}
static int
@@ -2331,10 +2305,10 @@ sg_get_nth_sfp(Sg_device * sdp, int nth)
unsigned long iflags;
int k;
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
+ read_lock_irqsave(&sg_index_lock, iflags);
for (k = 0, resp = sdp->headfp; resp && (k < nth);
++k, resp = resp->nextfp) ;
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
return resp;
}
#endif
@@ -2361,7 +2335,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
if (!sdp->headfp)
sdp->headfp = sfp;
else { /* add to tail of existing list */
@@ -2370,7 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
pfp = pfp->nextfp;
pfp->nextfp = sfp;
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
if (unlikely(sg_big_buff != def_reserved_size))
sg_big_buff = def_reserved_size;
@@ -2431,22 +2405,14 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
if (0 == dirty) {
unsigned long iflags;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
__sg_remove_sfp(sdp, sfp);
if (sdp->detached && (NULL == sdp->headfp)) {
- int k, maxd;
-
- maxd = sg_dev_max;
- for (k = 0; k < maxd; ++k) {
- if (sdp == sg_dev_arr[k])
- break;
- }
- if (k < maxd)
- sg_dev_arr[k] = NULL;
- kfree((char *) sdp);
+ idr_remove(&sg_index_idr, sdp->index);
+ kfree(sdp);
res = 1;
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
} else {
/* MOD_INC's to inhibit unloading sg and associated adapter driver */
/* only bump the access_count if we actually succeeded in
@@ -2546,16 +2512,25 @@ sg_allow_access(unsigned char opcode, char dev_type)
#ifdef CONFIG_SCSI_PROC_FS
static int
+sg_idr_max_id(int id, void *p, void *data)
+{
+ int *k = data;
+
+ if (*k < id)
+ *k = id;
+
+ return 0;
+}
+
+static int
sg_last_dev(void)
{
- int k;
+ int k = 0;
unsigned long iflags;
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
- for (k = sg_dev_max - 1; k >= 0; --k)
- if (sg_dev_arr[k] && sg_dev_arr[k]->device)
- break;
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ read_lock_irqsave(&sg_index_lock, iflags);
+ idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
return k + 1; /* origin 1 */
}
#endif
@@ -2563,15 +2538,13 @@ sg_last_dev(void)
static Sg_device *
sg_get_dev(int dev)
{
- Sg_device *sdp = NULL;
+ Sg_device *sdp;
unsigned long iflags;
- if (sg_dev_arr && (dev >= 0)) {
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
- if (dev < sg_dev_max)
- sdp = sg_dev_arr[dev];
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- }
+ read_lock_irqsave(&sg_index_lock, iflags);
+ sdp = idr_find(&sg_index_idr, dev);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
+
return sdp;
}
@@ -2805,8 +2778,6 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos)
if (! it)
return NULL;
- if (NULL == sg_dev_arr)
- return NULL;
it->index = *pos;
it->max = sg_last_dev();
if (it->index >= it->max)
@@ -2942,8 +2913,8 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
Sg_device *sdp;
if (it && (0 == it->index)) {
- seq_printf(s, "dev_max(currently)=%d max_active_device=%d "
- "(origin 1)\n", sg_dev_max, (int)it->max);
+ seq_printf(s, "max_active_device=%d(origin 1)\n",
+ (int)it->max);
seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
}
sdp = it ? sg_get_dev(it->index) : NULL;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 902eb11ffe8..c6199903114 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -78,7 +78,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
static int sr_probe(struct device *);
static int sr_remove(struct device *);
-static int sr_init_command(struct scsi_cmnd *);
+static int sr_done(struct scsi_cmnd *);
static struct scsi_driver sr_template = {
.owner = THIS_MODULE,
@@ -87,7 +87,7 @@ static struct scsi_driver sr_template = {
.probe = sr_probe,
.remove = sr_remove,
},
- .init_command = sr_init_command,
+ .done = sr_done,
};
static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
@@ -210,12 +210,12 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
}
/*
- * rw_intr is the interrupt routine for the device driver.
+ * sr_done is the interrupt routine for the device driver.
*
- * It will be notified on the end of a SCSI read / write, and will take on
+ * It will be notified on the end of a SCSI read / write, and will take one
* of several actions based on success or failure.
*/
-static void rw_intr(struct scsi_cmnd * SCpnt)
+static int sr_done(struct scsi_cmnd *SCpnt)
{
int result = SCpnt->result;
int this_count = SCpnt->request_bufflen;
@@ -288,27 +288,42 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
}
}
- /*
- * This calls the generic completion function, now that we know
- * how many actual sectors finished, and how many sectors we need
- * to say have failed.
- */
- scsi_io_completion(SCpnt, good_bytes);
+ return good_bytes;
}
-static int sr_init_command(struct scsi_cmnd * SCpnt)
+static int sr_prep_fn(struct request_queue *q, struct request *rq)
{
int block=0, this_count, s_size, timeout = SR_TIMEOUT;
- struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+ struct scsi_cd *cd;
+ struct scsi_cmnd *SCpnt;
+ struct scsi_device *sdp = q->queuedata;
+ int ret;
+
+ if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+ ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+ goto out;
+ } else if (rq->cmd_type != REQ_TYPE_FS) {
+ ret = BLKPREP_KILL;
+ goto out;
+ }
+ ret = scsi_setup_fs_cmnd(sdp, rq);
+ if (ret != BLKPREP_OK)
+ goto out;
+ SCpnt = rq->special;
+ cd = scsi_cd(rq->rq_disk);
+
+ /* from here on until we're complete, any goto out
+ * is used for a killable error condition */
+ ret = BLKPREP_KILL;
SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
cd->disk->disk_name, block));
if (!cd->device || !scsi_device_online(cd->device)) {
SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
- SCpnt->request->nr_sectors));
+ rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
- return 0;
+ goto out;
}
if (cd->device->changed) {
@@ -316,7 +331,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
* quietly refuse to do anything to a changed disc until the
* changed bit has been reset
*/
- return 0;
+ goto out;
}
/*
@@ -333,21 +348,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (s_size != 512 && s_size != 1024 && s_size != 2048) {
scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size);
- return 0;
+ goto out;
}
- if (rq_data_dir(SCpnt->request) == WRITE) {
+ if (rq_data_dir(rq) == WRITE) {
if (!cd->device->writeable)
- return 0;
+ goto out;
SCpnt->cmnd[0] = WRITE_10;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
cd->cdi.media_written = 1;
- } else if (rq_data_dir(SCpnt->request) == READ) {
+ } else if (rq_data_dir(rq) == READ) {
SCpnt->cmnd[0] = READ_10;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
- return 0;
+ blk_dump_rq_flags(rq, "Unknown sr command");
+ goto out;
}
{
@@ -368,10 +383,10 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
/*
* request doesn't start on hw block boundary, add scatter pads
*/
- if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+ if (((unsigned int)rq->sector % (s_size >> 9)) ||
(SCpnt->request_bufflen % s_size)) {
scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
- return 0;
+ goto out;
}
this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
@@ -379,12 +394,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
cd->cdi.name,
- (rq_data_dir(SCpnt->request) == WRITE) ?
+ (rq_data_dir(rq) == WRITE) ?
"writing" : "reading",
- this_count, SCpnt->request->nr_sectors));
+ this_count, rq->nr_sectors));
SCpnt->cmnd[1] = 0;
- block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+ block = (unsigned int)rq->sector / (s_size >> 9);
if (this_count > 0xffff) {
this_count = 0xffff;
@@ -410,16 +425,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCpnt->timeout_per_command = timeout;
/*
- * This is the completion routine we use. This is matched in terms
- * of capability to this function.
- */
- SCpnt->done = rw_intr;
-
- /*
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ ret = BLKPREP_OK;
+ out:
+ return scsi_prep_return(q, rq, ret);
}
static int sr_block_open(struct inode *inode, struct file *file)
@@ -590,6 +601,7 @@ static int sr_probe(struct device *dev)
/* FIXME: need to handle a get_capabilities failure properly ?? */
get_capabilities(cd);
+ blk_queue_prep_rq(sdev->request_queue, sr_prep_fn);
sr_vendor_init(cd);
disk->driverfs_dev = &sdev->sdev_gendev;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 98e3fe10c1d..dc15a22105f 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -2055,7 +2055,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
case PHASE_DATAIN:
@@ -2115,7 +2115,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2254,25 +2254,21 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) &&
(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
ASEN_PRINTK("scsi%d: performing request sense\n",
HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
/* this is initialized from initialize_SCp
cmd->SCp.buffer = NULL;
cmd->SCp.buffers_residual = 0;
*/
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 5db1520f8ba..5c72ca31a47 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -567,12 +567,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
pDCB->TagMask |= 1 << tag[1];
pSRB->TagNumber = tag[1];
DC390_write8(ScsiFifo, tag[1]);
- DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->pid, pSRB, tag[1]));
+ DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1]));
cmd = SEL_W_ATN3;
} else {
/* No TagQ */
//no_tag:
- DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->pid, pSRB));
+ DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB));
}
pSRB->SRBState = SRB_START_;
@@ -623,7 +623,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
{
dc390_freetag (pDCB, pSRB);
DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n",
- scmd->pid, scmd->device->id, scmd->device->lun));
+ scmd->serial_number, scmd->device->id, scmd->device->lun));
pSRB->SRBState = SRB_READY;
//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
pACB->SelLost++;
@@ -1708,7 +1708,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
status = pSRB->TargetStatus;
DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
- pSRB, pcmd->pid));
+ pSRB, pcmd->serial_number));
if(pSRB->SRBFlag & AUTO_REQSENSE)
{ /* Last command was a Request Sense */
pSRB->SRBFlag &= ~AUTO_REQSENSE;
@@ -1729,7 +1729,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
} else {
SET_RES_DRV(pcmd->result, DRIVER_SENSE);
//pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8);
- DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+ DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
@@ -1749,7 +1749,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
else if (status == SAM_STAT_TASK_SET_FULL)
{
scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
- DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+ DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
@@ -1803,7 +1803,7 @@ cmd_done:
/* Add to free list */
dc390_Free_insert (pACB, pSRB);
- DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
+ DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number));
pcmd->scsi_done (pcmd);
return;
@@ -1998,7 +1998,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata;
scmd_printk(KERN_WARNING, cmd,
- "DC390: Abort command (pid %li)\n", cmd->pid);
+ "DC390: Abort command (pid %li)\n", cmd->serial_number);
/* abort() is too stupid for already sent commands at the moment.
* If it's called we are in trouble anyway, so let's dump some info
@@ -2006,7 +2006,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
dc390_dumpinfo(pACB, pDCB, NULL);
pDCB->DCBFlag |= ABORT_DEV_;
- printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid);
+ printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number);
return FAILED;
}
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 9e8232a1f16..fc9f51818e8 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1254,7 +1254,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
if (SCpnt->host_scribble)
panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
- BN(j), SCpnt->pid, SCpnt);
+ BN(j), SCpnt->serial_number, SCpnt);
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
@@ -1285,7 +1285,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCpnt->device->channel, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->pid);
+ SCpnt->device->lun, SCpnt->serial_number);
cpp->opcode = OP_SCSI;
cpp->channel = SCpnt->device->channel;
@@ -1312,7 +1312,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
unmap_dma(i, j);
SCpnt->host_scribble = NULL;
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+ "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
return 1;
}
@@ -1333,13 +1333,13 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
if (SCarg->host_scribble == NULL) {
scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n",
- SCarg->pid);
+ SCarg->serial_number);
return SUCCESS;
}
i = *(unsigned int *)SCarg->host_scribble;
scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n",
- i, SCarg->pid);
+ i, SCarg->serial_number);
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -1383,7 +1383,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
+ BN(j), i, SCarg->serial_number);
SCarg->scsi_done(SCarg);
return SUCCESS;
}
@@ -1397,12 +1397,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
struct scsi_cmnd *SCpnt;
j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
- scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->pid);
+ scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number);
spin_lock_irq(sh[j]->host_lock);
if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number);
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
@@ -1440,13 +1440,13 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
HD(j)->cp_stat[i] = ABORTING;
printk("%s: reset, mbox %d aborting, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else {
HD(j)->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
if (SCpnt->host_scribble == NULL)
@@ -1495,7 +1495,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1508,7 +1508,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->cp_stat[i] = FREE;
printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else
@@ -1522,7 +1522,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->in_reset = FALSE;
do_trace = FALSE;
- if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+ if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number);
else printk("%s: reset, exit.\n", BN(j));
spin_unlock_irq(sh[j]->host_lock);
@@ -1639,7 +1639,7 @@ static int reorder(unsigned int j, unsigned long cursec,
if (!input_only) for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
+ ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number;
if (!n) continue;
@@ -1666,7 +1666,7 @@ static int reorder(unsigned int j, unsigned long cursec,
printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\
" cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
- SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
+ SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready,
SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->xdir);
@@ -1703,7 +1703,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in
scmd_printk(KERN_INFO, SCpnt,
"%s, pid %ld, mbox %d, adapter"
" busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k);
+ SCpnt->serial_number, k);
HD(j)->cp_stat[k] = ABORTING;
continue;
}
@@ -1787,11 +1787,11 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
- SCpnt->pid, SCpnt);
+ SCpnt->serial_number, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
- BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+ BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble);
sync_dma(i, j);
@@ -1835,12 +1835,12 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
(SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
scmd_printk(KERN_INFO, SCpnt,
"ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n",
- SCpnt->pid, spp->target_status,
+ SCpnt->serial_number, spp->target_status,
SCpnt->sense_buffer[2]);
HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0;
- if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+ if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0;
break;
case ASST: /* Selection Time Out */
@@ -1877,7 +1877,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
#endif
HD(j)->retries++;
- HD(j)->last_retried_pid = SCpnt->pid;
+ HD(j)->last_retried_pid = SCpnt->serial_number;
}
else
status = DID_ERROR << 16;
@@ -1907,7 +1907,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
#endif
scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\
" pid %ld, reg 0x%x, count %d.\n",
- i, spp->adapter_status, spp->target_status, SCpnt->pid,
+ i, spp->adapter_status, spp->target_status, SCpnt->serial_number,
reg, HD(j)->iocount);
unmap_dma(i, j);
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index b92ff047af3..0e8e642fd3b 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -381,7 +381,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
DB(DB_QUEUE_COMMAND,
- printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid))
+ printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number))
/* Set up a few fields in the scsi_cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
@@ -463,7 +463,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
wd33c93_execute(cmd->device->host);
- DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+ DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
spin_unlock_irq(&hostdata->lock);
return 0;
@@ -686,7 +686,7 @@ wd33c93_execute(struct Scsi_Host *instance)
*/
DB(DB_EXECUTE,
- printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+ printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
}
static void
@@ -963,7 +963,7 @@ wd33c93_intr(struct Scsi_Host *instance)
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+ DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
hostdata);
hostdata->state = S_CONNECTED;
@@ -1007,7 +1007,7 @@ wd33c93_intr(struct Scsi_Host *instance)
switch (msg) {
case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+ DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
@@ -1174,7 +1174,7 @@ wd33c93_intr(struct Scsi_Host *instance)
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+ DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_wd33c93(regs, WD_TARGET_LUN);
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1201,7 +1201,7 @@ wd33c93_intr(struct Scsi_Host *instance)
} else {
printk
("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",
- asr, sr, phs, cmd->pid);
+ asr, sr, phs, cmd->serial_number);
spin_unlock_irqrestore(&hostdata->lock, flags);
}
break;
@@ -1266,7 +1266,7 @@ wd33c93_intr(struct Scsi_Host *instance)
spin_unlock_irqrestore(&hostdata->lock, flags);
return;
}
- DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
@@ -1292,7 +1292,7 @@ wd33c93_intr(struct Scsi_Host *instance)
*/
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
@@ -1491,7 +1491,7 @@ wd33c93_intr(struct Scsi_Host *instance)
} else
hostdata->state = S_CONNECTED;
- DB(DB_INTR, printk("-%ld", cmd->pid))
+ DB(DB_INTR, printk("-%ld", cmd->serial_number))
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
@@ -1638,7 +1638,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
cmd->result = DID_ABORT << 16;
printk
("scsi%d: Abort - removing command %ld from input_Q. ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
enable_irq(cmd->device->host->irq);
cmd->scsi_done(cmd);
return SUCCESS;
@@ -1663,7 +1663,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
unsigned long timeout;
printk("scsi%d: Aborting connected command %ld - ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
printk("stopping DMA - ");
if (hostdata->dma == D_DMA_RUNNING) {
@@ -1730,7 +1730,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
if (tmp == cmd) {
printk
("scsi%d: Abort - command %ld found on disconnected_Q - ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
printk("Abort SNOOZE. ");
enable_irq(cmd->device->host->irq);
return FAILED;
@@ -2184,7 +2184,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
if (hd->connected) {
cmd = (struct scsi_cmnd *) hd->connected;
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
@@ -2193,7 +2193,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
cmd = (struct scsi_cmnd *) hd->input_Q;
while (cmd) {
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
@@ -2203,7 +2203,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
cmd = (struct scsi_cmnd *) hd->disconnected_Q;
while (cmd) {
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index c822debc266..ac67394c737 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -69,7 +69,7 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
static int __devinit zorro7xx_init_one(struct zorro_dev *z,
const struct zorro_device_id *ent)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
struct zorro_driver_data *zdd;
unsigned long board, ioaddr;
@@ -89,14 +89,12 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
return -EBUSY;
}
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "zorro7xx: Failed to allocate host data\n");
goto out_release;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-
/* Fill in the required pieces of hostdata */
if (ioaddr > 0x01000000)
hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 035cca02819..ec36ad78d2f 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -756,8 +756,8 @@ mpc52xx_console_setup(struct console *co, char *options)
if (port->membase == NULL)
return -EINVAL;
- pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n",
- port->mapbase, port->membase, port->irq, port->uartclk);
+ pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+ (void*)port->mapbase, port->membase, port->irq, port->uartclk);
/* Setup the port parameters accoding to options */
if (options)
@@ -974,8 +974,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
port->mapbase = res.start;
port->irq = irq_of_parse_and_map(op->node, 0);
- dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n",
- port->mapbase, port->irq, port->uartclk);
+ dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+ (void*)port->mapbase, port->irq, port->uartclk);
if ((port->irq==NO_IRQ) || !port->mapbase) {
printk(KERN_ERR "Could not allocate resources for PSC\n");
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 053fca41b08..73440e26834 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -4,6 +4,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
* Copyright (C) 2002 - 2006 Paul Mundt
+ * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
*
@@ -301,6 +302,38 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
}
sci_out(port, SCFCR, fcr_val);
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+ unsigned short data;
+
+ if (cflag & CRTSCTS) {
+ /* enable RTS/CTS */
+ if (port->mapbase == 0xa4430000) { /* SCIF0 */
+ /* Clear PTCR bit 9-2; enable all scif pins but sck */
+ data = ctrl_inw(PORT_PTCR);
+ ctrl_outw((data & 0xfc03), PORT_PTCR);
+ } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+ /* Clear PVCR bit 9-2 */
+ data = ctrl_inw(PORT_PVCR);
+ ctrl_outw((data & 0xfc03), PORT_PVCR);
+ }
+ fcr_val |= SCFCR_MCE;
+ } else {
+ if (port->mapbase == 0xa4430000) { /* SCIF0 */
+ /* Clear PTCR bit 5-2; enable only tx and rx */
+ data = ctrl_inw(PORT_PTCR);
+ ctrl_outw((data & 0xffc3), PORT_PTCR);
+ } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+ /* Clear PVCR bit 5-2 */
+ data = ctrl_inw(PORT_PVCR);
+ ctrl_outw((data & 0xffc3), PORT_PVCR);
+ }
+ }
+ sci_out(port, SCFCR, fcr_val);
+}
+
#elif defined(CONFIG_CPU_SH3)
/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -1276,7 +1309,7 @@ static int __init sci_console_init(void)
console_initcall(sci_console_init);
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-#ifdef CONFIG_SH_KGDB
+#ifdef CONFIG_SH_KGDB_CONSOLE
/*
* FIXME: Most of this can go away.. at the moment, we rely on
* arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
@@ -1334,9 +1367,7 @@ int __init kgdb_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-#endif /* CONFIG_SH_KGDB */
-#ifdef CONFIG_SH_KGDB_CONSOLE
static struct console kgdb_console = {
.name = "ttySC",
.device = uart_console_device,
@@ -1432,7 +1463,7 @@ static int __devinit sci_probe(struct platform_device *dev)
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
- dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
+ dev_info(&dev->dev, "CPU frequency notifier registered\n");
#endif
#ifdef CONFIG_SH_STANDARD_BIOS
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index cf75466ebf5..e89ae29645d 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -10,19 +10,19 @@
* Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
* Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
* Removed SH7300 support (Jul 2007).
+ * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007).
*/
#include <linux/serial_core.h>
#include <asm/io.h>
-#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
+
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
#include <asm/regs306x.h>
#endif
#if defined(CONFIG_H8S2678)
#include <asm/regs267x.h>
#endif
-#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
@@ -46,6 +46,10 @@
*/
# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCIF_ONLY
+#define SCIF_ORER 0x0200 /* overrun error bit */
#elif defined(CONFIG_SH_RTS7751R2D)
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -217,7 +221,8 @@
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCIF_ORER 0x0200
#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
#define SCIF_RFDC_MASK 0x007f
@@ -254,7 +259,8 @@
# define SCxSR_FER(port) SCIF_FER
# define SCxSR_PER(port) SCIF_PER
# define SCxSR_BRK(port) SCIF_BRK
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc)
# define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73)
# define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf)
@@ -362,7 +368,8 @@
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -388,7 +395,8 @@
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
@@ -510,7 +518,15 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
return;
}
}
-
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xa4430000)
+ return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+ else if (port->mapbase == 0xa4438000)
+ return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
@@ -653,6 +669,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffc60000)
return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#endif
@@ -691,7 +708,8 @@ static inline int sci_rxd_in(struct uart_port *port)
#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
defined(CONFIG_CPU_SUBTYPE_SH7785)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
#elif defined(__H8300H__) || defined(__H8300S__)
#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 8a143894e33..a96f4a8cfeb 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -2,5 +2,5 @@
# Makefile for the SuperH specific drivers.
#
-obj-$(CONFIG_SUPERHYWAY) += superhyway/
-
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
+obj-$(CONFIG_MAPLE) += maple/
diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile
new file mode 100644
index 00000000000..65dfeeb610e
--- /dev/null
+++ b/drivers/sh/maple/Makefile
@@ -0,0 +1,3 @@
+# Makefile for Maple Bus
+
+obj-$(CONFIG_MAPLE) := maple.o
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
new file mode 100644
index 00000000000..161d1021b7e
--- /dev/null
+++ b/drivers/sh/maple/maple.c
@@ -0,0 +1,735 @@
+/*
+ * Core maple bus functionality
+ *
+ * Copyright (C) 2007 Adrian McMenamin
+ *
+ * Based on 2.4 code by:
+ *
+ * Copyright (C) 2000-2001 YAEGASHI Takeshi
+ * Copyright (C) 2001 M. R. Brown
+ * Copyright (C) 2001 Paul Mundt
+ *
+ * and others.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/maple.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+#include <asm/mach/maple.h>
+
+MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin");
+MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
+
+static void maple_dma_handler(struct work_struct *work);
+static void maple_vblank_handler(struct work_struct *work);
+
+static DECLARE_WORK(maple_dma_process, maple_dma_handler);
+static DECLARE_WORK(maple_vblank_process, maple_vblank_handler);
+
+static LIST_HEAD(maple_waitq);
+static LIST_HEAD(maple_sentq);
+
+static DEFINE_MUTEX(maple_list_lock);
+
+static struct maple_driver maple_dummy_driver;
+static struct device maple_bus;
+static int subdevice_map[MAPLE_PORTS];
+static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
+static unsigned long maple_pnp_time;
+static int started, scanning, liststatus;
+static struct kmem_cache *maple_queue_cache;
+
+struct maple_device_specify {
+ int port;
+ int unit;
+};
+
+/**
+ * maple_driver_register - register a device driver
+ * automatically makes the driver bus a maple bus
+ * @drv: the driver to be registered
+ */
+int maple_driver_register(struct device_driver *drv)
+{
+ if (!drv)
+ return -EINVAL;
+ drv->bus = &maple_bus_type;
+ return driver_register(drv);
+}
+EXPORT_SYMBOL_GPL(maple_driver_register);
+
+/* set hardware registers to enable next round of dma */
+static void maplebus_dma_reset(void)
+{
+ ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
+ /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
+ ctrl_outl(1, MAPLE_TRIGTYPE);
+ ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);
+ ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
+ ctrl_outl(1, MAPLE_ENABLE);
+}
+
+/**
+ * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND
+ * @dev: device responding
+ * @callback: handler callback
+ * @interval: interval in jiffies between callbacks
+ * @function: the function code for the device
+ */
+void maple_getcond_callback(struct maple_device *dev,
+ void (*callback) (struct mapleq * mq),
+ unsigned long interval, unsigned long function)
+{
+ dev->callback = callback;
+ dev->interval = interval;
+ dev->function = cpu_to_be32(function);
+ dev->when = jiffies;
+}
+EXPORT_SYMBOL_GPL(maple_getcond_callback);
+
+static int maple_dma_done(void)
+{
+ return (ctrl_inl(MAPLE_STATE) & 1) == 0;
+}
+
+static void maple_release_device(struct device *dev)
+{
+ if (dev->type) {
+ kfree(dev->type->name);
+ kfree(dev->type);
+ }
+}
+
+/**
+ * maple_add_packet - add a single instruction to the queue
+ * @mq: instruction to add to waiting queue
+ */
+void maple_add_packet(struct mapleq *mq)
+{
+ mutex_lock(&maple_list_lock);
+ list_add(&mq->list, &maple_waitq);
+ mutex_unlock(&maple_list_lock);
+}
+EXPORT_SYMBOL_GPL(maple_add_packet);
+
+static struct mapleq *maple_allocq(struct maple_device *dev)
+{
+ struct mapleq *mq;
+
+ mq = kmalloc(sizeof(*mq), GFP_KERNEL);
+ if (!mq)
+ return NULL;
+
+ mq->dev = dev;
+ mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
+ mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
+ if (!mq->recvbuf) {
+ kfree(mq);
+ return NULL;
+ }
+
+ return mq;
+}
+
+static struct maple_device *maple_alloc_dev(int port, int unit)
+{
+ struct maple_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->port = port;
+ dev->unit = unit;
+ dev->mq = maple_allocq(dev);
+
+ if (!dev->mq) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static void maple_free_dev(struct maple_device *mdev)
+{
+ if (!mdev)
+ return;
+ if (mdev->mq) {
+ kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp);
+ kfree(mdev->mq);
+ }
+ kfree(mdev);
+}
+
+/* process the command queue into a maple command block
+ * terminating command has bit 32 of first long set to 0
+ */
+static void maple_build_block(struct mapleq *mq)
+{
+ int port, unit, from, to, len;
+ unsigned long *lsendbuf = mq->sendbuf;
+
+ port = mq->dev->port & 3;
+ unit = mq->dev->unit;
+ len = mq->length;
+ from = port << 6;
+ to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20);
+
+ *maple_lastptr &= 0x7fffffff;
+ maple_lastptr = maple_sendptr;
+
+ *maple_sendptr++ = (port << 16) | len | 0x80000000;
+ *maple_sendptr++ = PHYSADDR(mq->recvbuf);
+ *maple_sendptr++ =
+ mq->command | (to << 8) | (from << 16) | (len << 24);
+
+ while (len-- > 0)
+ *maple_sendptr++ = *lsendbuf++;
+}
+
+/* build up command queue */
+static void maple_send(void)
+{
+ int i;
+ int maple_packets;
+ struct mapleq *mq, *nmq;
+
+ if (!list_empty(&maple_sentq))
+ return;
+ if (list_empty(&maple_waitq) || !maple_dma_done())
+ return;
+ maple_packets = 0;
+ maple_sendptr = maple_lastptr = maple_sendbuf;
+ list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
+ maple_build_block(mq);
+ list_move(&mq->list, &maple_sentq);
+ if (maple_packets++ > MAPLE_MAXPACKETS)
+ break;
+ }
+ if (maple_packets > 0) {
+ for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++)
+ dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ }
+}
+
+static int attach_matching_maple_driver(struct device_driver *driver,
+ void *devptr)
+{
+ struct maple_driver *maple_drv;
+ struct maple_device *mdev;
+
+ mdev = devptr;
+ maple_drv = to_maple_driver(driver);
+ if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) {
+ if (maple_drv->connect(mdev) == 0) {
+ mdev->driver = maple_drv;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void maple_detach_driver(struct maple_device *mdev)
+{
+ if (!mdev)
+ return;
+ if (mdev->driver) {
+ if (mdev->driver->disconnect)
+ mdev->driver->disconnect(mdev);
+ }
+ mdev->driver = NULL;
+ if (mdev->registered) {
+ maple_release_device(&mdev->dev);
+ device_unregister(&mdev->dev);
+ }
+ mdev->registered = 0;
+ maple_free_dev(mdev);
+}
+
+/* process initial MAPLE_COMMAND_DEVINFO for each device or port */
+static void maple_attach_driver(struct maple_device *dev)
+{
+ char *p;
+
+ char *recvbuf;
+ unsigned long function;
+ int matched, retval;
+
+ recvbuf = dev->mq->recvbuf;
+ memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo));
+ memcpy(dev->product_name, dev->devinfo.product_name, 30);
+ memcpy(dev->product_licence, dev->devinfo.product_licence, 60);
+ dev->product_name[30] = '\0';
+ dev->product_licence[60] = '\0';
+
+ for (p = dev->product_name + 29; dev->product_name <= p; p--)
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+
+ for (p = dev->product_licence + 59; dev->product_licence <= p; p--)
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+
+ function = be32_to_cpu(dev->devinfo.function);
+
+ if (function > 0x200) {
+ /* Do this silently - as not a real device */
+ function = 0;
+ dev->driver = &maple_dummy_driver;
+ sprintf(dev->dev.bus_id, "%d:0.port", dev->port);
+ } else {
+ printk(KERN_INFO
+ "Maple bus at (%d, %d): Connected function 0x%lX\n",
+ dev->port, dev->unit, function);
+
+ matched =
+ bus_for_each_drv(&maple_bus_type, NULL, dev,
+ attach_matching_maple_driver);
+
+ if (matched == 0) {
+ /* Driver does not exist yet */
+ printk(KERN_INFO
+ "No maple driver found for this device\n");
+ dev->driver = &maple_dummy_driver;
+ }
+
+ sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port,
+ dev->unit, function);
+ }
+ dev->function = function;
+ dev->dev.bus = &maple_bus_type;
+ dev->dev.parent = &maple_bus;
+ dev->dev.release = &maple_release_device;
+ retval = device_register(&dev->dev);
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Attempt to register device (%x, %x) failed.\n",
+ dev->port, dev->unit);
+ maple_free_dev(dev);
+ }
+ dev->registered = 1;
+}
+
+/*
+ * if device has been registered for the given
+ * port and unit then return 1 - allows identification
+ * of which devices need to be attached or detached
+ */
+static int detach_maple_device(struct device *device, void *portptr)
+{
+ struct maple_device_specify *ds;
+ struct maple_device *mdev;
+
+ ds = portptr;
+ mdev = to_maple_dev(device);
+ if (mdev->port == ds->port && mdev->unit == ds->unit)
+ return 1;
+ return 0;
+}
+
+static int setup_maple_commands(struct device *device, void *ignored)
+{
+ struct maple_device *maple_dev = to_maple_dev(device);
+
+ if ((maple_dev->interval > 0)
+ && time_after(jiffies, maple_dev->when)) {
+ maple_dev->when = jiffies + maple_dev->interval;
+ maple_dev->mq->command = MAPLE_COMMAND_GETCOND;
+ maple_dev->mq->sendbuf = &maple_dev->function;
+ maple_dev->mq->length = 1;
+ maple_add_packet(maple_dev->mq);
+ liststatus++;
+ } else {
+ if (time_after(jiffies, maple_pnp_time)) {
+ maple_dev->mq->command = MAPLE_COMMAND_DEVINFO;
+ maple_dev->mq->length = 0;
+ maple_add_packet(maple_dev->mq);
+ liststatus++;
+ }
+ }
+
+ return 0;
+}
+
+/* VBLANK bottom half - implemented via workqueue */
+static void maple_vblank_handler(struct work_struct *work)
+{
+ if (!maple_dma_done())
+ return;
+ if (!list_empty(&maple_sentq))
+ return;
+ ctrl_outl(0, MAPLE_ENABLE);
+ liststatus = 0;
+ bus_for_each_dev(&maple_bus_type, NULL, NULL,
+ setup_maple_commands);
+ if (time_after(jiffies, maple_pnp_time))
+ maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
+ if (liststatus && list_empty(&maple_sentq)) {
+ INIT_LIST_HEAD(&maple_sentq);
+ maple_send();
+ }
+ maplebus_dma_reset();
+}
+
+/* handle devices added via hotplugs - placing them on queue for DEVINFO*/
+static void maple_map_subunits(struct maple_device *mdev, int submask)
+{
+ int retval, k, devcheck;
+ struct maple_device *mdev_add;
+ struct maple_device_specify ds;
+
+ for (k = 0; k < 5; k++) {
+ ds.port = mdev->port;
+ ds.unit = k + 1;
+ retval =
+ bus_for_each_dev(&maple_bus_type, NULL, &ds,
+ detach_maple_device);
+ if (retval) {
+ submask = submask >> 1;
+ continue;
+ }
+ devcheck = submask & 0x01;
+ if (devcheck) {
+ mdev_add = maple_alloc_dev(mdev->port, k + 1);
+ if (!mdev_add)
+ return;
+ mdev_add->mq->command = MAPLE_COMMAND_DEVINFO;
+ mdev_add->mq->length = 0;
+ maple_add_packet(mdev_add->mq);
+ scanning = 1;
+ }
+ submask = submask >> 1;
+ }
+}
+
+/* mark a device as removed */
+static void maple_clean_submap(struct maple_device *mdev)
+{
+ int killbit;
+
+ killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20);
+ killbit = ~killbit;
+ killbit &= 0xFF;
+ subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit;
+}
+
+/* handle empty port or hotplug removal */
+static void maple_response_none(struct maple_device *mdev,
+ struct mapleq *mq)
+{
+ if (mdev->unit != 0) {
+ list_del(&mq->list);
+ maple_clean_submap(mdev);
+ printk(KERN_INFO
+ "Maple bus device detaching at (%d, %d)\n",
+ mdev->port, mdev->unit);
+ maple_detach_driver(mdev);
+ return;
+ }
+ if (!started) {
+ printk(KERN_INFO "No maple devices attached to port %d\n",
+ mdev->port);
+ return;
+ }
+ maple_clean_submap(mdev);
+}
+
+/* preprocess hotplugs or scans */
+static void maple_response_devinfo(struct maple_device *mdev,
+ char *recvbuf)
+{
+ char submask;
+ if ((!started) || (scanning == 2)) {
+ maple_attach_driver(mdev);
+ return;
+ }
+ if (mdev->unit == 0) {
+ submask = recvbuf[2] & 0x1F;
+ if (submask ^ subdevice_map[mdev->port]) {
+ maple_map_subunits(mdev, submask);
+ subdevice_map[mdev->port] = submask;
+ }
+ }
+}
+
+/* maple dma end bottom half - implemented via workqueue */
+static void maple_dma_handler(struct work_struct *work)
+{
+ struct mapleq *mq, *nmq;
+ struct maple_device *dev;
+ char *recvbuf;
+ enum maple_code code;
+
+ if (!maple_dma_done())
+ return;
+ ctrl_outl(0, MAPLE_ENABLE);
+ if (!list_empty(&maple_sentq)) {
+ list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
+ recvbuf = mq->recvbuf;
+ code = recvbuf[0];
+ dev = mq->dev;
+ switch (code) {
+ case MAPLE_RESPONSE_NONE:
+ maple_response_none(dev, mq);
+ break;
+
+ case MAPLE_RESPONSE_DEVINFO:
+ maple_response_devinfo(dev, recvbuf);
+ break;
+
+ case MAPLE_RESPONSE_DATATRF:
+ if (dev->callback)
+ dev->callback(mq);
+ break;
+
+ case MAPLE_RESPONSE_FILEERR:
+ case MAPLE_RESPONSE_AGAIN:
+ case MAPLE_RESPONSE_BADCMD:
+ case MAPLE_RESPONSE_BADFUNC:
+ printk(KERN_DEBUG
+ "Maple non-fatal error 0x%X\n",
+ code);
+ break;
+
+ case MAPLE_RESPONSE_ALLINFO:
+ printk(KERN_DEBUG
+ "Maple - extended device information not supported\n");
+ break;
+
+ case MAPLE_RESPONSE_OK:
+ break;
+
+ default:
+ break;
+ }
+ }
+ INIT_LIST_HEAD(&maple_sentq);
+ if (scanning == 1) {
+ maple_send();
+ scanning = 2;
+ } else
+ scanning = 0;
+
+ if (started == 0)
+ started = 1;
+ }
+ maplebus_dma_reset();
+}
+
+static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id)
+{
+ /* Load everything into the bottom half */
+ schedule_work(&maple_dma_process);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
+{
+ schedule_work(&maple_vblank_process);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction maple_dma_irq = {
+ .name = "maple bus DMA handler",
+ .handler = maplebus_dma_interrupt,
+ .flags = IRQF_SHARED,
+};
+
+static struct irqaction maple_vblank_irq = {
+ .name = "maple bus VBLANK handler",
+ .handler = maplebus_vblank_interrupt,
+ .flags = IRQF_SHARED,
+};
+
+static int maple_set_dma_interrupt_handler(void)
+{
+ return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq);
+}
+
+static int maple_set_vblank_interrupt_handler(void)
+{
+ return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq);
+}
+
+static int maple_get_dma_buffer(void)
+{
+ maple_sendbuf =
+ (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ MAPLE_DMA_PAGES);
+ if (!maple_sendbuf)
+ return -ENOMEM;
+ return 0;
+}
+
+static int match_maple_bus_driver(struct device *devptr,
+ struct device_driver *drvptr)
+{
+ struct maple_driver *maple_drv;
+ struct maple_device *maple_dev;
+
+ maple_drv = container_of(drvptr, struct maple_driver, drv);
+ maple_dev = container_of(devptr, struct maple_device, dev);
+ /* Trap empty port case */
+ if (maple_dev->devinfo.function == 0xFFFFFFFF)
+ return 0;
+ else if (maple_dev->devinfo.function &
+ be32_to_cpu(maple_drv->function))
+ return 1;
+ return 0;
+}
+
+static int maple_bus_uevent(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ return 0;
+}
+
+static void maple_bus_release(struct device *dev)
+{
+}
+
+static struct maple_driver maple_dummy_driver = {
+ .drv = {
+ .name = "maple_dummy_driver",
+ .bus = &maple_bus_type,
+ },
+};
+
+struct bus_type maple_bus_type = {
+ .name = "maple",
+ .match = match_maple_bus_driver,
+ .uevent = maple_bus_uevent,
+};
+EXPORT_SYMBOL_GPL(maple_bus_type);
+
+static struct device maple_bus = {
+ .bus_id = "maple",
+ .release = maple_bus_release,
+};
+
+static int __init maple_bus_init(void)
+{
+ int retval, i;
+ struct maple_device *mdev[MAPLE_PORTS];
+ ctrl_outl(0, MAPLE_STATE);
+
+ retval = device_register(&maple_bus);
+ if (retval)
+ goto cleanup;
+
+ retval = bus_register(&maple_bus_type);
+ if (retval)
+ goto cleanup_device;
+
+ retval = driver_register(&maple_dummy_driver.drv);
+
+ if (retval)
+ goto cleanup_bus;
+
+ /* allocate memory for maple bus dma */
+ retval = maple_get_dma_buffer();
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Failed to allocate Maple DMA buffers\n");
+ goto cleanup_basic;
+ }
+
+ /* set up DMA interrupt handler */
+ retval = maple_set_dma_interrupt_handler();
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Failed to grab maple DMA IRQ\n");
+ goto cleanup_dma;
+ }
+
+ /* set up VBLANK interrupt handler */
+ retval = maple_set_vblank_interrupt_handler();
+ if (retval) {
+ printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n");
+ goto cleanup_irq;
+ }
+
+ maple_queue_cache =
+ kmem_cache_create("maple_queue_cache", 0x400, 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+
+ if (!maple_queue_cache)
+ goto cleanup_bothirqs;
+
+ /* setup maple ports */
+ for (i = 0; i < MAPLE_PORTS; i++) {
+ mdev[i] = maple_alloc_dev(i, 0);
+ if (!mdev[i]) {
+ while (i-- > 0)
+ maple_free_dev(mdev[i]);
+ goto cleanup_cache;
+ }
+ mdev[i]->registered = 0;
+ mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO;
+ mdev[i]->mq->length = 0;
+ maple_attach_driver(mdev[i]);
+ maple_add_packet(mdev[i]->mq);
+ subdevice_map[i] = 0;
+ }
+
+ /* setup maplebus hardware */
+ maplebus_dma_reset();
+
+ /* initial detection */
+ maple_send();
+
+ maple_pnp_time = jiffies;
+
+ printk(KERN_INFO "Maple bus core now registered.\n");
+
+ return 0;
+
+cleanup_cache:
+ kmem_cache_destroy(maple_queue_cache);
+
+cleanup_bothirqs:
+ free_irq(HW_EVENT_VSYNC, 0);
+
+cleanup_irq:
+ free_irq(HW_EVENT_MAPLE_DMA, 0);
+
+cleanup_dma:
+ free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
+
+cleanup_basic:
+ driver_unregister(&maple_dummy_driver.drv);
+
+cleanup_bus:
+ bus_unregister(&maple_bus_type);
+
+cleanup_device:
+ device_unregister(&maple_bus);
+
+cleanup:
+ printk(KERN_INFO "Maple bus registration failed\n");
+ return retval;
+}
+subsys_initcall(maple_bus_init);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e84d2159794..bcb8dd5fb0b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
}
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
- envp[1] = NULL;
+ add_uevent_var(env, "MODALIAS=%s", spi->modalias);
return 0;
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 74d5182db4b..c12a741b557 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -11,6 +11,7 @@
#include "ssb_private.h"
#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_regs.h>
#include <linux/dma-mapping.h>
@@ -320,23 +321,17 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int ssb_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
- int ret, i = 0, length = 0;
if (!dev)
return -ENODEV;
- ret = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ return add_uevent_var(env,
"MODALIAS=ssb:v%04Xid%04Xrev%02X",
ssb_dev->id.vendor, ssb_dev->id.coreid,
ssb_dev->id.revision);
- envp[i] = NULL;
-
- return ret;
}
static struct bus_type ssb_bustype = {
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index 7c773603b40..b6abee846f0 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -10,6 +10,7 @@
#include <linux/ssb/ssb.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ac49b15fa76..516a6400db4 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
-obj-$(CONFIG_USB_ADUTUX) += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
-obj-$(CONFIG_USB_AUERSWALD) += misc/
-obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM) += misc/
-obj-$(CONFIG_USB_EMI26) += misc/
-obj-$(CONFIG_USB_EMI62) += misc/
-obj-$(CONFIG_USB_FTDI_ELAN) += misc/
-obj-$(CONFIG_USB_IDMOUSE) += misc/
-obj-$(CONFIG_USB_LCD) += misc/
-obj-$(CONFIG_USB_LD) += misc/
-obj-$(CONFIG_USB_LED) += misc/
-obj-$(CONFIG_USB_LEGOTOWER) += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_RIO500) += misc/
-obj-$(CONFIG_USB_SISUSBVGA) += misc/
-obj-$(CONFIG_USB_TEST) += misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720) += misc/
-obj-$(CONFIG_USB_IOWARRIOR) += misc/
+obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index a73e714288e..a51eeedc18d 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
- dbg("too big transfer requested");
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+ wbuflen, rbuflen);
ret = -ENOMEM;
goto fail;
}
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting read urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting write urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
- dbg("sending cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
- dbg("receiving cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
- dbg("response is not a positive multiple of %d: %#x",
- CMD_PACKET_SIZE, actlen);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+ cm, actlen);
ret = -EIO;
goto fail;
}
@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
- dbg("wrong cm %#x in response", rbuf[offb]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+ rbuf[offb], cm);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
- dbg("response failed: %#x", rbuf[offb + 1]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+ cm, rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
- dbg("wrong data length %#x in response", l);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+ cm, l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
- dbg("wrong index %#x in response", offd);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+ offd, cm);
ret = -EIO;
goto cleanup;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index eb0615abff6..7d27c9cf3c4 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -88,7 +88,7 @@ static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
static unsigned char ModemMode = DEFAULT_MODEM_MODE;
static unsigned char ModemOption[MODEM_OPTION_LENGTH];
-static int num_ModemOption;
+static unsigned int num_ModemOption;
module_param(altsetting, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(altsetting,
@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
- struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
- if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+ if (!usb_ifnum_to_if(usb_dev, 2)) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 29807d048b0..389c5b164eb 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2,7 +2,8 @@
* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -107,18 +108,51 @@
#define uea_info(usb_dev, format,args...) \
dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
u32 address;
u16 offset;
u32 data;
} __attribute__ ((packed));
+struct uea_cmvs_v2 {
+ u32 group;
+ u32 address;
+ u32 offset;
+ u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+ u8 function;
+ u16 idx;
+ u32 address;
+ u16 offset;
+};
+
+struct cmv_dsc_e4 {
+ u16 function;
+ u16 offset;
+ u16 address;
+ u16 group;
+};
+
+union cmv_dsc {
+ struct cmv_dsc_e1 e1;
+ struct cmv_dsc_e4 e4;
+};
+
struct uea_softc {
struct usb_device *usb_dev;
struct usbatm_data *usbatm;
int modem_index;
unsigned int driver_info;
+ int annex;
+#define ANNEXA 0
+#define ANNEXB 1
int booting;
int reset;
@@ -127,20 +161,23 @@ struct uea_softc {
struct task_struct *kthread;
u32 data;
- wait_queue_head_t cmv_ack_wait;
+ u32 data1;
+
int cmv_ack;
+ union cmv_dsc cmv_dsc;
struct work_struct task;
+ struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
const struct firmware *dsp_firm;
struct urb *urb_int;
- u8 cmv_function;
- u16 cmv_idx;
- u32 cmv_address;
- u16 cmv_offset;
+ void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+ void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+ int (*stat) (struct uea_softc *);
+ int (*send_cmvs) (struct uea_softc *);
/* keep in sync with eaglectl */
struct uea_stats {
@@ -174,10 +211,34 @@ struct uea_softc {
#define ELSA_PID_PSTFIRM 0x3350
#define ELSA_PID_PREFIRM 0x3351
+#define ELSA_PID_A_PREFIRM 0x3352
+#define ELSA_PID_A_PSTFIRM 0x3353
+#define ELSA_PID_B_PREFIRM 0x3362
+#define ELSA_PID_B_PSTFIRM 0x3363
+
/*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
*/
-#define EAGLE_VID 0x1110
+#define DEVOLO_VID 0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID 0x1110
+#define ADI930_PID_PREFIRM 0x9001
+#define ADI930_PID_PSTFIRM 0x9000
+
#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */
#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */
@@ -187,12 +248,12 @@ struct uea_softc {
#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */
#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */
-/*
- * Eagle III Pid
- */
#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */
#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */
+#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */
+
/*
* USR USB IDs
*/
@@ -208,11 +269,15 @@ struct uea_softc {
#define PREFIRM 0
#define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
enum {
ADI930 = 0,
EAGLE_I,
EAGLE_II,
- EAGLE_III
+ EAGLE_III,
+ EAGLE_IV
};
/* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
-#define IS_ISDN(usb_dev) \
- (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+ ((x)->annex & ANNEXB)
#define INS_TO_USBDEV(ins) ins->usb_dev
#define GET_STATUS(data) \
((data >> 8) & 0xf)
+
#define IS_OPERATIONAL(sc) \
- (GET_STATUS(sc->stats.phy.state) == 2)
+ ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+ (GET_STATUS(sc->stats.phy.state) == 2) : \
+ (sc->stats.phy.state == 7))
/*
* Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@ enum {
#define UEA_INTR_PIPE 0x04
#define UEA_ISO_DATA_PIPE 0x08
-#define UEA_SET_BLOCK 0x0001
+#define UEA_E1_SET_BLOCK 0x0001
+#define UEA_E4_SET_BLOCK 0x002c
#define UEA_SET_MODE 0x0003
#define UEA_SET_2183_DATA 0x0004
#define UEA_SET_TIMEOUT 0x0011
@@ -275,71 +344,179 @@ enum {
#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000)
#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000)
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware */
+struct block_index {
+ __le32 PageOffset;
+ __le32 NotLastBlock;
+ __le32 dummy;
+ __le32 PageSize;
+ __le32 PageAddress;
+ __le16 dummy1;
+ __le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+ u8 string_header[E4_L1_STRING_HEADER];
+ u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+ struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+ u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
__le16 wHdr;
-#define UEA_BIHDR 0xabcd
__le16 wAddress;
__le16 wSize;
__le16 wOvlOffset;
__le16 wOvl; /* overlay */
__le16 wLast;
} __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
+
+struct block_info_e4 {
+ __be16 wHdr;
+ __u8 bBootPage;
+ __u8 bPageNumber;
+ __be32 dwSize;
+ __be32 dwAddress;
+ __be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
- __le16 wPreamble;
-#define PREAMBLE 0x535c
- __u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
- __u8 bFunction;
-#define FUNCTION_TYPE(f) ((f) >> 4)
-#define MEMACCESS 0x1
-#define ADSLDIRECTIVE 0x7
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
/* for MEMACCESS */
-#define REQUESTREAD 0x0
-#define REQUESTWRITE 0x1
-#define REPLYREAD 0x2
-#define REPLYWRITE 0x3
+#define E1_REQUESTREAD 0x0
+#define E1_REQUESTWRITE 0x1
+#define E1_REPLYREAD 0x2
+#define E1_REPLYWRITE 0x3
+
+#define E4_REQUESTREAD 0x0
+#define E4_REQUESTWRITE 0x4
+#define E4_REPLYREAD (E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE (E4_REQUESTWRITE | 1)
+
/* for ADSLDIRECTIVE */
-#define KERNELREADY 0x0
-#define MODEMREADY 0x1
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY 0x1
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
- __le16 wIndex;
- __le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d) \
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY 0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d) \
(((c) & 0xff) << 24 | \
((d) & 0xff) << 16 | \
((a) & 0xff) << 8 | \
((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
-
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+ __le16 wPreamble;
+ __u8 bDirection;
+ __u8 bFunction;
+ __le16 wIndex;
+ __le32 dwSymbolicAddress;
__le16 wOffsetAddress;
__le32 dwData;
} __attribute__ ((packed));
-#define CMV_SIZE 16
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+ __be16 wGroup;
+ __be16 wFunction;
+ __be16 wOffset;
+ __be16 wAddress;
+ __be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
__u8 bSwapPageNo;
__u8 bOvl; /* overlay */
} __attribute__ ((packed));
-/* structure representing interrupt data */
+struct swap_info_e4 {
+ __u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV 0x0002
+
+union intr_data_e1 {
+ struct {
+ struct swap_info_e1 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e1 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+ struct {
+ struct swap_info_e4 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e4 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
struct intr_pkt {
__u8 bType;
__u8 bNotification;
@@ -347,43 +524,48 @@ struct intr_pkt {
__le16 wIndex;
__le16 wLength;
__le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV 0x0002
union {
- struct {
- struct swap_info swapinfo;
- __le16 wDataSize;
- } __attribute__ ((packed)) s1;
-
- struct {
- struct cmv cmv;
- __le16 wDataSize;
- } __attribute__ ((packed)) s2;
- } __attribute__ ((packed)) u;
-#define bSwapPageNo u.s1.swapinfo.bSwapPageNo
-#define bOvl u.s1.swapinfo.bOvl
+ union intr_data_e1 e1;
+ union intr_data_e4 e4;
+ } u;
} __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
static struct usb_driver uea_driver;
static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
static int modem_index;
static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
static int sync_wait[NB_MODEM];
static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+ "1=isoc slowest, ... , 8=isoc fastest (default)");
module_param_array(sync_wait, bool, NULL, 0644);
MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
module_param_array(cmv_file, charp, NULL, 0644);
MODULE_PARM_DESC(cmv_file,
"file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+ "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+ int _r = wait_event_interruptible_timeout(sc->sync_q, \
+ (cond) || kthread_should_stop(), timeo); \
+ if (kthread_should_stop()) \
+ _r = -ENODEV; \
+ _r; \
+})
#define UPDATE_ATM_STAT(type, val) \
do { \
@@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
case EAGLE_III:
fw_name = FW_DIR "eagleIII.fw";
break;
+ case EAGLE_IV:
+ fw_name = FW_DIR "eagleIV.fw";
+ break;
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
/*
* Make sure that the DSP code provided is safe to use.
*/
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
{
u8 pagecount, blockcount;
u16 blocksize;
@@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len)
return 0;
}
+static int check_dsp_e4(u8 *dsp, int len)
+{
+ int i;
+ struct l1_code *p = (struct l1_code *) dsp;
+ unsigned int sum = p->code - dsp;
+
+ if (len < sum)
+ return 1;
+
+ if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+ strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+ return 1;
+
+ for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+ struct block_index *blockidx;
+ u8 blockno = p->page_number_to_block_index[i];
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ continue;
+
+ do {
+ u64 l;
+
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ return 1;
+
+ blockidx = &p->page_header[blockno++];
+ if ((u8 *)(blockidx + 1) - dsp >= len)
+ return 1;
+
+ if (le16_to_cpu(blockidx->PageNumber) != i)
+ return 1;
+
+ l = E4_PAGE_BYTES(blockidx->PageSize);
+ sum += l;
+ l += le32_to_cpu(blockidx->PageOffset);
+ if (l > len)
+ return 1;
+
+ /* zero is zero regardless endianes */
+ } while (blockidx->NotLastBlock);
+ }
+
+ return (sum == len) ? 0 : 1;
+}
+
/*
* send data to the idma pipe
* */
@@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc)
int ret;
char *dsp_name;
- if (UEA_CHIP_VERSION(sc) == ADI930) {
- if (IS_ISDN(sc->usb_dev))
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (IS_ISDN(sc))
+ dsp_name = FW_DIR "DSP4i.bin";
+ else
+ dsp_name = FW_DIR "DSP4p.bin";
+ } else if (UEA_CHIP_VERSION(sc) == ADI930) {
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
- if (IS_ISDN(sc->usb_dev))
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"requesting firmware %s failed with error %d\n",
- dsp_name, ret);
+ dsp_name, ret);
return ret;
}
- if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+ else
+ ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+ if (ret) {
uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
dsp_name);
release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc)
/*
* The uea_load_page() function must be called within a process context
*/
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
{
struct uea_softc *sc = container_of(work, struct uea_softc, task);
u16 pageno = sc->pageno;
u16 ovl = sc->ovl;
- struct block_info bi;
+ struct block_info_e1 bi;
u8 *p;
u8 pagecount, blockcount;
@@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work)
bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
/* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+ if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
goto bad2;
/* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@ bad1:
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
}
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+ struct block_info_e4 bi;
+ struct block_index *blockidx;
+ struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+ u8 blockno = p->page_number_to_block_index[pageno];
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = boot;
+ bi.bPageNumber = pageno;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+ do {
+ u8 *blockoffset;
+ unsigned int blocksize;
+
+ blockidx = &p->page_header[blockno];
+ blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+ blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+ bi.dwSize = cpu_to_be32(blocksize);
+ bi.dwAddress = swab32(blockidx->PageAddress);
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending block %u for DSP page %u size %u adress %x\n",
+ blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ goto bad;
+
+ /* send block data through the IDMA pipe */
+ if (uea_idma_write(sc, blockoffset, blocksize))
+ goto bad;
+
+ blockno++;
+ } while (blockidx->NotLastBlock);
+
+ return;
+
+bad:
+ uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+ return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+ struct uea_softc *sc = container_of(work, struct uea_softc, task);
+ u8 pageno = sc->pageno;
+ int i;
+ struct block_info_e4 bi;
+ struct l1_code *p;
+
+ uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+ /* reload firmware when reboot start and it's loaded already */
+ if (pageno == 0 && sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+
+ if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+ return;
+
+ p = (struct l1_code *) sc->dsp_firm->data;
+ if (pageno >= p->page_header[0].PageNumber) {
+ uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+ return;
+ }
+
+ if (pageno != 0) {
+ __uea_load_page_e4(sc, pageno, 0);
+ return;
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+ for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+ if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+ __uea_load_page_e4(sc, i, 1);
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = 0;
+ bi.bPageNumber = 0xff;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+ bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+ bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
static inline void wake_up_cmv_ack(struct uea_softc *sc)
{
BUG_ON(sc->cmv_ack);
sc->cmv_ack = 1;
- wake_up(&sc->cmv_ack_wait);
+ wake_up(&sc->sync_q);
}
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
- sc->cmv_ack, ACK_TIMEOUT);
+ int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
sc->cmv_ack = 0;
uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc,
return 0;
}
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
u8 function, u32 address, u16 offset, u32 data)
{
- struct cmv cmv;
+ struct cmv_e1 cmv;
int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
"offset : 0x%04x, data : 0x%08x\n",
- FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
- GETSA1(address), GETSA2(address), GETSA3(address),
- GETSA4(address), offset, data);
+ E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+ E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+ E1_GETSA4(address), offset, data);
+
/* we send a request, but we expect a reply */
- sc->cmv_function = function | 0x2;
- sc->cmv_idx++;
- sc->cmv_address = address;
- sc->cmv_offset = offset;
+ sc->cmv_dsc.e1.function = function | 0x2;
+ sc->cmv_dsc.e1.idx++;
+ sc->cmv_dsc.e1.address = address;
+ sc->cmv_dsc.e1.offset = offset;
- cmv.wPreamble = cpu_to_le16(PREAMBLE);
- cmv.bDirection = HOSTTOMODEM;
+ cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+ cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
- cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+ cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
- ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+ ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+ if (ret < 0)
+ return ret;
+ ret = wait_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return ret;
+}
+
+static int uea_cmv_e4(struct uea_softc *sc,
+ u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+ struct cmv_e4 cmv;
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ memset(&cmv, 0, sizeof(cmv));
+
+ uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+ "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+ E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+ group, address, offset, data);
+
+ /* we send a request, but we expect a reply */
+ sc->cmv_dsc.e4.function = function | (0x1 << 4);
+ sc->cmv_dsc.e4.offset = offset;
+ sc->cmv_dsc.e4.address = address;
+ sc->cmv_dsc.e4.group = group;
+
+ cmv.wFunction = cpu_to_be16(function);
+ cmv.wGroup = cpu_to_be16(group);
+ cmv.wAddress = cpu_to_be16(address);
+ cmv.wOffset = cpu_to_be16(offset);
+ cmv.dwData[0] = cpu_to_be32(data);
+
+ ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
return ret;
ret = wait_cmv_ack(sc);
@@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_read_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 *data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
address, offset, 0);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+ group, address, offset, 0);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "reading cmv failed with error %d\n", ret);
+ else {
+ *data = sc->data;
+ /* size is in 16-bit word quantities */
+ if (size > 2)
+ *(data + 1) = sc->data1;
+ }
+ return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
address, offset, data);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc,
return ret;
}
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+ group, address, offset, data);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "writing cmv failed with error %d\n", ret);
+
+ return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+ int ret;
+ u16 timeout;
+
+ /* in bulk mode the modem have problem with high rate
+ * changing internal timing could improve things, but the
+ * value is misterious.
+ * ADI930 don't support it (-EPIPE error).
+ */
+
+ if (UEA_CHIP_VERSION(sc) == ADI930 ||
+ altsetting[sc->modem_index] > 0 ||
+ sc->stats.phy.dsrate == dsrate)
+ return;
+
+ /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+ timeout = (dsrate <= 1024*1024) ? 0 : 1;
+ ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+ timeout, ret < 0 ? " failed" : "");
+
+}
+
/*
* Monitor the modem and update the stat
* return 0 if everything is ok
* return < 0 if an error occurs (-EAGAIN reboot needed)
*/
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
{
u32 data;
int ret;
@@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc)
uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
- ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+ ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
if (ret < 0)
return ret;
@@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc)
case 3: /* fail ... */
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
- " (may be try other cmv/dsp)\n");
+ " (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
@@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc)
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
- ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
if (ret < 0)
return ret;
sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc)
return 0;
}
- ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
if (ret < 0)
return ret;
- /* in bulk mode the modem have problem with high rate
- * changing internal timing could improve things, but the
- * value is misterious.
- * ADI930 don't support it (-EPIPE error).
- */
- if (UEA_CHIP_VERSION(sc) != ADI930
- && !use_iso[sc->modem_index]
- && sc->stats.phy.dsrate != (data >> 16) * 32) {
- /* Original timming from ADI(used in windows driver)
- * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
- */
- u16 timeout = (data <= 0x20ffff) ? 0 : 1;
- ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
- uea_info(INS_TO_USBDEV(sc),
- "setting new timeout %d%s\n", timeout,
- ret < 0?" failed":"");
- }
+ uea_set_bulk_timeout(sc, (data >> 16) * 32);
sc->stats.phy.dsrate = (data >> 16) * 32;
sc->stats.phy.usrate = (data & 0xffff) * 32;
UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
- ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
if (ret < 0)
return ret;
sc->stats.phy.dsattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
if (ret < 0)
return ret;
sc->stats.phy.usattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
if (ret < 0)
return ret;
return 0;
}
-static int request_cmvs(struct uea_softc *sc,
- struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
{
- int ret, size;
- u8 *data;
+ u32 data;
+ u32 tmp_arr[2];
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ data = sc->stats.phy.state;
+
+ /* XXX only need to be done before operationnal... */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+ if (ret < 0)
+ return ret;
+
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+ return 0;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+ return 0;
+ case 0x2: /* fail ... */
+ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+ " (may be try other cmv/dsp)\n");
+ return -EAGAIN;
+ case 0x7: /* operational */
+ break;
+ default:
+ uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+ return 0;
+ }
+
+ if (data != 7) {
+ uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+ /* release the dsp firmware as it is not needed until
+ * the next failure
+ */
+ if (sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+ }
+
+ /* always update it as atm layer could not be init when we switch to
+ * operational state
+ */
+ UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+ /* wake up processes waiting for synchronization */
+ wake_up(&sc->sync_q);
+
+ /* TODO improve this state machine :
+ * we need some CMV info : what they do and their unit
+ * we should find the equivalent of eagle3- CMV
+ */
+ /* check flags */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+ /* in case of a flags ( for example delineation LOSS (& 0x10)),
+ * we check the status again in order to detect the failure earlier
+ */
+ if (sc->stats.phy.flags) {
+ uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+ sc->stats.phy.flags);
+ if (sc->stats.phy.flags & 1) //delineation LOSS
+ return -EAGAIN;
+ if (sc->stats.phy.flags & 0x4000) //Reset Flag
+ return -EAGAIN;
+ return 0;
+ }
+
+ /* rate data may be in upper or lower half of 64 bit word, strange */
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ sc->stats.phy.usrate = data / 1000;
+
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ uea_set_bulk_timeout(sc, data / 1000);
+ sc->stats.phy.dsrate = data / 1000;
+ UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsmargin = data / 2;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usmargin = data / 10;
+
+ return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+ char file_arr[] = "CMVxy.bin";
char *file;
- char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ /* set proper name corresponding modem version and line type */
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
- file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+ file_arr[3] = '9';
+ else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ file_arr[3] = '4';
else
- file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+ file_arr[3] = 'e';
+
+ file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+ file = file_arr;
} else
file = cmv_file[sc->modem_index];
strcpy(cmv_name, FW_DIR);
- strlcat(cmv_name, file, sizeof(cmv_name));
+ strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+ if (ver == 2)
+ strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
+
+static int request_cmvs_old(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw)
+{
+ int ret, size;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ cmvs_file_name(sc, cmv_name, 1);
ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc,
}
data = (u8 *) (*fw)->data;
- size = *data * sizeof(struct uea_cmvs) + 1;
- if (size != (*fw)->size) {
- uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
- cmv_name);
- release_firmware(*fw);
- return -EILSEQ;
+ size = (*fw)->size;
+ if (size < 1)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *)(data + 1);
+ return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw, int *ver)
+{
+ int ret, size;
+ u32 crc;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+ cmvs_file_name(sc, cmv_name, 2);
+ ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+ if (ret < 0) {
+ /* if caller can handle old version, try to provide it */
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+ "try to get older cmvs\n", cmv_name);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ uea_err(INS_TO_USBDEV(sc),
+ "requesting firmware %s failed with error %d\n",
+ cmv_name, ret);
+ return ret;
+ }
+
+ size = (*fw)->size;
+ data = (u8 *) (*fw)->data;
+ if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+ "try to get older cmvs\n", cmv_name);
+ release_firmware(*fw);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ goto err_fw_corrupted;
}
- *cmvs = (struct uea_cmvs *)(data + 1);
+ *ver = 2;
+
+ data += 4;
+ size -= 4;
+ if (size < 5)
+ goto err_fw_corrupted;
+
+ crc = FW_GET_LONG(data);
+ data += 4;
+ size -= 4;
+ if (crc32_be(0, data, size) != crc)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *) (data + 1);
return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 1; // we can handle v1 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 1) {
+ struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+ uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+ "please update your firmware\n");
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+ FW_GET_WORD(&cmvs_v1[i].offset),
+ FW_GET_LONG(&cmvs_v1[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else if (ver == 2) {
+ struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+ (u16) FW_GET_LONG(&cmvs_v2[i].offset),
+ FW_GET_LONG(&cmvs_v2[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 2; // we can only handle v2 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ /* XXX don't read the 3th byte as it is always 6 */
+ ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 2) {
+ struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e4(sc, 1,
+ FW_GET_LONG(&cmvs_v2[i].group),
+ FW_GET_LONG(&cmvs_v2[i].address),
+ FW_GET_LONG(&cmvs_v2[i].offset),
+ FW_GET_LONG(&cmvs_v2[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
}
/* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc,
static int uea_start_reset(struct uea_softc *sc)
{
u16 zero = 0; /* ;-) */
- int i, len, ret;
- struct uea_cmvs *cmvs;
- const struct firmware *cmvs_fw;
+ int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc)
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
/* original driver use 200ms, but windows driver use 100ms */
- msleep(100);
+ ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+ if (ret < 0)
+ return ret;
/* leave reset mode */
uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
- /* clear tx and rx mailboxes */
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+ /* clear tx and rx mailboxes */
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ }
+
+ ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+ if (ret < 0)
+ return ret;
+
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+ else
+ sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
- msleep(1000);
- sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
/* demask interrupt */
sc->booting = 0;
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
- schedule_work(&sc->task);
+ queue_work(sc->work_q, &sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc)
uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
- /* Enter in R-IDLE (cmv) until instructed otherwise */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
- if (ret < 0)
- return ret;
-
- /* Dump firmware version */
- ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+ ret = sc->send_cmvs(sc);
if (ret < 0)
return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
- /* get options */
- ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
- if (ret < 0)
- return ret;
-
- /* send options */
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
- FW_GET_WORD(&cmvs[i].offset),
- FW_GET_LONG(&cmvs[i].data));
- if (ret < 0)
- goto out;
- }
- /* Enter in R-ACT-REQ */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
- uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
- uea_info(INS_TO_USBDEV(sc), "Modem started, "
- "waiting synchronization\n");
-out:
- release_firmware(cmvs_fw);
sc->reset = 0;
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1174,12 +1879,10 @@ static int uea_kthread(void *data)
if (ret < 0 || sc->reset)
ret = uea_start_reset(sc);
if (!ret)
- ret = uea_stat(sc);
+ ret = sc->stat(sc);
if (ret != -EAGAIN)
- msleep_interruptible(1000);
- if (try_to_freeze())
- uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
- "please unplug/replug your modem\n");
+ uea_wait(sc, 0, msecs_to_jiffies(1000));
+ try_to_freeze();
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
if (ret < 0)
uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
-
err1:
release_firmware(fw_entry);
err0:
@@ -1243,40 +1945,41 @@ err0:
}
/* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
{
+ struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+ struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
uea_enters(INS_TO_USBDEV(sc));
- if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+ if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
goto bad1;
- if (cmv->bDirection != MODEMTOHOST)
+ if (cmv->bDirection != E1_MODEMTOHOST)
goto bad1;
/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
* the first MEMACESS cmv. Ignore it...
*/
- if (cmv->bFunction != sc->cmv_function) {
+ if (cmv->bFunction != dsc->function) {
if (UEA_CHIP_VERSION(sc) == ADI930
- && cmv->bFunction == MAKEFUNCTION(2, 2)) {
- cmv->wIndex = cpu_to_le16(sc->cmv_idx);
- put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
- cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
- }
- else
+ && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
+ cmv->wIndex = cpu_to_le16(dsc->idx);
+ put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+ cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+ } else
goto bad2;
}
- if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+ if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
wake_up_cmv_ack(sc);
uea_leaves(INS_TO_USBDEV(sc));
return;
}
/* in case of MEMACCESS */
- if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
- sc->cmv_address
- || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+ if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+ le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
bad2:
uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
"Function : %d, Subfunction : %d\n",
- FUNCTION_TYPE(cmv->bFunction),
- FUNCTION_SUBTYPE(cmv->bFunction));
+ E1_FUNCTION_TYPE(cmv->bFunction),
+ E1_FUNCTION_SUBTYPE(cmv->bFunction));
uea_leaves(INS_TO_USBDEV(sc));
return;
@@ -1301,6 +2004,61 @@ bad1:
uea_leaves(INS_TO_USBDEV(sc));
}
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+ struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+ be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+ be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+ be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+ if (be16_to_cpu(cmv->wFunction) != dsc->function)
+ goto bad2;
+
+ if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+ }
+
+ /* in case of MEMACCESS */
+ if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+ be16_to_cpu(cmv->wGroup) != dsc->group ||
+ be16_to_cpu(cmv->wAddress) != dsc->address)
+ goto bad2;
+
+ sc->data = be32_to_cpu(cmv->dwData[0]);
+ sc->data1 = be32_to_cpu(cmv->dwData[1]);
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+
+bad2:
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ "Function : %d, Subfunction : %d\n",
+ E4_FUNCTION_TYPE(cmv->wFunction),
+ E4_FUNCTION_SUBTYPE(cmv->wFunction));
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e1_bSwapPageNo;
+ sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+ queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e4_bSwapPageNo;
+ queue_work(sc->work_q, &sc->task);
+}
+
/*
* interrupt handler
*/
@@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb)
switch (le16_to_cpu(intr->wInterrupt)) {
case INT_LOADSWAPPAGE:
- sc->pageno = intr->bSwapPageNo;
- sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
- schedule_work(&sc->task);
+ sc->schedule_load_page(sc, intr);
break;
case INT_INCOMINGCMV:
- uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+ sc->dispatch_cmv(sc, intr);
break;
default:
@@ -1349,35 +2105,55 @@ resubmit:
*/
static int uea_boot(struct uea_softc *sc)
{
- int ret;
+ int ret, size;
struct intr_pkt *intr;
uea_enters(INS_TO_USBDEV(sc));
- INIT_WORK(&sc->task, uea_load_page);
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ size = E4_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e4;
+ sc->schedule_load_page = uea_schedule_load_page_e4;
+ sc->stat = uea_stat_e4;
+ sc->send_cmvs = uea_send_cmvs_e4;
+ INIT_WORK(&sc->task, uea_load_page_e4);
+ } else {
+ size = E1_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e1;
+ sc->schedule_load_page = uea_schedule_load_page_e1;
+ sc->stat = uea_stat_e1;
+ sc->send_cmvs = uea_send_cmvs_e1;
+ INIT_WORK(&sc->task, uea_load_page_e1);
+ }
+
init_waitqueue_head(&sc->sync_q);
- init_waitqueue_head(&sc->cmv_ack_wait);
+
+ sc->work_q = create_workqueue("ueagle-dsp");
+ if (!sc->work_q) {
+ uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+ uea_leaves(INS_TO_USBDEV(sc));
+ return -ENOMEM;
+ }
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
- intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+ intr = kmalloc(size, GFP_KERNEL);
if (!intr) {
uea_err(INS_TO_USBDEV(sc),
"cannot allocate interrupt package\n");
- uea_leaves(INS_TO_USBDEV(sc));
- return -ENOMEM;
+ goto err0;
}
sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
if (!sc->urb_int) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
- goto err;
+ goto err1;
}
usb_fill_int_urb(sc->urb_int, sc->usb_dev,
usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
- intr, INTR_PKT_SIZE, uea_intr, sc,
+ intr, size, uea_intr, sc,
sc->usb_dev->actconfig->interface[0]->altsetting[0].
endpoint[0].desc.bInterval);
@@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"urb submition failed with error %d\n", ret);
- goto err;
+ goto err1;
}
sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc)
err2:
usb_kill_urb(sc->urb_int);
-err:
+err1:
usb_free_urb(sc->urb_int);
sc->urb_int = NULL;
kfree(intr);
+err0:
+ destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
@@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc)
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
- /* stop any pending boot process */
- flush_scheduled_work();
-
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
usb_kill_urb(sc->urb_int);
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
+ /* stop any pending boot process, when no one can schedule work */
+ destroy_workqueue(sc->work_q);
+
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
@@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
char *buf)
{
int ret = -ENODEV;
+ int modem_state;
struct uea_softc *sc;
mutex_lock(&uea_mutex);
@@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
if (!sc)
goto out;
- switch (GET_STATUS(sc->stats.phy.state)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ modem_state = 0;
+ break;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ modem_state = 1;
+ break;
+ case 0x7: /* operational */
+ modem_state = 2;
+ break;
+ case 0x2: /* fail ... */
+ modem_state = 3;
+ break;
+ default: /* unknown */
+ modem_state = 4;
+ break;
+ }
+ } else
+ modem_state = GET_STATUS(sc->stats.phy.state);
+
+ switch (modem_state) {
case 0:
ret = sprintf(buf, "Modem is booting\n");
break;
@@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
case 2:
ret = sprintf(buf, "Modem is operational\n");
break;
- default:
+ case 3:
ret = sprintf(buf, "Modem synchronization failed\n");
break;
+ default:
+ ret = sprintf(buf, "Modem state is unknown\n");
+ break;
}
out:
mutex_unlock(&uea_mutex);
@@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
{
int ret = -ENODEV;
struct uea_softc *sc;
+ char *delin = "GOOD";
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev);
if (!sc)
goto out;
- if (sc->stats.phy.flags & 0x0C00)
- ret = sprintf(buf, "ERROR\n");
- else if (sc->stats.phy.flags & 0x0030)
- ret = sprintf(buf, "LOSS\n");
- else
- ret = sprintf(buf, "GOOD\n");
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (sc->stats.phy.flags & 0x4000)
+ delin = "RESET";
+ else if (sc->stats.phy.flags & 0x0001)
+ delin = "LOSS";
+ } else {
+ if (sc->stats.phy.flags & 0x0C00)
+ delin = "ERROR";
+ else if (sc->stats.phy.flags & 0x0030)
+ delin = "LOSS";
+ }
+
+ ret = sprintf(buf, "%s\n", delin);
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
struct usb_device *usb = interface_to_usbdev(intf);
struct uea_softc *sc;
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+ unsigned int alt;
uea_enters(usb);
@@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
sc->driver_info = id->driver_info;
- /* ADI930 don't support iso */
- if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
- int i;
-
- /* try set fastest alternate for inbound traffic interface */
- for (i = FASTEST_ISO_INTF; i > 0; i--)
- if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
- break;
+ /* first try to use module parameter */
+ if (annex[sc->modem_index] == 1)
+ sc->annex = ANNEXA;
+ else if (annex[sc->modem_index] == 2)
+ sc->annex = ANNEXB;
+ /* try to autodetect annex */
+ else if (sc->driver_info & AUTO_ANNEX_A)
+ sc->annex = ANNEXA;
+ else if (sc->driver_info & AUTO_ANNEX_B)
+ sc->annex = ANNEXB;
+ else
+ sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
- if (i > 0) {
- uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+ alt = altsetting[sc->modem_index];
+ /* ADI930 don't support iso */
+ if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+ if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+ uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
uea_info(usb, "using iso mode\n");
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
} else {
- uea_err(usb, "setting any alternate failed for "
- "2 interface, using bulk mode\n");
+ uea_err(usb, "setting alternate %u failed for "
+ "2 interface, using bulk mode\n", alt);
}
}
@@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
- le16_to_cpu(usb->descriptor.idVendor),
- le16_to_cpu(usb->descriptor.idProduct),
- chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+ le16_to_cpu(usb->descriptor.idVendor),
+ le16_to_cpu(usb->descriptor.idProduct),
+ le16_to_cpu(usb->descriptor.bcdDevice),
+ chip_name[UEA_CHIP_VERSION(id)]);
usb_reset_device(usb);
@@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf)
* List of supported VID/PID
*/
static const struct usb_device_id uea_ids[] = {
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{}
};
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 70125c6d3be..8472543eee8 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -29,7 +29,7 @@
#define XUSBATM_PARM(name, type, parmtype, desc) \
static type name[XUSBATM_DRIVERS_MAX]; \
- static int num_##name; \
+ static unsigned int num_##name; \
module_param_array(name, parmtype, &num_##name, 0444); \
MODULE_PARM_DESC(name, desc)
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 5192cd9356d..ad632f2d6f9 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -28,6 +28,7 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
+ * none - Maintained in Linux kernel after v0.13
*/
/*
@@ -69,7 +70,6 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
-#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
+#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
@@ -159,10 +159,12 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
+ unsigned int flags; /* mode flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
+ unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
- request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+ request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
- /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
- kfree(urb->transfer_buffer);
- urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
- error = usblp_read_status (usblp, usblp->statusbuf);
- if (error < 0) {
+ mutex_lock(&usblp->mut);
+ if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+ mutex_unlock(&usblp->mut);
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
-
status = *usblp->statusbuf;
+ mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
- * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
- * This is #if 0-ed because we *don't* want to fail an open
- * just because the printer is off-line.
+ * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+ * - We do not want persistent state which close(2) does not clear
+ * - It is not used anyway, according to CUPS people
*/
-#if 0
- if ((retval = usblp_check_status(usblp, 0))) {
- retval = retval > 1 ? -EIO : -ENOSPC;
- goto out;
- }
-#else
- retval = 0;
-#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
+ usblp->flags &= ~LP_ABORT;
+
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
- ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
- | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+ ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
+ ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
+ case LPABORT:
+ if (arg)
+ usblp->flags |= LP_ABORT;
+ else
+ usblp->flags &= ~LP_ABORT;
+ break;
+
default:
retval = -ENOTTY;
}
@@ -684,10 +686,30 @@ done:
return retval;
}
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+ struct urb *urb;
+ char *writebuf;
+
+ if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+ return NULL;
+ if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+ kfree(writebuf);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, usblp->dev,
+ usb_sndbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+ writebuf, transfer_length, usblp_bulk_write, usblp);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ return urb;
+}
+
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
- if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
- goto raise_buf;
- if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+ if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
goto raise_urb;
- usb_fill_bulk_urb(writeurb, usblp->dev,
- usb_sndbulkpipe(usblp->dev,
- usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
- writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
- if (copy_from_user(writebuf,
+ if (copy_from_user(writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
/* Presume that it's going to complete well. */
writecount += transfer_length;
}
+ if (rv == -ENOSPC) {
+ spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 1; /* Mark for poll(2) */
+ spin_unlock_irq(&usblp->lock);
+ writecount += transfer_length;
+ }
/* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
- usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
@@ -771,8 +793,6 @@ raise_badaddr:
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
- kfree(writebuf);
-raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@ done:
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
+ int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
- set_current_state(TASK_INTERRUPTIBLE);
- if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
- mutex_unlock(&usblp->mut);
- break;
- }
+ rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
- if (rc == 0)
+ if (rc <= 0)
break;
- schedule();
+
+ if (usblp->flags & LP_ABORT) {
+ if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+ err = usblp_check_status(usblp, err);
+ if (err == 1) { /* Paper out */
+ rc = -ENOSPC;
+ break;
+ }
+ }
+ } else {
+ schedule();
+ }
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index cb69aa1e02e..1a8edcee7f3 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
}
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ * whole thing. A non-authorized USB device has no
+ * configurations.
+ */
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
- int result = -ENOMEM;
+ int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
+ cfgno = 0;
+ if (dev->authorized == 0) /* Not really an error */
+ goto out_not_authorized;
+ result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
- for (cfgno = 0; cfgno < ncfg; cfgno++) {
+ result = 0;
+ for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s\n", cfgno, "start");
+ "descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
+out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181120a..f013b4012c9 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -71,6 +71,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ int status;
u32 secid;
};
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
- if (urb->pipe & USB_DIR_IN)
- dev_info(&urb->dev->dev, "direction=IN\n");
- else
- dev_info(&urb->dev->dev, "direction=OUT\n");
+ dev_info(&urb->dev->dev, "direction=%s\n",
+ usb_urb_dir_in(urb) ? "IN" : "OUT");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
+ as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
- sinfo.si_errno = as->urb->status;
+ sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
+ int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
- if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
- ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- else
- ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+ is_in = 1;
+ ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ } else {
+ is_in = 0;
+ ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ }
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_CONTROL)
+ if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
- uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+ if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+ is_in = 1;
+ uurb->endpoint |= USB_DIR_IN;
+ } else {
+ is_in = 0;
+ uurb->endpoint &= ~USB_DIR_IN;
+ }
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
- dr->bRequest, dr->bRequestType, dr->wValue,
- dr->wIndex, dr->wLength);
+ dr->bRequest, dr->bRequestType,
+ __le16_to_cpup(&dr->wValue),
+ __le16_to_cpup(&dr->wIndex),
+ __le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
- switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_ISOC)
+ if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
- as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags;
+ as->urb->pipe = (uurb->type << 30) |
+ __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+ (uurb->endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb->flags |
+ (is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
- if (!(uurb->endpoint & USB_DIR_IN)) {
- if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+ if (!is_in) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+ as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
- snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
}
const struct file_operations usbdev_file_operations = {
+ .owner = THIS_MODULE,
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = {
};
#endif
-static struct cdev usb_device_cdev = {
- .kobj = {.name = "usb_device", },
- .owner = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
int __init usb_devio_init(void)
{
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 63b1243a913..8586817698a 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return -ENODEV;
+ }
+
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
@@ -576,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -610,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
* all the device descriptors we don't tell them about. Or
* act as usermode drivers.
*/
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
/* per-device configurations are common */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
/* class-based driver binding models */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "BUSNUM=%03d",
+ if (add_uevent_var(env, "BUSNUM=%03d",
usb_dev->bus->busnum))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVNUM=%03d",
+ if (add_uevent_var(env, "DEVNUM=%03d",
usb_dev->devnum))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -945,11 +935,11 @@ done:
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
{
int i;
struct usb_interface *intf;
- unsigned long suspend_time;
+ unsigned long suspend_time, j;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@@ -991,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev)
}
/* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request.
+ * enough, queue a delayed autosuspend request. If the device
+ * _has_ been idle for long enough and the reschedule flag is set,
+ * likewise queue a delayed (1 second) autosuspend request.
*/
- if (time_after(suspend_time, jiffies)) {
+ j = jiffies;
+ if (time_before(j, suspend_time))
+ reschedule = 1;
+ else
+ suspend_time = j + HZ;
+ if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
-
- /* The value of jiffies may change between the
- * time_after() comparison above and the subtraction
- * below. That's okay; the system behaves sanely
- * when a timer is registered for the present moment
- * or for the past.
- */
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_relative(suspend_time - jiffies));
- }
+ round_jiffies_relative(suspend_time - j));
+ }
return -EAGAIN;
}
return 0;
@@ -1012,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev)
#else
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
{
return 0;
}
@@ -1069,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
- status = autosuspend_check(udev);
+ status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
}
@@ -1083,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
- if (status == 0) {
-
- /* Non-root devices don't need to do anything for FREEZE
- * or PRETHAW. */
- if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
- msg.event == PM_EVENT_PRETHAW))
- goto done;
+ if (status == 0)
status = usb_suspend_device(udev, msg);
- }
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
@@ -1102,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
- autosuspend_check(udev);
+ autosuspend_check(udev, status == -EBUSY);
- /* If the suspend succeeded, propagate it up the tree */
+ /* If the suspend succeeded then prevent any more URB submissions,
+ * flush any outstanding URBs, and propagate the suspend up the tree.
+ */
} else {
cancel_delayed_work(&udev->autosuspend);
- if (parent)
+ udev->can_submit = 0;
+ for (i = 0; i < 16; ++i) {
+ usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+ usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+ }
+
+ /* If this is just a FREEZE or a PRETHAW, udev might
+ * not really be suspended. Only true suspends get
+ * propagated up the device tree.
+ */
+ if (parent && udev->state == USB_STATE_SUSPENDED)
usb_autosuspend_device(parent);
}
@@ -1156,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
+ udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
+ struct usb_device *udev;
+
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
- return usb_external_suspend_device(to_usb_device(dev), message);
+ udev = to_usb_device(dev);
+
+ /* If udev is already suspended, we can skip this suspend and
+ * we should also skip the upcoming system resume. */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ udev->skip_sys_resume = 1;
+ return 0;
+ }
+
+ udev->skip_sys_resume = 0;
+ return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
@@ -1542,13 +1550,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
- /* If autoresume is disabled then we also want to prevent resume
- * during system wakeup. However, a "persistent-device" reset-resume
- * after power loss counts as a wakeup event. So allow a
- * reset-resume to occur if remote wakeup is enabled. */
- if (udev->autoresume_disabled) {
+ /* If udev->skip_sys_resume is set then udev was already suspended
+ * when the system suspend started, so we don't want to resume
+ * udev during this system wakeup. However a reset-resume counts
+ * as a wakeup event, so allow a reset-resume to occur if remote
+ * wakeup is enabled. */
+ if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
- return -EPERM;
+ return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index e0ec7045e86..7dc123d6b2d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
- dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b2fc2b11525..c1cb94e9f24 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
- c = choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ if (udev->authorized == 0)
+ dev_err(&udev->dev, "Device is not authorized for usage\n");
+ else {
+ c = usb_choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
}
}
-
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
+
+ /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+ else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ rc = 0;
else
rc = usb_port_suspend(udev);
+
return rc;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 42ef1d5f6c8..3dd997df850 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
- unsigned long flags;
- int status = 0;
+ int status;
int n;
+ might_sleep();
+
+ spin_lock_irq(&hcd_root_hub_lock);
+ status = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irq(&hcd_root_hub_lock);
+ if (status)
+ return status;
+ urb->hcpriv = hcd; /* Indicate it's queued */
+
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@ error:
}
/* any errors get returned through the urb completion */
- local_irq_save (flags);
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ spin_lock_irq(&hcd_root_hub_lock);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ /* This peculiar use of spinlocks echoes what real HC drivers do.
+ * Avoiding calls to local_irq_disable/enable makes the code
+ * RT-friendly.
+ */
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+
+ spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) {
/* try to complete the status urb */
- local_irq_save (flags);
- spin_lock(&hcd_root_hub_lock);
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) {
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- urb->status = 0;
- urb->hcpriv = NULL;
- urb->actual_length = length;
- memcpy(urb->transfer_buffer, buffer, length);
- } else /* urb has been unlinked */
- length = 0;
- spin_unlock(&urb->lock);
- } else
- length = 0;
- spin_unlock(&hcd_root_hub_lock);
+ hcd->poll_pending = 0;
+ hcd->status_urb = NULL;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
- /* local irqs are always blocked in completions */
- if (length > 0)
- usb_hcd_giveback_urb (hcd, urb);
- else
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, 0);
+ spin_lock(&hcd_root_hub_lock);
+ } else {
+ length = 0;
hcd->poll_pending = 1;
- local_irq_restore (flags);
+ }
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
@@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
- if (urb->status != -EINPROGRESS) /* already unlinked */
- retval = urb->status;
- else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
- } else {
- hcd->status_urb = urb;
- urb->hcpriv = hcd; /* indicate it's queued */
+ goto done;
+ }
- if (!hcd->uses_new_polling)
- mod_timer (&hcd->rh_timer,
- (jiffies/(HZ/4) + 1) * (HZ/4));
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
+ goto done;
- /* If a status change has already occurred, report it ASAP */
- else if (hcd->poll_pending)
- mod_timer (&hcd->rh_timer, jiffies);
- retval = 0;
- }
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
+ if (!hcd->uses_new_polling)
+ mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+ /* If a status change has already occurred, report it ASAP */
+ else if (hcd->poll_pending)
+ mod_timer(&hcd->rh_timer, jiffies);
+ retval = 0;
+ done:
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeint (urb->pipe))
+ if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
- if (usb_pipecontrol (urb->pipe))
+ if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
@@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer);
- local_irq_save (flags);
- spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
- urb->hcpriv = NULL;
- } else
- urb = NULL; /* wasn't fully queued */
- spin_unlock (&hcd_root_hub_lock);
- if (urb)
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+ }
}
+ done:
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ return rc;
+}
- return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned val;
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ result = sscanf(buf, "%u\n", &val);
+ if (result == 1) {
+ usb_hcd->authorized_default = val? 1 : 0;
+ result = size;
+ }
+ else
+ result = -EINVAL;
+ return result;
}
+static DEVICE_ATTR(authorized_default, 0644,
+ usb_host_authorized_default_show,
+ usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+ &dev_attr_authorized_default.attr,
+ NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = usb_bus_attrs,
+};
+
+
+
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
@@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
*/
static int usb_register_bus(struct usb_bus *bus)
{
+ int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum < USB_MAXBUS) {
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
- } else {
+ if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
- mutex_unlock(&usb_bus_list_lock);
- return -E2BIG;
+ goto error_find_busnum;
}
-
+ set_bit (busnum, busmap.busmap);
+ bus->busnum = busnum;
bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d", busnum);
- if (IS_ERR(bus->class_dev)) {
- clear_bit(busnum, busmap.busmap);
- mutex_unlock(&usb_bus_list_lock);
- return PTR_ERR(bus->class_dev);
- }
-
+ bus->controller, "usb_host%d",
+ busnum);
+ result = PTR_ERR(bus->class_dev);
+ if (IS_ERR(bus->class_dev))
+ goto error_create_class_dev;
class_set_devdata(bus->class_dev, bus);
/* Add it to the local list of buses */
@@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
usb_notify_add_bus(bus);
- dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+ dev_info (bus->controller, "new USB bus registered, assigned bus "
+ "number %d\n", bus->busnum);
return 0;
+
+error_create_class_dev:
+ clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+ mutex_unlock(&usb_bus_list_lock);
+ return result;
}
/**
@@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail). If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
+ int rc = 0;
- /* clear all state linking urb to this dev (and hcd) */
- spin_lock_irqsave(&hcd_urb_list_lock, flags);
- list_del_init (&urb->urb_list);
- spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+ spin_lock(&hcd_urb_list_lock);
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_pipecontrol (urb->pipe)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- dma_unmap_single (hcd->self.controller, urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
- dma_unmap_single (hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
+ /* Check that the URB isn't being killed */
+ if (unlikely(urb->reject)) {
+ rc = -EPERM;
+ goto done;
}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
- int status;
- struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
- struct usb_host_endpoint *ep;
- unsigned long flags;
- if (!hcd)
- return -ENODEV;
+ if (unlikely(!urb->ep->enabled)) {
+ rc = -ENOENT;
+ goto done;
+ }
- usbmon_urb_submit(&hcd->self, urb);
+ if (unlikely(!urb->dev->can_submit)) {
+ rc = -EHOSTUNREACH;
+ goto done;
+ }
/*
- * Atomically queue the urb, first to our records, then to the HCD.
- * Access to urb->status is controlled by urb->lock ... changes on
- * i/o completion (normal or fault) or unlinking.
+ * Check the host controller's state and add the URB to the
+ * endpoint's queue.
*/
-
- // FIXME: verify that quiescing hc works right (RH cleans up)
-
- spin_lock_irqsave(&hcd_urb_list_lock, flags);
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (unlikely (!ep))
- status = -ENOENT;
- else if (unlikely (urb->reject))
- status = -EPERM;
- else switch (hcd->state) {
+ switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
- list_add_tail (&urb->urb_list, &ep->urb_list);
- status = 0;
+ urb->unlinked = 0;
+ list_add_tail(&urb->urb_list, &urb->ep->urb_list);
break;
default:
- status = -ESHUTDOWN;
- break;
+ rc = -ESHUTDOWN;
+ goto done;
}
- spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
- if (status) {
- INIT_LIST_HEAD (&urb->urb_list);
- usbmon_urb_submit_error(&hcd->self, urb, status);
- return status;
+ done:
+ spin_unlock(&hcd_urb_list_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail). The possible error codes are:
+ *
+ * -EIDRM: @urb was not submitted or has already completed.
+ * The completion function may not have been called yet.
+ *
+ * -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct list_head *tmp;
+
+ /* insist the urb is still queued */
+ list_for_each(tmp, &urb->ep->urb_list) {
+ if (tmp == &urb->urb_list)
+ break;
}
+ if (tmp != &urb->urb_list)
+ return -EIDRM;
- /* increment urb's reference count as part of giving it to the HCD
- * (which now controls it). HCD guarantees that it either returns
- * an error or calls giveback(), but not both.
+ /* Any status except -EINPROGRESS means something already started to
+ * unlink this URB from the hardware. So there's no more work to do.
*/
- urb = usb_get_urb (urb);
- atomic_inc (&urb->use_count);
-
- if (is_root_hub(urb->dev)) {
- /* NOTE: requirement on hub callers (usbfs and the hub
- * driver, for now) that URBs' urb->transfer_buffer be
- * valid and usb_buffer_{sync,unmap}() not be needed, since
- * they could clobber root hub response data.
- */
- status = rh_urb_enqueue (hcd, urb);
- goto done;
+ if (urb->unlinked)
+ return -EBUSY;
+ urb->unlinked = status;
+
+ /* IRQ setup can easily be broken so that USB controllers
+ * never get completion IRQs ... maybe even the ones we need to
+ * finish unlinking the initial failed usb_set_address()
+ * or device descriptor fetch.
+ */
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
+ dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
+ "Controller is probably using the wrong IRQ.\n");
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
- /* lower level hcd code should use *_dma exclusively,
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
+ * interrupts must be disabled. The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* clear all state linking urb to this dev (and hcd) */
+ spin_lock(&hcd_urb_list_lock);
+ list_del_init(&urb->urb_list);
+ spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* Map the URB's buffers for DMA access.
+ * Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.uses_dma) {
- if (usb_pipecontrol (urb->pipe)
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
hcd->self.controller,
@@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_urb_dir_in(urb)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
+}
- status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
- if (unlikely (status)) {
- urb_unlink(hcd, urb);
- atomic_dec (&urb->use_count);
- if (urb->reject)
- wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single(hcd->self.controller, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ dma_unmap_single(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_urb_dir_in(urb)
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+ int status;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+
+ /* increment urb's reference count as part of giving it to the HCD
+ * (which will control it). HCD guarantees that it either returns
+ * an error or calls giveback(), but not both.
+ */
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usbmon_urb_submit(&hcd->self, urb);
+
+ /* NOTE requirements on root-hub callers (usbfs and the hub
+ * driver, for now): URBs' urb->transfer_buffer must be
+ * valid and usb_buffer_{sync,unmap}() not be needed, since
+ * they could clobber root hub response data. Also, control
+ * URBs must be submitted in process context with interrupts
+ * enabled.
+ */
+ map_urb_for_dma(hcd, urb);
+ if (is_root_hub(urb->dev))
+ status = rh_urb_enqueue(hcd, urb);
+ else
+ status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+ if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
- usb_put_urb (urb);
+ unmap_urb_for_dma(hcd, urb);
+ urb->hcpriv = NULL;
+ INIT_LIST_HEAD(&urb->urb_list);
+ atomic_dec(&urb->use_count);
+ atomic_dec(&urb->dev->urbnum);
+ if (urb->reject)
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
}
return status;
}
@@ -1042,24 +1213,19 @@ done:
* soon as practical. we've already set up the urb's return status,
* but we can't know if the callback completed already.
*/
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
{
int value;
if (is_root_hub(urb->dev))
- value = usb_rh_urb_dequeue (hcd, urb);
+ value = usb_rh_urb_dequeue(hcd, urb, status);
else {
/* The only reason an HCD might fail this call is if
* it has not yet fully queued the urb to begin with.
* Such failures should be harmless. */
- value = hcd->driver->urb_dequeue (hcd, urb);
+ value = hcd->driver->urb_dequeue(hcd, urb, status);
}
-
- if (value != 0)
- dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
- urb, value);
return value;
}
@@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
*/
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
- struct usb_host_endpoint *ep;
- struct usb_hcd *hcd = NULL;
- struct device *sys = NULL;
- unsigned long flags;
- struct list_head *tmp;
- int retval;
-
- if (!urb)
- return -EINVAL;
- if (!urb->dev || !urb->dev->bus)
- return -ENODEV;
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep)
- return -ENODEV;
-
- /*
- * we contend for urb->status with the hcd core,
- * which changes it while returning the urb.
- *
- * Caller guaranteed that the urb pointer hasn't been freed, and
- * that it was submitted. But as a rule it can't know whether or
- * not it's already been unlinked ... so we respect the reversed
- * lock sequence needed for the usb_hcd_giveback_urb() code paths
- * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
- * unlinking it.
- */
- spin_lock_irqsave (&urb->lock, flags);
- spin_lock(&hcd_urb_list_lock);
+ struct usb_hcd *hcd;
+ int retval;
- sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
- if (hcd == NULL) {
- retval = -ENODEV;
- goto done;
- }
+ retval = unlink1(hcd, urb, status);
- /* insist the urb is still queued */
- list_for_each(tmp, &ep->urb_list) {
- if (tmp == &urb->urb_list)
- break;
- }
- if (tmp != &urb->urb_list) {
- retval = -EIDRM;
- goto done;
- }
-
- /* Any status except -EINPROGRESS means something already started to
- * unlink this URB from the hardware. So there's no more work to do.
- */
- if (urb->status != -EINPROGRESS) {
- retval = -EBUSY;
- goto done;
- }
-
- /* IRQ setup can easily be broken so that USB controllers
- * never get completion IRQs ... maybe even the ones we need to
- * finish unlinking the initial failed usb_set_address()
- * or device descriptor fetch.
- */
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
- !is_root_hub(urb->dev)) {
- dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ.\n");
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
- }
-
- urb->status = status;
-
- spin_unlock(&hcd_urb_list_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
-
- retval = unlink1 (hcd, urb);
if (retval == 0)
retval = -EINPROGRESS;
- return retval;
-
-done:
- spin_unlock(&hcd_urb_list_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
- if (retval != -EIDRM && sys && sys->driver)
- dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+ urb, retval);
return retval;
}
@@ -1162,6 +1257,7 @@ done:
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
* Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1265,27 @@ done:
* (and is done using urb->hcpriv). It also released all HCD locks;
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked. Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
*/
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
- urb_unlink(hcd, urb);
- usbmon_urb_complete (&hcd->self, urb);
+ urb->hcpriv = NULL;
+ if (unlikely(urb->unlinked))
+ status = urb->unlinked;
+ else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
+ urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
@@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example: a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely. The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
*/
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
+ if (!ep)
+ return;
+ might_sleep();
hcd = bus_to_hcd(udev->bus);
- local_irq_disable ();
- /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+ /* No more submits can occur */
rescan:
- spin_lock(&hcd_urb_list_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
- int tmp;
+ int is_in;
- /* the urb may already have been unlinked */
- if (urb->status != -EINPROGRESS)
+ if (urb->unlinked)
continue;
usb_get_urb (urb);
+ is_in = usb_urb_dir_in(urb);
spin_unlock(&hcd_urb_list_lock);
- spin_lock (&urb->lock);
- tmp = urb->status;
- if (tmp == -EINPROGRESS)
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
-
- /* kick hcd unless it's already returning this */
- if (tmp == -EINPROGRESS) {
- tmp = urb->pipe;
- unlink1 (hcd, urb);
- dev_dbg (hcd->self.controller,
- "shutdown urb %p pipe %08x ep%d%s%s\n",
- urb, tmp, usb_pipeendpoint (tmp),
- (tmp & USB_DIR_IN) ? "in" : "out",
- ({ char *s; \
- switch (usb_pipetype (tmp)) { \
- case PIPE_CONTROL: s = ""; break; \
- case PIPE_BULK: s = "-bulk"; break; \
- case PIPE_INTERRUPT: s = "-intr"; break; \
- default: s = "-iso"; break; \
- }; s;}));
- }
+ /* kick hcd */
+ unlink1(hcd, urb, -ESHUTDOWN);
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %p ep%d%s%s\n",
+ urb, usb_endpoint_num(&ep->desc),
+ is_in ? "in" : "out",
+ ({ char *s;
+
+ switch (usb_endpoint_type(&ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ s = ""; break;
+ case USB_ENDPOINT_XFER_BULK:
+ s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ s = "-intr"; break;
+ default:
+ s = "-iso"; break;
+ };
+ s;
+ }));
usb_put_urb (urb);
/* list contents may have changed */
goto rescan;
}
- spin_unlock(&hcd_urb_list_lock);
- local_irq_enable ();
-
- /* synchronize with the hardware, so old configuration state
- * clears out immediately (and will be freed).
- */
- might_sleep ();
- if (hcd->driver->endpoint_disable)
- hcd->driver->endpoint_disable (hcd, ep);
+ spin_unlock_irq(&hcd_urb_list_lock);
- /* Wait until the endpoint queue is completely empty. Most HCDs
- * will have done this already in their endpoint_disable method,
- * but some might not. And there could be root-hub control URBs
- * still pending since they aren't affected by the HCDs'
- * endpoint_disable methods.
- */
+ /* Wait until the endpoint queue is completely empty */
while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock);
@@ -1278,6 +1370,25 @@ rescan:
}
}
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable(hcd, ep);
+}
+
/*-------------------------------------------------------------------------*/
/* called in any context */
@@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
-
return hcd;
}
EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+ hcd->authorized_default = hcd->wireless? 0 : 1;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init,
@@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
+ retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+ if (retval < 0) {
+ printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+ retval);
+ goto error_create_attr_group;
+ }
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
+error_create_attr_group:
+ mutex_lock(&usb_bus_list_lock);
+ usb_disconnect(&hcd->self.root_hub);
+ mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
@@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
+ sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index b5ebb73c233..98e24194a4a 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
#ifdef __KERNEL__
+#include <linux/rwsem.h>
+
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
@@ -51,6 +53,12 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ * connect by default or they require explicit
+ * user space authorization; this bit is settable
+ * through /sys/class/usb_host/X/authorized_default.
+ * For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
+ unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
- int (*urb_enqueue) (struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
- struct urb *urb,
- gfp_t mem_flags);
- int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+ int (*urb_enqueue)(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags);
+ int (*urb_dequeue)(struct usb_hcd *hcd,
+ struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
- void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+ void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status)
{
if (bus->monitored)
- (*mon_ops->urb_complete)(bus, urb);
+ (*mon_ops->urb_complete)(bus, urb, status);
}
int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status) {}
#endif /* CONFIG_USB_MON */
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
: (in_interrupt () ? "in_interrupt" : "can sleep"))
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f7b337feb3e..d20cb545a6e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
"first one fails");
+/* Mutual exclusion for EHCI CF initialization. This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
static inline char *portspeed(int portstatus)
{
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
- int status;
+ int status = urb->status;
int i;
unsigned long bits;
- switch (urb->status) {
+ switch (status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
- dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+ dev_dbg (hub->intfdev, "transfer --> %d\n", status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
- hub->error = urb->status;
+ hub->error = status;
/* FALL THROUGH */
/* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#endif
/**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not. Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
*/
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
{
- int err;
-
- /* Determine quirks */
- usb_detect_quirks(udev);
-
- err = usb_get_configuration(udev);
- if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- goto fail;
- }
-
- /* read the standard strings and cache them if present */
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
- udev->manufacturer = usb_cache_string(udev,
- udev->descriptor.iManufacturer);
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
- /* Tell the world! */
- dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
+ int err = 0;
#ifdef CONFIG_USB_OTG
/*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
err = -ENOTSUPP;
goto fail;
}
+fail:
#endif
+ return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+ int err;
+ if (udev->config == NULL) {
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+ }
+ if (udev->wusb == 1 && udev->authorized == 0) {
+ udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ }
+ else {
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+ }
+ err = usb_configure_device_otg(udev);
+fail:
+ return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+ int err;
+
+ usb_detect_quirks(udev); /* Determine quirks */
+ err = usb_configure_device(udev); /* detect & probe dev/intfs */
+ if (err < 0)
+ goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
- if (udev->parent)
- usb_autosuspend_device(udev->parent);
goto fail;
}
-exit:
+ /* Tell the world! */
+ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- goto exit;
+ return err;
}
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+ unsigned cnt;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 0)
+ goto out_unauthorized;
+ usb_dev->authorized = 0;
+ usb_set_configuration(usb_dev, -1);
+ usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->config);
+ usb_dev->config = NULL;
+ for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+ kfree(usb_dev->rawdescriptors[cnt]);
+ usb_dev->descriptor.bNumConfigurations = 0;
+ kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+ usb_unlock_device(usb_dev);
+ return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+ int result = 0, c;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 1)
+ goto out_authorized;
+ kfree(usb_dev->product);
+ usb_dev->product = NULL;
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = NULL;
+ kfree(usb_dev->serial);
+ usb_dev->serial = NULL;
+ result = usb_autoresume_device(usb_dev);
+ if (result < 0) {
+ dev_err(&usb_dev->dev,
+ "can't autoresume for authorization: %d\n", result);
+ goto error_autoresume;
+ }
+ result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+ if (result < 0) {
+ dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+ "authorization: %d\n", result);
+ goto error_device_descriptor;
+ }
+ usb_dev->authorized = 1;
+ result = usb_configure_device(usb_dev);
+ if (result < 0)
+ goto error_configure;
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = usb_choose_configuration(usb_dev);
+ if (c >= 0) {
+ result = usb_set_configuration(usb_dev, c);
+ if (result) {
+ dev_err(&usb_dev->dev,
+ "can't set config #%d, error %d\n", c, result);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+ dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+ usb_unlock_device(usb_dev); // complements locktree
+ return result;
+}
+
+
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
@@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
+ /* Block EHCI CF initialization during the port reset.
+ * Some companion controllers don't like it when they mix.
+ */
+ down_read(&ehci_cf_port_reset_rwsem);
+
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
+ udev->devnum = 0; /* Device now at address 0 */
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
- return status;
+ goto done;
}
dev_dbg (hub->intfdev,
@@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
+ done:
+ up_read(&ehci_cf_port_reset_rwsem);
return status;
}
@@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
- udev->state != USB_STATE_SUSPENDED
-#else
- udev->dev.power.power_state.event
- == PM_EVENT_ON
-#endif
- ) {
+ if (udev && udev->can_submit) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
@@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+ usb_enable_endpoint(udev, &udev->ep0);
}
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
- if (udev->devnum == 0)
+ if (devnum <= 1)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
- USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+ USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
+ udev->devnum = devnum; /* Device now using proper address */
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
}
@@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
+ int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
oldspeed = udev->speed;
-
+
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
- udev->bus->controller->driver->name, udev->devnum);
+ udev->bus->controller->driver->name, devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev);
+ retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
msleep(200);
@@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
- udev->devnum, retval);
+ devnum, retval);
goto fail;
}
@@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = 0;
fail:
- if (retval)
+ if (retval) {
hub_port_disable(hub, port1, 0);
+ udev->devnum = devnum; /* for disconnect processing */
+ }
mutex_unlock(&usb_address0_mutex);
return retval;
}
@@ -2699,9 +2831,9 @@ static void hub_events(void)
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
- hub->limited_power = 0;
- else
hub->limited_power = 1;
+ else
+ hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index d8f7b089a8f..c021af39037 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+ usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+ io->sg, io->nents);
io->dev = NULL;
}
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
status, io->status);
// BUG ();
}
@@ -379,7 +380,8 @@ int usb_sg_init (
*/
dma = (dev->dev.dma_mask != NULL);
if (dma)
- io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+ io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+ sg, nents);
else
io->entries = nents;
@@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep && dev->bus)
- usb_hcd_endpoint_disable(dev, ep);
+ if (ep) {
+ ep->enabled = 0;
+ usb_hcd_flush_endpoint(dev, ep);
+ usb_hcd_disable_endpoint(dev, ep);
+ }
}
/**
@@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
- unsigned int epaddr = ep->desc.bEndpointAddress;
- unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
- int is_control;
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
- is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_CONTROL);
- if (usb_endpoint_out(epaddr) || is_control) {
+ if (is_out || is_control) {
usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
- if (!usb_endpoint_out(epaddr) || is_control) {
+ if (!is_out || is_control) {
usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
+ ep->enabled = 1;
}
/*
@@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_host_interface *alt;
int ret;
int manual = 0;
+ int changed;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- if (device_is_registered(&iface->dev))
+ changed = (iface->cur_altsetting != alt);
+ if (changed && device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.)
*/
usb_enable_interface(dev, iface);
- if (device_is_registered(&iface->dev))
+ if (changed && device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0;
@@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@@ -1339,14 +1344,11 @@ void usb_release_interface(struct device *dev)
}
#ifdef CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
struct usb_interface *intf;
struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -1359,39 +1361,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
alt = intf->cur_altsetting;
#ifdef CONFIG_USB_DEVICEFS
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
+ if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ if (add_uevent_var(env,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -1404,14 +1397,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_if_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -1481,6 +1472,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
* channels are available independently; and choosing between open
* standard device protocols (like CDC) or proprietary ones.
*
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
@@ -1502,7 +1496,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
- if (configuration == -1)
+ if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ebf3dc20110..d42c561c75f 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
- /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
- { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* SGS Thomson Microelectronics 4in1 card reader */
- { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
- { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Benq S2W 3300U */
- { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N1240U/LiDE30 */
- { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N650U/N656U */
- { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan 1220U */
- { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
- { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* old Cannon scanner */
- { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp. Perfection 1200 */
- { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp. Perfection 660 */
- { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Epson Perfection 1260 Photo */
- { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp - Perfection 1670 */
- { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* EPSON Perfection 2480 */
- { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp.*/
- { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Samsung ML-2010 printer */
- { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Samsung ML-2510 Series printer */
- { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Elsa MicroLink 56k (V.250) */
- { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Ultima Electronics Corp.*/
- { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Genesys USB-to-IDE */
- { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* USB Graphical LCD - EEH Datalink GmbH */
- { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
- /* Agfa Snapscan1212u */
- { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seagate RSS LLC */
- { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Umax [hex] Astra 3400U */
- { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
- /* Alcor multi-card reader */
- { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Canon EOS 5D in PC Connection mode */
- { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* RIM Blackberry */
- { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Apple iPhone */
- { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
/* SKYMEDI USB_DRIVE */
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef CONFIG_USB_SUSPEND
- /* disable autosuspend, but allow the user to re-enable it via sysfs */
- udev->autosuspend_disabled = 1;
-#endif
-}
-
static const struct usb_device_id *find_id(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
- /* do any special quirk handling here if needed */
- if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
- usb_autosuspend_quirk(udev);
-
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
- udev->autosuspend_delay = -1;
+ udev->autosuspend_disabled = 1;
#endif
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 2ab222be8fd..b04afd06e50 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_device *usb_dev = to_usb_device(dev);
+ unsigned val;
+ result = sscanf(buf, "%u\n", &val);
+ if (result != 1)
+ result = -EINVAL;
+ else if (val == 0)
+ result = usb_deauthorize_device(usb_dev);
+ else
+ result = usb_authorize_device(usb_dev);
+ return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+ usb_dev_authorized_show, usb_dev_authorized_store);
+
+
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
+ &dev_attr_urbnum.attr,
/* device attributes */
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
+ &dev_attr_authorized.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index be630228461..c20c03aaf01 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/log2.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
- spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
- int pipe, temp, max;
- struct usb_device *dev;
- int is_out;
+ int xfertype, max;
+ struct usb_device *dev;
+ struct usb_host_endpoint *ep;
+ int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
- if (!(dev = urb->dev) ||
- (dev->state < USB_STATE_DEFAULT) ||
- (!dev->bus) || (dev->devnum <= 0))
+ if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
return -ENODEV;
- if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
- || dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
+ /* For now, get the endpoint from the pipe. Eventually drivers
+ * will be required to set urb->ep directly and we will eliminate
+ * urb->pipe.
+ */
+ ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep)
+ return -ENOENT;
+
+ urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
- pipe = urb->pipe;
- temp = usb_pipetype(pipe);
- is_out = usb_pipeout(pipe);
+ xfertype = usb_endpoint_type(&ep->desc);
+ if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+ struct usb_ctrlrequest *setup =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!setup)
+ return -ENOEXEC;
+ is_out = !(setup->bRequestType & USB_DIR_IN) ||
+ !setup->wLength;
+ } else {
+ is_out = usb_endpoint_dir_out(&ep->desc);
+ }
- if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
- return -ENODEV;
+ /* Cache the direction for later use */
+ urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+ (is_out ? URB_DIR_OUT : URB_DIR_IN);
- /* FIXME there should be a sharable lock protecting us against
- * config/altsetting changes and disconnects, kicking in here.
- * (here == before maxpacket, and eventually endpoint type,
- * checks get made.)
- */
+ if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+ dev->state < USB_STATE_CONFIGURED)
+ return -ENODEV;
- max = usb_maxpacket(dev, pipe, is_out);
+ max = le16_to_cpu(ep->desc.wMaxPacketSize);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint(pipe), is_out ? "out" : "in",
+ usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
- if (temp == PIPE_ISOCHRONOUS) {
+ if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
- URB_NO_INTERRUPT);
- switch (temp) {
- case PIPE_BULK:
+ URB_NO_INTERRUPT | URB_DIR_MASK);
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
- case PIPE_CONTROL:
+ case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
- case PIPE_ISOCHRONOUS:
+ case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
- switch (temp) {
- case PIPE_ISOCHRONOUS:
- case PIPE_INTERRUPT:
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
- temp = 1024 * 8;
+ max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
- if (temp == PIPE_INTERRUPT) {
+ if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
- temp = 128;
+ max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
- temp = 1024;
+ max = 1024;
}
break;
default:
return -EINVAL;
}
- /* power of two? */
- while (temp > urb->interval)
- temp >>= 1;
- urb->interval = temp;
+ /* Round down to a power of 2, no more than max */
+ urb->interval = min(max, 1 << ilog2(urb->interval));
}
return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!(urb->dev && urb->dev->bus))
+ if (!urb->dev)
return -ENODEV;
+ if (!urb->ep)
+ return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
@@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
*/
void usb_kill_urb(struct urb *urb)
{
+ static DEFINE_MUTEX(reject_mutex);
+
might_sleep();
- if (!(urb && urb->dev && urb->dev->bus))
+ if (!(urb && urb->dev && urb->ep))
return;
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
++urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
--urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
}
/**
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c66fd6..c99938d5f78 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
#endif /* CONFIG_PM */
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+ return hcd->wireless;
+}
+
+
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
+ struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+ unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
+ atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
- dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+ usb_enable_endpoint(dev, &dev->ep0);
+ dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
+ if (root_hub) /* Root hub always ok [and always wired] */
+ dev->authorized = 1;
+ else {
+ dev->authorized = usb_hcd->authorized_default;
+ dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+ }
return dev;
}
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
- || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
// FIXME generic api broken like pci, can't report errors
return dma_map_sg(controller, sg, nents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_sync_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_unmap_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa0338f4..c52626c51f7 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+extern void usb_enable_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 767aed5b4be..f81d08d6538 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
+config USB_GADGET_DEBUG_FS
+ boolean "Debugging information files in debugfs"
+ depends on USB_GADGET && DEBUG_FS
+ help
+ Some of the drivers in the "gadget" framework can expose
+ debugging information in files under /sys/kernel/debug/.
+ The information in these files may help when you're
+ troubleshooting or bringing up a driver on a new board.
+ Enable these files by choosing "Y" here. If in doubt, or
+ to conserve kernel memory, say "N".
+
config USB_GADGET_SELECTED
boolean
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_ATMEL_USBA
+ boolean "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+ depends on AVR32
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+ tristate
+ depends on USB_GADGET_ATMEL_USBA
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
-
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 1bc0f03550c..904e57bf611 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 714156ca8fe..1c804060252 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -69,7 +69,7 @@
/* gadget stack */
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/* udc specific */
#include "amd5536udc.h"
@@ -3244,7 +3244,6 @@ static int udc_pci_probe(
retval = -ENOMEM;
goto finished;
}
- memset(dev, 0, sizeof(struct udc));
/* pci setup */
if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@ static int udc_pci_probe(
pci_set_drvdata(pdev, dev);
- /* chip revision */
- dev->chiprev = 0;
+ /* chip revision for Hs AMD5536 */
+ dev->chiprev = pdev->revision;
pci_set_master(pdev);
pci_set_mwi(pdev);
- /* chip rev for Hs AMD5536 */
- pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
/* init dma pools */
if (use_dma) {
retval = init_dma_pools(dev);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 63d7d656869..a6adf7e0f6f 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 00000000000..4fb5ff46957
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_ep *ep = inode->i_private;
+ struct usba_request *req, *req_copy;
+ struct list_head *queue_data;
+
+ queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+ if (!queue_data)
+ return -ENOMEM;
+ INIT_LIST_HEAD(queue_data);
+
+ spin_lock_irq(&ep->udc->lock);
+ list_for_each_entry(req, &ep->queue, queue) {
+ req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+ if (!req_copy)
+ goto fail;
+ memcpy(req_copy, req, sizeof(*req_copy));
+ list_add_tail(&req_copy->queue, queue_data);
+ }
+ spin_unlock_irq(&ep->udc->lock);
+
+ file->private_data = queue_data;
+ return 0;
+
+fail:
+ spin_unlock_irq(&ep->udc->lock);
+ list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct list_head *queue = file->private_data;
+ struct usba_request *req, *tmp_req;
+ size_t len, remaining, actual = 0;
+ char tmpbuf[38];
+
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ list_for_each_entry_safe(req, tmp_req, queue, queue) {
+ len = snprintf(tmpbuf, sizeof(tmpbuf),
+ "%8p %08x %c%c%c %5d %c%c%c\n",
+ req->req.buf, req->req.length,
+ req->req.no_interrupt ? 'i' : 'I',
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 's' : 'S',
+ req->req.status,
+ req->submitted ? 'F' : 'f',
+ req->using_dma ? 'D' : 'd',
+ req->last_transaction ? 'L' : 'l');
+ len = min(len, sizeof(tmpbuf));
+ if (len > nbytes)
+ break;
+
+ list_del(&req->queue);
+ kfree(req);
+
+ remaining = __copy_to_user(buf, tmpbuf, len);
+ actual += len - remaining;
+ if (remaining)
+ break;
+
+ nbytes -= len;
+ buf += len;
+ }
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+ return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+ struct list_head *queue_data = file->private_data;
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_udc *udc;
+ unsigned int i;
+ u32 *data;
+ int ret = -ENOMEM;
+
+ mutex_lock(&inode->i_mutex);
+ udc = inode->i_private;
+ data = kmalloc(inode->i_size, GFP_KERNEL);
+ if (!data)
+ goto out;
+
+ spin_lock_irq(&udc->lock);
+ for (i = 0; i < inode->i_size / 4; i++)
+ data[i] = __raw_readl(udc->regs + i * 4);
+ spin_unlock_irq(&udc->lock);
+
+ file->private_data = data;
+ ret = 0;
+
+out:
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = simple_read_from_buffer(buf, nbytes, ppos,
+ file->private_data,
+ file->f_dentry->d_inode->i_size);
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queue_dbg_open,
+ .llseek = no_llseek,
+ .read = queue_dbg_read,
+ .release = queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = regs_dbg_open,
+ .llseek = generic_file_llseek,
+ .read = regs_dbg_read,
+ .release = regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+ struct dentry *ep_root;
+
+ ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+ if (!ep_root)
+ goto err_root;
+ ep->debugfs_dir = ep_root;
+
+ ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+ ep, &queue_dbg_fops);
+ if (!ep->debugfs_queue)
+ goto err_queue;
+
+ if (ep->can_dma) {
+ ep->debugfs_dma_status
+ = debugfs_create_u32("dma_status", 0400, ep_root,
+ &ep->last_dma_status);
+ if (!ep->debugfs_dma_status)
+ goto err_dma_status;
+ }
+ if (ep_is_control(ep)) {
+ ep->debugfs_state
+ = debugfs_create_u32("state", 0400, ep_root,
+ &ep->state);
+ if (!ep->debugfs_state)
+ goto err_state;
+ }
+
+ return;
+
+err_state:
+ if (ep->can_dma)
+ debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+ debugfs_remove(ep->debugfs_queue);
+err_queue:
+ debugfs_remove(ep_root);
+err_root:
+ dev_err(&ep->udc->pdev->dev,
+ "failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+ debugfs_remove(ep->debugfs_queue);
+ debugfs_remove(ep->debugfs_dma_status);
+ debugfs_remove(ep->debugfs_state);
+ debugfs_remove(ep->debugfs_dir);
+ ep->debugfs_dma_status = NULL;
+ ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+ struct dentry *root, *regs;
+ struct resource *regs_resource;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+ udc->debugfs_root = root;
+
+ regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+ if (!regs)
+ goto err_regs;
+
+ regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+ CTRL_IOMEM_ID);
+ regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+ udc->debugfs_regs = regs;
+
+ usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+ return;
+
+err_regs:
+ debugfs_remove(root);
+err_root:
+ udc->debugfs_root = NULL;
+ dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+ usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+ debugfs_remove(udc->debugfs_regs);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_regs = NULL;
+ udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+ if (udc->vbus_pin != -1)
+ return gpio_get_value(udc->vbus_pin);
+
+ /* No Vbus detection: Assume always present */
+ return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+ for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+ tmp = *(unsigned long *)buf;
+ if (len >= 4) {
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ __raw_writel(tmp, fifo);
+ } else {
+ do {
+ DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24);
+ __raw_writeb(tmp >> 24, fifo);
+ fifo++;
+ tmp <<= 8;
+ } while (--len);
+ break;
+ }
+ }
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+ union {
+ unsigned long *w;
+ unsigned char *b;
+ } p;
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+ for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+ if (len >= 4) {
+ tmp = __raw_readl(fifo);
+ *p.w = tmp;
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ } else {
+ do {
+ tmp = __raw_readb(fifo);
+ *p.b = tmp;
+ DBG(DBG_FIFO, " -> %02lx\n", tmp);
+ fifo++, p.b++;
+ } while (--len);
+ }
+ }
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+ unsigned int transaction_len;
+
+ transaction_len = req->req.length - req->req.actual;
+ req->last_transaction = 1;
+ if (transaction_len > ep->ep.maxpacket) {
+ transaction_len = ep->ep.maxpacket;
+ req->last_transaction = 0;
+ } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+ req->last_transaction = 0;
+
+ DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+ ep->ep.name, req, transaction_len,
+ req->last_transaction ? ", done" : "");
+
+ copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+ DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+ ep->ep.name, req, req->req.length);
+
+ req->req.actual = 0;
+ req->submitted = 1;
+
+ if (req->using_dma) {
+ if (req->req.length == 0) {
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ return;
+ }
+
+ if (req->req.zero)
+ usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+ else
+ usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+ usba_dma_writel(ep, ADDRESS, req->req.dma);
+ usba_dma_writel(ep, CONTROL, req->ctrl);
+ } else {
+ next_fifo_transaction(ep, req);
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ } else {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ }
+ }
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+ struct usba_request *req;
+
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ if (!req->submitted)
+ submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+ ep->state = STATUS_STAGE_IN;
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req;
+ unsigned long status;
+ unsigned int bytecount, nr_busy;
+ int is_complete = 0;
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+ while (nr_busy > 0) {
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ break;
+ }
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+ if (status & (1 << 31))
+ is_complete = 1;
+ if (req->req.actual + bytecount >= req->req.length) {
+ is_complete = 1;
+ bytecount = req->req.length - req->req.actual;
+ }
+
+ copy_from_fifo(req->req.buf + req->req.actual,
+ ep->fifo, bytecount);
+ req->req.actual += bytecount;
+
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+ if (is_complete) {
+ DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+ req->req.status = 0;
+ list_del_init(&req->queue);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+ }
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ if (is_complete && ep_is_control(ep)) {
+ send_status(udc, ep);
+ break;
+ }
+ }
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+ struct usba_udc *udc = ep->udc;
+
+ WARN_ON(!list_empty(&req->queue));
+
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+
+ if (req->mapped) {
+ dma_unmap_single(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ DBG(DBG_GADGET | DBG_REQ,
+ "%s: req %p complete: status %d, actual %u\n",
+ ep->ep.name, req, req->req.status, req->req.actual);
+
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, list, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags, ept_cfg, maxpacket;
+ unsigned int nr_trans;
+
+ DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+ maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+ if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+ || ep->index == 0
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || maxpacket == 0
+ || maxpacket > ep->fifo_size) {
+ DBG(DBG_ERR, "ep_enable: Invalid argument");
+ return -EINVAL;
+ }
+
+ ep->is_isoc = 0;
+ ep->is_in = 0;
+
+ if (maxpacket <= 8)
+ ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+ else
+ /* LSB is bit 1, not 0 */
+ ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+ DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+ ep->ep.name, ept_cfg, maxpacket);
+
+ if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ ep->is_in = 1;
+ ept_cfg |= USBA_EPT_DIR_IN;
+ }
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!ep->can_isoc) {
+ DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+ ep->ep.name);
+ return -EINVAL;
+ }
+
+ /*
+ * Bits 11:12 specify number of _additional_
+ * transactions per microframe.
+ */
+ nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+ if (nr_trans > 3)
+ return -EINVAL;
+
+ ep->is_isoc = 1;
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+ /*
+ * Do triple-buffering on high-bandwidth iso endpoints.
+ */
+ if (nr_trans > 1 && ep->nr_banks == 3)
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+ else
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ }
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ if (ep->desc) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+ return -EBUSY;
+ }
+
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ usba_ep_writel(ep, CFG, ept_cfg);
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+ if (ep->can_dma) {
+ u32 ctrl;
+
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)
+ | USBA_BF(DMA_INT, 1 << ep->index)));
+ ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+ usba_ep_writel(ep, CTL_ENB, ctrl);
+ } else {
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)));
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+ (unsigned long)usba_ep_readl(ep, CFG));
+ DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+ (unsigned long)usba_readl(udc, INT_ENB));
+
+ return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ LIST_HEAD(req_list);
+ unsigned long flags;
+
+ DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!ep->desc) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+ return -EINVAL;
+ }
+ ep->desc = NULL;
+
+ list_splice_init(&ep->queue, &req_list);
+ if (ep->can_dma) {
+ usba_dma_writel(ep, CONTROL, 0);
+ usba_dma_writel(ep, ADDRESS, 0);
+ usba_dma_readl(ep, STATUS);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+ usba_writel(udc, INT_ENB,
+ usba_readl(udc, INT_ENB)
+ & ~USBA_BF(EPT_INT, 1 << ep->index));
+
+ request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct usba_request *req;
+
+ DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->req.dma = DMA_ADDR_INVALID;
+
+ return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_request *req = to_usba_req(_req);
+
+ DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+ kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+ struct usba_request *req, gfp_t gfp_flags)
+{
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+ ep->ep.name, req->req.length, req->req.dma,
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 'S' : 's',
+ req->req.no_interrupt ? 'I' : 'i');
+
+ if (req->req.length > 0x10000) {
+ /* Lengths from 0 to 65536 (inclusive) are supported */
+ DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+ return -EINVAL;
+ }
+
+ req->using_dma = 1;
+
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(
+ &udc->pdev->dev, req->req.buf, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+ | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+ | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+ if (ep->is_in)
+ req->ctrl |= USBA_DMA_END_BUF_EN;
+
+ /*
+ * Add this request to the queue and submit for DMA if
+ * possible. Check if we're still alive first -- we may have
+ * received a reset since last time we checked.
+ */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ if (list_empty(&ep->queue))
+ submit_request(ep, req);
+
+ list_add_tail(&req->queue, &ep->queue);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct usba_request *req = to_usba_req(_req);
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+ ep->ep.name, req, _req->length);
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+ return -ESHUTDOWN;
+
+ req->submitted = 0;
+ req->using_dma = 0;
+ req->last_transaction = 0;
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ if (ep->can_dma)
+ return queue_dma(udc, ep, req, gfp_flags);
+
+ /* May have received a reset since last time we checked */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ list_add_tail(&req->queue, &ep->queue);
+
+ if (ep->is_in || (ep_is_control(ep)
+ && (ep->state == DATA_STAGE_IN
+ || ep->state == STATUS_STAGE_IN)))
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ else
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+ req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+ unsigned int timeout;
+ u32 status;
+
+ /*
+ * Stop the DMA controller. When writing both CH_EN
+ * and LINK to 0, the other bits are not affected.
+ */
+ usba_dma_writel(ep, CONTROL, 0);
+
+ /* Wait for the FIFO to empty */
+ for (timeout = 40; timeout; --timeout) {
+ status = usba_dma_readl(ep, STATUS);
+ if (!(status & USBA_DMA_CH_EN))
+ break;
+ udelay(1);
+ }
+
+ if (pstatus)
+ *pstatus = status;
+
+ if (timeout == 0) {
+ dev_err(&ep->udc->pdev->dev,
+ "%s: timed out waiting for DMA FIFO to empty\n",
+ ep->ep.name);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req = to_usba_req(_req);
+ unsigned long flags;
+ u32 status;
+
+ DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+ ep->ep.name, req);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (req->using_dma) {
+ /*
+ * If this request is currently being transferred,
+ * stop the DMA controller and reset the FIFO.
+ */
+ if (ep->queue.next == &req->queue) {
+ status = usba_dma_readl(ep, STATUS);
+ if (status & USBA_DMA_CH_EN)
+ stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+
+ usba_update_req(ep, req, status);
+ }
+ }
+
+ /*
+ * Errors should stop the queue from advancing until the
+ * completion function returns.
+ */
+ list_del_init(&req->queue);
+
+ request_complete(ep, req, -ECONNRESET);
+
+ /* Process the next request if any */
+ submit_next_request(ep);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret = 0;
+
+ DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+ value ? "set" : "clear");
+
+ if (!ep->desc) {
+ DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+ ep->ep.name);
+ return -ENODEV;
+ }
+ if (ep->is_isoc) {
+ DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+ ep->ep.name);
+ return -ENOTTY;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*
+ * We can't halt IN endpoints while there are still data to be
+ * transferred
+ */
+ if (!list_empty(&ep->queue)
+ || ((value && ep->is_in && (usba_ep_readl(ep, STA)
+ & USBA_BF(BUSY_BANKS, -1L))))) {
+ ret = -EAGAIN;
+ } else {
+ if (value)
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ else
+ usba_ep_writel(ep, CLR_STA,
+ USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+ usba_ep_readl(ep, STA);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+
+ return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+ .enable = usba_ep_enable,
+ .disable = usba_ep_disable,
+ .alloc_request = usba_ep_alloc_request,
+ .free_request = usba_ep_free_request,
+ .queue = usba_ep_queue,
+ .dequeue = usba_ep_dequeue,
+ .set_halt = usba_ep_set_halt,
+ .fifo_status = usba_ep_fifo_status,
+ .fifo_flush = usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+
+ return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+ u32 ctrl;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+ ctrl = usba_readl(udc, CTRL);
+ usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (is_selfpowered)
+ udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+ .get_frame = usba_udc_get_frame,
+ .wakeup = usba_udc_wakeup,
+ .set_selfpowered = usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
+{ \
+ .ep = { \
+ .ops = &usba_ep_ops, \
+ .name = nam, \
+ .maxpacket = maxpkt, \
+ }, \
+ .udc = &the_udc, \
+ .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \
+ .fifo_size = maxpkt, \
+ .nr_banks = maxbk, \
+ .index = idx, \
+ .can_dma = dma, \
+ .can_isoc = isoc, \
+}
+
+static struct usba_ep usba_ep[] = {
+ EP("ep0", 0, 64, 1, 0, 0),
+ EP("ep1in-bulk", 1, 512, 2, 1, 1),
+ EP("ep2out-bulk", 2, 512, 2, 1, 1),
+ EP("ep3in-int", 3, 64, 3, 1, 0),
+ EP("ep4out-int", 4, 64, 3, 1, 0),
+ EP("ep5in-iso", 5, 1024, 3, 1, 1),
+ EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
+ /* FIXME: I have no idea what to put here */
+ .bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+ .gadget = {
+ .ops = &usba_udc_ops,
+ .ep0 = &usba_ep[0].ep,
+ .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+ .is_dualspeed = 1,
+ .name = "atmel_usba_udc",
+ .dev = {
+ .bus_id = "gadget",
+ .release = nop_release,
+ },
+ },
+
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+ struct usba_ep *ep;
+ struct usba_request *req, *tmp_req;
+
+ usba_writel(udc, EPT_RST, ~0UL);
+
+ ep = to_usba_ep(udc->gadget.ep0);
+ list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, -ECONNRESET);
+ }
+
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc) {
+ spin_unlock(&udc->lock);
+ usba_ep_disable(&ep->ep);
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+ struct usba_ep *ep;
+
+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+ return to_usba_ep(udc->gadget.ep0);
+
+ list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+ u8 bEndpointAddress;
+
+ if (!ep->desc)
+ continue;
+ bEndpointAddress = ep->desc->bEndpointAddress;
+ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+ continue;
+ if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+ == (wIndex & USB_ENDPOINT_NUMBER_MASK))
+ return ep;
+ }
+
+ return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+ if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+ return 1;
+ return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+ u32 regval;
+
+ DBG(DBG_BUS, "setting address %u...\n", addr);
+ regval = usba_readl(udc, CTRL);
+ regval = USBA_BFINS(DEV_ADDR, addr, regval);
+ usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+ static const char test_packet_buffer[] = {
+ /* JKJKJKJK * 9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK * 8 */
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ /* JJKKJJKK * 8 */
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ /* JJJJJJJKKKKKKK * 8 */
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* JJJJJJJK * 8 */
+ 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+ /* {JKKKKKKK * 10}, JK */
+ 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+ };
+ struct usba_ep *ep;
+ struct device *dev = &udc->pdev->dev;
+ int test_mode;
+
+ test_mode = udc->test_mode;
+
+ /* Start from a clean slate */
+ reset_all_endpoints(udc);
+
+ switch (test_mode) {
+ case 0x0100:
+ /* Test_J */
+ usba_writel(udc, TST, USBA_TST_J_MODE);
+ dev_info(dev, "Entering Test_J mode...\n");
+ break;
+ case 0x0200:
+ /* Test_K */
+ usba_writel(udc, TST, USBA_TST_K_MODE);
+ dev_info(dev, "Entering Test_K mode...\n");
+ break;
+ case 0x0300:
+ /*
+ * Test_SE0_NAK: Force high-speed mode and set up ep0
+ * for Bulk IN transfers
+ */
+ ep = &usba_ep[0];
+ usba_writel(udc, TST,
+ USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+ }
+ break;
+ case 0x0400:
+ /* Test_Packet */
+ ep = &usba_ep[0];
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_Packet: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ usba_writel(udc, TST, USBA_TST_PKT_MODE);
+ copy_to_fifo(ep->fifo, test_packet_buffer,
+ sizeof(test_packet_buffer));
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ dev_info(dev, "Entering Test_Packet mode...\n");
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+ return true;
+ return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+ struct usb_ctrlrequest *crq)
+{
+ int retval = 0;;
+
+ switch (crq->bRequest) {
+ case USB_REQ_GET_STATUS: {
+ u16 status;
+
+ if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+ status = cpu_to_le16(udc->devstatus);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+ status = __constant_cpu_to_le16(0);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+ struct usba_ep *target;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ status = 0;
+ if (is_stalled(udc, target))
+ status |= __constant_cpu_to_le16(1);
+ } else
+ goto delegate;
+
+ /* Write directly to the FIFO. No queueing is done. */
+ if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+ goto stall;
+ ep->state = DATA_STAGE_IN;
+ __raw_writew(status, ep->fifo);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ break;
+ }
+
+ case USB_REQ_CLEAR_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_remote_wakeup(crq))
+ udc->devstatus
+ &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+ else
+ /* Can't CLEAR_FEATURE TEST_MODE */
+ goto stall;
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+ if (target->index != 0)
+ usba_ep_writel(target, CLR_STA,
+ USBA_TOGGLE_CLR);
+ } else {
+ goto delegate;
+ }
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_test_mode(crq)) {
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_TEST;
+ udc->test_mode = le16_to_cpu(crq->wIndex);
+ return 0;
+ } else if (feature_is_dev_remote_wakeup(crq)) {
+ udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+ } else {
+ goto stall;
+ }
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+ } else
+ goto delegate;
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_ADDRESS:
+ if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ goto delegate;
+
+ set_address(udc, le16_to_cpu(crq->wValue));
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_ADDR;
+ break;
+
+ default:
+delegate:
+ spin_unlock(&udc->lock);
+ retval = udc->driver->setup(&udc->gadget, crq);
+ spin_lock(&udc->lock);
+ }
+
+ return retval;
+
+stall:
+ printk(KERN_ERR
+ "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+ "halting endpoint...\n",
+ ep->ep.name, crq->bRequestType, crq->bRequest,
+ le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+ le16_to_cpu(crq->wLength));
+ set_protocol_stall(udc, ep);
+ return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+restart:
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+ ep->ep.name, ep->state, epstatus, epctrl);
+
+ req = NULL;
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ }
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+ usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+ switch (ep->state) {
+ case DATA_STAGE_IN:
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = STATUS_STAGE_OUT;
+ break;
+ case STATUS_STAGE_ADDR:
+ /* Activate our new address */
+ usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+ | USBA_FADDR_EN));
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_IN:
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ submit_next_request(ep);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_TEST:
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ if (do_test_mode(udc))
+ set_protocol_stall(udc, ep);
+ break;
+ default:
+ printk(KERN_ERR
+ "udc: %s: TXCOMP: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ switch (ep->state) {
+ case STATUS_STAGE_OUT:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ }
+ ep->state = WAIT_FOR_SETUP;
+ break;
+
+ case DATA_STAGE_OUT:
+ receive_data(ep);
+ break;
+
+ default:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ printk(KERN_ERR
+ "udc: %s: RXRDY: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if (epstatus & USBA_RX_SETUP) {
+ union {
+ struct usb_ctrlrequest crq;
+ unsigned long data[2];
+ } crq;
+ unsigned int pkt_len;
+ int ret;
+
+ if (ep->state != WAIT_FOR_SETUP) {
+ /*
+ * Didn't expect a SETUP packet at this
+ * point. Clean up any pending requests (which
+ * may be successful).
+ */
+ int status = -EPROTO;
+
+ /*
+ * RXRDY and TXCOMP are dropped when SETUP
+ * packets arrive. Just pretend we received
+ * the status packet.
+ */
+ if (ep->state == STATUS_STAGE_OUT
+ || ep->state == STATUS_STAGE_IN) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ status = 0;
+ }
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+ }
+
+ pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+ DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+ if (pkt_len != sizeof(crq)) {
+ printk(KERN_WARNING "udc: Invalid packet length %u "
+ "(expected %lu)\n", pkt_len, sizeof(crq));
+ set_protocol_stall(udc, ep);
+ return;
+ }
+
+ DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+ copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+ /* Free up one bank in the FIFO so that we can
+ * generate or receive a reply right away. */
+ usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+ /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+ ep->state, crq.crq.bRequestType,
+ crq.crq.bRequest); */
+
+ if (crq.crq.bRequestType & USB_DIR_IN) {
+ /*
+ * The USB 2.0 spec states that "if wLength is
+ * zero, there is no data transfer phase."
+ * However, testusb #14 seems to actually
+ * expect a data phase even if wLength = 0...
+ */
+ ep->state = DATA_STAGE_IN;
+ } else {
+ if (crq.crq.wLength != __constant_cpu_to_le16(0))
+ ep->state = DATA_STAGE_OUT;
+ else
+ ep->state = STATUS_STAGE_IN;
+ }
+
+ ret = -1;
+ if (ep->index == 0)
+ ret = handle_ep0_setup(udc, ep, &crq.crq);
+ else {
+ spin_unlock(&udc->lock);
+ ret = udc->driver->setup(&udc->gadget, &crq.crq);
+ spin_lock(&udc->lock);
+ }
+
+ DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+ crq.crq.bRequestType, crq.crq.bRequest,
+ le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+ if (ret < 0) {
+ /* Let the host know that we failed */
+ set_protocol_stall(udc, ep);
+ }
+ }
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+ while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+ if (list_empty(&ep->queue)) {
+ dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+
+ if (req->using_dma) {
+ /* Send a zero-length packet */
+ usba_ep_writel(ep, SET_STA,
+ USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_DIS,
+ USBA_TX_PK_RDY);
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ } else {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+ }
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+ receive_data(ep);
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ }
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 status, control, pending;
+
+ status = usba_dma_readl(ep, STATUS);
+ control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+ pending = status & control;
+ DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+ if (status & USBA_DMA_CH_EN) {
+ dev_err(&udc->pdev->dev,
+ "DMA_CH_EN is set after transfer is finished!\n");
+ dev_err(&udc->pdev->dev,
+ "status=%#08x, pending=%#08x, control=%#08x\n",
+ status, pending, control);
+
+ /*
+ * try to pretend nothing happened. We might have to
+ * do something here...
+ */
+ }
+
+ if (list_empty(&ep->queue))
+ /* Might happen if a reset comes along at the right moment */
+ return;
+
+ if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ usba_update_req(ep, req, status);
+
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ u32 status;
+ u32 dma_status;
+ u32 ep_status;
+
+ spin_lock(&udc->lock);
+
+ status = usba_readl(udc, INT_STA);
+ DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+ if (status & USBA_DET_SUSPEND) {
+ usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+ DBG(DBG_BUS, "Suspend detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ if (status & USBA_WAKE_UP) {
+ usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+ DBG(DBG_BUS, "Wake Up CPU detected\n");
+ }
+
+ if (status & USBA_END_OF_RESUME) {
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+ DBG(DBG_BUS, "Resume detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ dma_status = USBA_BFEXT(DMA_INT, status);
+ if (dma_status) {
+ int i;
+
+ for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+ if (dma_status & (1 << i))
+ usba_dma_irq(udc, &usba_ep[i]);
+ }
+
+ ep_status = USBA_BFEXT(EPT_INT, status);
+ if (ep_status) {
+ int i;
+
+ for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+ if (ep_status & (1 << i)) {
+ if (ep_is_control(&usba_ep[i]))
+ usba_control_irq(udc, &usba_ep[i]);
+ else
+ usba_ep_irq(udc, &usba_ep[i]);
+ }
+ }
+
+ if (status & USBA_END_OF_RESET) {
+ struct usba_ep *ep0;
+
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+ reset_all_endpoints(udc);
+
+ if (status & USBA_HIGH_SPEED) {
+ DBG(DBG_BUS, "High-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_HIGH;
+ } else {
+ DBG(DBG_BUS, "Full-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_FULL;
+ }
+
+ ep0 = &usba_ep[0];
+ ep0->desc = &usba_ep0_desc;
+ ep0->state = WAIT_FOR_SETUP;
+ usba_ep_writel(ep0, CFG,
+ (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+ | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+ usba_ep_writel(ep0, CTL_ENB,
+ USBA_EPT_ENABLE | USBA_RX_SETUP);
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1)
+ | USBA_DET_SUSPEND
+ | USBA_END_OF_RESUME));
+
+ if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+ dev_warn(&udc->pdev->dev,
+ "WARNING: EP0 configuration is invalid!\n");
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ int vbus;
+
+ /* debounce */
+ udelay(10);
+
+ spin_lock(&udc->lock);
+
+ /* May happen if Vbus pin toggles during probe() */
+ if (!udc->driver)
+ goto out;
+
+ vbus = gpio_get_value(udc->vbus_pin);
+ if (vbus != udc->vbus_prev) {
+ if (vbus) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ } else {
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ usba_writel(udc, CTRL, 0);
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ udc->vbus_prev = vbus;
+ }
+
+out:
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+ int ret;
+
+ if (!udc->pdev)
+ return -ENODEV;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->driver) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EBUSY;
+ }
+
+ udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ clk_enable(udc->pclk);
+ clk_enable(udc->hclk);
+
+ ret = driver->bind(&udc->gadget);
+ if (ret) {
+ DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+ driver->driver.name, ret);
+ goto err_driver_bind;
+ }
+
+ DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+ udc->vbus_prev = 0;
+ if (udc->vbus_pin != -1)
+ enable_irq(gpio_to_irq(udc->vbus_pin));
+
+ /* If Vbus is present, enable the controller and wait for reset */
+ spin_lock_irqsave(&udc->lock, flags);
+ if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+
+err_driver_bind:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+
+ if (!udc->pdev)
+ return -ENODEV;
+ if (driver != udc->driver)
+ return -EINVAL;
+
+ if (udc->vbus_pin != -1)
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* This will also disable the DP pullup */
+ usba_writel(udc, CTRL, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ clk_disable(udc->hclk);
+ clk_disable(udc->pclk);
+
+ DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+ struct usba_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *regs, *fifo;
+ struct clk *pclk, *hclk;
+ struct usba_udc *udc = &the_udc;
+ int irq, ret, i;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+ fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+ if (!regs || !fifo)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+ hclk = clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(hclk)) {
+ ret = PTR_ERR(hclk);
+ goto err_get_hclk;
+ }
+
+ udc->pdev = pdev;
+ udc->pclk = pclk;
+ udc->hclk = hclk;
+ udc->vbus_pin = -1;
+
+ ret = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+ goto err_map_regs;
+ }
+ dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+ (unsigned long)regs->start, udc->regs);
+ udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+ if (!udc->fifo) {
+ dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+ goto err_map_fifo;
+ }
+ dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+ (unsigned long)fifo->start, udc->fifo);
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ platform_set_drvdata(pdev, udc);
+
+ /* Make sure we start from a clean slate */
+ clk_enable(pclk);
+ usba_writel(udc, CTRL, 0);
+ clk_disable(pclk);
+
+ INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+ usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+ usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+ usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+ struct usba_ep *ep = &usba_ep[i];
+
+ ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+ ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+ ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ }
+
+ ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+ irq, ret);
+ goto err_request_irq;
+ }
+ udc->irq = irq;
+
+ ret = device_add(&udc->gadget.dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+ goto err_device_add;
+ }
+
+ if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+ if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+ udc->vbus_pin = pdata->vbus_pin;
+
+ ret = request_irq(gpio_to_irq(udc->vbus_pin),
+ usba_vbus_irq, 0,
+ "atmel_usba_udc", udc);
+ if (ret) {
+ gpio_free(udc->vbus_pin);
+ udc->vbus_pin = -1;
+ dev_warn(&udc->pdev->dev,
+ "failed to request vbus irq; "
+ "assuming always on\n");
+ } else {
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+ }
+ }
+ }
+
+ usba_init_debugfs(udc);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+ return 0;
+
+err_device_add:
+ free_irq(irq, udc);
+err_request_irq:
+ iounmap(udc->fifo);
+err_map_fifo:
+ iounmap(udc->regs);
+err_map_regs:
+ clk_put(hclk);
+err_get_hclk:
+ clk_put(pclk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+ struct usba_udc *udc;
+ int i;
+
+ udc = platform_get_drvdata(pdev);
+
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_cleanup_debugfs(&usba_ep[i]);
+ usba_cleanup_debugfs(udc);
+
+ if (udc->vbus_pin != -1)
+ gpio_free(udc->vbus_pin);
+
+ free_irq(udc->irq, udc);
+ iounmap(udc->fifo);
+ iounmap(udc->regs);
+ clk_put(udc->hclk);
+ clk_put(udc->pclk);
+
+ device_unregister(&udc->gadget.dev);
+
+ return 0;
+}
+
+static struct platform_driver udc_driver = {
+ .remove = __exit_p(usba_udc_remove),
+ .driver = {
+ .name = "atmel_usba_udc",
+ },
+};
+
+static int __init udc_init(void)
+{
+ return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 00000000000..a68304e31a6
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL 0x0000
+#define USBA_FNUM 0x0004
+#define USBA_INT_ENB 0x0010
+#define USBA_INT_STA 0x0014
+#define USBA_INT_CLR 0x0018
+#define USBA_EPT_RST 0x001c
+#define USBA_TST 0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG 0x0000
+#define USBA_EPT_CTL_ENB 0x0004
+#define USBA_EPT_CTL_DIS 0x0008
+#define USBA_EPT_CTL 0x000c
+#define USBA_EPT_SET_STA 0x0014
+#define USBA_EPT_CLR_STA 0x0018
+#define USBA_EPT_STA 0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC 0x0000
+#define USBA_DMA_ADDRESS 0x0004
+#define USBA_DMA_CONTROL 0x0008
+#define USBA_DMA_STATUS 0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET 0
+#define USBA_DEV_ADDR_SIZE 7
+#define USBA_FADDR_EN (1 << 7)
+#define USBA_EN_USBA (1 << 8)
+#define USBA_DETACH (1 << 9)
+#define USBA_REMOTE_WAKE_UP (1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET 0
+#define USBA_MICRO_FRAME_NUM_SIZE 3
+#define USBA_FRAME_NUMBER_OFFSET 3
+#define USBA_FRAME_NUMBER_SIZE 11
+#define USBA_FRAME_NUM_ERROR (1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED (1 << 0)
+#define USBA_DET_SUSPEND (1 << 1)
+#define USBA_MICRO_SOF (1 << 2)
+#define USBA_SOF (1 << 3)
+#define USBA_END_OF_RESET (1 << 4)
+#define USBA_WAKE_UP (1 << 5)
+#define USBA_END_OF_RESUME (1 << 6)
+#define USBA_UPSTREAM_RESUME (1 << 7)
+#define USBA_EPT_INT_OFFSET 8
+#define USBA_EPT_INT_SIZE 16
+#define USBA_DMA_INT_OFFSET 24
+#define USBA_DMA_INT_SIZE 8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET 0
+#define USBA_RST_SIZE 16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET 0
+#define USBA_SPEED_CFG_SIZE 2
+#define USBA_TST_J_MODE (1 << 2)
+#define USBA_TST_K_MODE (1 << 3)
+#define USBA_TST_PKT_MODE (1 << 4)
+#define USBA_OPMODE2 (1 << 5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET 0
+#define USBA_EPT_SIZE_SIZE 3
+#define USBA_EPT_DIR_IN (1 << 3)
+#define USBA_EPT_TYPE_OFFSET 4
+#define USBA_EPT_TYPE_SIZE 2
+#define USBA_BK_NUMBER_OFFSET 6
+#define USBA_BK_NUMBER_SIZE 2
+#define USBA_NB_TRANS_OFFSET 8
+#define USBA_NB_TRANS_SIZE 2
+#define USBA_EPT_MAPPED (1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE (1 << 0)
+#define USBA_AUTO_VALID (1 << 1)
+#define USBA_INTDIS_DMA (1 << 3)
+#define USBA_NYET_DIS (1 << 4)
+#define USBA_DATAX_RX (1 << 6)
+#define USBA_MDATA_RX (1 << 7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE (1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL (1 << 5)
+#define USBA_TOGGLE_CLR (1 << 6)
+#define USBA_TOGGLE_SEQ_OFFSET 6
+#define USBA_TOGGLE_SEQ_SIZE 2
+#define USBA_ERR_OVFLW (1 << 8)
+#define USBA_RX_BK_RDY (1 << 9)
+#define USBA_KILL_BANK (1 << 9)
+#define USBA_TX_COMPLETE (1 << 10)
+#define USBA_TX_PK_RDY (1 << 11)
+#define USBA_ISO_ERR_TRANS (1 << 11)
+#define USBA_RX_SETUP (1 << 12)
+#define USBA_ISO_ERR_FLOW (1 << 12)
+#define USBA_STALL_SENT (1 << 13)
+#define USBA_ISO_ERR_CRC (1 << 13)
+#define USBA_ISO_ERR_NBTRANS (1 << 13)
+#define USBA_NAK_IN (1 << 14)
+#define USBA_ISO_ERR_FLUSH (1 << 14)
+#define USBA_NAK_OUT (1 << 15)
+#define USBA_CURRENT_BANK_OFFSET 16
+#define USBA_CURRENT_BANK_SIZE 2
+#define USBA_BUSY_BANKS_OFFSET 18
+#define USBA_BUSY_BANKS_SIZE 2
+#define USBA_BYTE_COUNT_OFFSET 20
+#define USBA_BYTE_COUNT_SIZE 11
+#define USBA_SHORT_PACKET (1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN (1 << 0)
+#define USBA_DMA_LINK (1 << 1)
+#define USBA_DMA_END_TR_EN (1 << 2)
+#define USBA_DMA_END_BUF_EN (1 << 3)
+#define USBA_DMA_END_TR_IE (1 << 4)
+#define USBA_DMA_END_BUF_IE (1 << 5)
+#define USBA_DMA_DESC_LOAD_IE (1 << 6)
+#define USBA_DMA_BURST_LOCK (1 << 7)
+#define USBA_DMA_BUF_LEN_OFFSET 16
+#define USBA_DMA_BUF_LEN_SIZE 16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE (1 << 1)
+#define USBA_DMA_END_TR_ST (1 << 4)
+#define USBA_DMA_END_BUF_ST (1 << 5)
+#define USBA_DMA_DESC_LOAD_ST (1 << 6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL 0
+#define USBA_SPEED_CFG_FORCE_HIGH 2
+#define USBA_SPEED_CFG_FORCE_FULL 3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8 0
+#define USBA_EPT_SIZE_16 1
+#define USBA_EPT_SIZE_32 2
+#define USBA_EPT_SIZE_64 3
+#define USBA_EPT_SIZE_128 4
+#define USBA_EPT_SIZE_256 5
+#define USBA_EPT_SIZE_512 6
+#define USBA_EPT_SIZE_1024 7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL 0
+#define USBA_EPT_TYPE_ISO 1
+#define USBA_EPT_TYPE_BULK 2
+#define USBA_EPT_TYPE_INT 3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO 0
+#define USBA_BK_NUMBER_ONE 1
+#define USBA_BK_NUMBER_DOUBLE 2
+#define USBA_BK_NUMBER_TRIPLE 3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value) \
+ (((value) & ((1 << USBA_##name##_SIZE) - 1)) \
+ << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value) \
+ (((value) >> USBA_##name##_OFFSET) \
+ & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old) \
+ (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \
+ << USBA_##name##_OFFSET)) \
+ | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg) \
+ __raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg) \
+ __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg) \
+ __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x) ((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS 7
+
+#define EP0_FIFO_SIZE 64
+#define EP0_EPT_SIZE USBA_EPT_SIZE_64
+#define EP0_NR_BANKS 1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID 0
+#define CTRL_IOMEM_ID 1
+
+#ifdef DEBUG
+#define DBG_ERR 0x0001 /* report all error returns */
+#define DBG_HW 0x0002 /* debug hardware initialization */
+#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
+#define DBG_INT 0x0008 /* interrupts */
+#define DBG_BUS 0x0010 /* report changes in bus state */
+#define DBG_QUEUE 0x0020 /* debug request queue processing */
+#define DBG_FIFO 0x0040 /* debug FIFO contents */
+#define DBG_DMA 0x0080 /* debug DMA handling */
+#define DBG_REQ 0x0100 /* print out queued request length */
+#define DBG_ALL 0xffff
+#define DBG_NONE 0x0000
+
+#define DEBUG_LEVEL (DBG_ERR)
+#define DBG(level, fmt, ...) \
+ do { \
+ if ((level) & DEBUG_LEVEL) \
+ printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+ WAIT_FOR_SETUP,
+ DATA_STAGE_IN,
+ DATA_STAGE_OUT,
+ STATUS_STAGE_IN,
+ STATUS_STAGE_OUT,
+ STATUS_STAGE_ADDR,
+ STATUS_STAGE_TEST,
+};
+/*
+ EP_STATE_IDLE,
+ EP_STATE_SETUP,
+ EP_STATE_IN_DATA,
+ EP_STATE_OUT_DATA,
+ EP_STATE_SET_ADDR_STATUS,
+ EP_STATE_RX_STATUS,
+ EP_STATE_TX_STATUS,
+ EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+ dma_addr_t next;
+ dma_addr_t addr;
+ u32 ctrl;
+};
+
+struct usba_ep {
+ int state;
+ void __iomem *ep_regs;
+ void __iomem *dma_regs;
+ void __iomem *fifo;
+ struct usb_ep ep;
+ struct usba_udc *udc;
+
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+
+ u16 fifo_size;
+ u8 nr_banks;
+ u8 index;
+ unsigned int can_dma:1;
+ unsigned int can_isoc:1;
+ unsigned int is_isoc:1;
+ unsigned int is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ u32 last_dma_status;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_queue;
+ struct dentry *debugfs_dma_status;
+ struct dentry *debugfs_state;
+#endif
+};
+
+struct usba_request {
+ struct usb_request req;
+ struct list_head queue;
+
+ u32 ctrl;
+
+ unsigned int submitted:1;
+ unsigned int last_transaction:1;
+ unsigned int using_dma:1;
+ unsigned int mapped:1;
+};
+
+struct usba_udc {
+ /* Protect hw registers from concurrent modifications */
+ spinlock_t lock;
+
+ void __iomem *regs;
+ void __iomem *fifo;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *pdev;
+ int irq;
+ int vbus_pin;
+ struct clk *pclk;
+ struct clk *hclk;
+
+ u16 devstatus;
+
+ u16 test_mode;
+ int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+ return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep) ((ep)->index == 0)
+#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index c6760aee1e5..a4e54b2743f 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/**
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index d008d1360a7..9db2482bdfa 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -46,7 +46,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
+ int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
+ rc = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (rc) {
+ kfree(urbp);
+ goto done;
+ }
if (!dum->udev) {
dum->udev = urb->dev;
@@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
+ done:
+ spin_unlock_irqrestore(&dum->lock, flags);
+ return rc;
}
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct dummy *dum;
unsigned long flags;
+ int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
- if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+ !list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
-}
-static void maybe_set_status (struct urb *urb, int status)
-{
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
+ spin_unlock_irqrestore (&dum->lock, flags);
+ return rc;
}
/* transfer up to a frame's worth; caller must own lock */
static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+ int *status)
{
struct dummy_request *req;
@@ -1088,24 +1092,20 @@ top:
*
* partially filling a buffer optionally blocks queue advances
* (so completion handlers can clean up the queue) but we don't
- * need to emulate such data-in-flight. so we only show part
- * of the URB_SHORT_NOT_OK effect: completion status.
+ * need to emulate such data-in-flight.
*/
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
- maybe_set_status (urb, 0);
+ *status = 0;
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
- maybe_set_status (urb, -EOVERFLOW);
+ *status = -EOVERFLOW;
else
- maybe_set_status (urb,
- (urb->transfer_flags
- & URB_SHORT_NOT_OK)
- ? -EREMOTEIO : 0);
+ *status = 0;
} else if (!to_host) {
- maybe_set_status (urb, 0);
+ *status = 0;
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@@ -1119,9 +1119,8 @@ top:
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
- & URB_ZERO_PACKET)) {
- maybe_set_status (urb, 0);
- }
+ & URB_ZERO_PACKET))
+ *status = 0;
}
/* device side completion --> continuable */
@@ -1137,7 +1136,7 @@ top:
}
/* host side completion --> terminate */
- if (urb->status != -EINPROGRESS)
+ if (*status != -EINPROGRESS)
break;
/* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@ restart:
u8 address;
struct dummy_ep *ep = NULL;
int type;
+ int status = -EINPROGRESS;
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
- /* likely it was just unlinked */
+ if (urb->unlinked)
goto return_urb;
- } else if (dum->rh_state != DUMMY_RH_RUNNING)
+ else if (dum->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
@@ -1274,7 +1273,7 @@ restart:
dev_dbg (dummy_dev(dum),
"no ep configured for urb %p\n",
urb);
- maybe_set_status (urb, -EPROTO);
+ status = -EPROTO;
goto return_urb;
}
@@ -1289,7 +1288,7 @@ restart:
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
ep->ep.name, urb);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
goto return_urb;
}
/* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@ restart:
w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
- maybe_set_status (urb, -EOVERFLOW);
+ status = -EOVERFLOW;
goto return_urb;
}
@@ -1337,7 +1336,7 @@ restart:
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
- maybe_set_status (urb, 0);
+ status = 0;
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
@@ -1364,7 +1363,7 @@ restart:
if (value == 0) {
dum->devstatus |=
(1 << w_value);
- maybe_set_status (urb, 0);
+ status = 0;
}
} else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@ restart:
}
ep2->halted = 1;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@ restart:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
break;
default:
value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@ restart:
}
ep2->halted = 0;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@ restart:
urb->actual_length = min (2,
urb->transfer_buffer_length);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
}
@@ -1465,7 +1464,7 @@ restart:
dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
urb->actual_length = 0;
}
@@ -1482,7 +1481,7 @@ restart:
* report random errors, to debug drivers.
*/
limit = max (limit, periodic_bytes (dum, ep));
- maybe_set_status (urb, -ENOSYS);
+ status = -ENOSYS;
break;
case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@ restart:
default:
treat_control_like_bulk:
ep->last_io = jiffies;
- total = transfer (dum, urb, ep, limit);
+ total = transfer(dum, urb, ep, limit, &status);
break;
}
/* incomplete transfer? */
- if (urb->status == -EINPROGRESS)
+ if (status == -EINPROGRESS)
continue;
return_urb:
- urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
+ usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
- usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+ usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
spin_lock (&dum->lock);
goto restart;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 3aa46cfa66b..f9d07108bc3 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
#include <linux/string.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f70055473a0..9e732bff9df 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -19,40 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* #define VERBOSE_DEBUG */
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
#define qlen(gadget) \
(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY qmult
-
static inline int BITRATE(struct usb_gadget *g)
{
return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
}
#else /* full speed (low speed doesn't do bulk) */
+
+#define qmult 1
+
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DEBUG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
};
#endif
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
}
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = {
* complications: class descriptors, and an altsetting.
*/
static int
-config_buf (enum usb_device_speed speed,
- u8 *buf, u8 type,
- unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
{
int len;
const struct usb_config_descriptor *config;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (speed == USB_SPEED_HIGH);
+ int hs = 0;
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(g)) {
+ hs = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define which_fn(t) (fs_ ## t ## _function)
-#endif
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
if (number)
eth_reset_config (dev);
usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
+ gadget_is_otg(dev->gadget) ? 8 : 100);
} else {
char *speed;
unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- value = config_buf (gadget->speed, req->buf,
+ value = config_buf(gadget, req->buf,
wValue >> 8,
wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (value >= 0)
value = min (wLength, (u16) value);
break;
@@ -1585,12 +1553,12 @@ done_set_intf:
&& rndis_control_intf.bInterfaceNumber
== wIndex) {
u8 *buf;
+ u32 n;
/* return the result */
- buf = rndis_get_next_response (dev->rndis_config,
- &value);
+ buf = rndis_get_next_response(dev->rndis_config, &n);
if (buf) {
- memcpy (req->buf, buf, value);
+ memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
}
@@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
spin_lock_irqsave(&dev->req_lock, flags);
+ /*
+ * this freelist can be empty if an interrupt triggered disconnect()
+ * and reconfigured the gadget (shutting down this queue) after the
+ * network stack decided to xmit but before we got the spinlock.
+ */
+ if (list_empty(&dev->tx_reqs)) {
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ return 1;
+ }
+
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
+
+ /* temporarily stop TX queue when the freelist empties */
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
req->length = length;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
- req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
- ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
- : 0;
-#endif
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+ : 0;
retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
}
if (rndis_active(dev)) {
- rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3, 0);
+ rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
@@ -2443,26 +2421,28 @@ autoconf_fail:
if (rndis)
device_desc.bNumConfigurations = 2;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (rndis)
- dev_qualifier.bNumConfigurations = 2;
- else if (!cdc)
- dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+ if (gadget_is_dualspeed(gadget)) {
+ if (rndis)
+ dev_qualifier.bNumConfigurations = 2;
+ else if (!cdc)
+ dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
- /* assumes ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (status_ep)
- hs_status_desc.bEndpointAddress =
- fs_status_desc.bEndpointAddress;
+ if (status_ep)
+ hs_status_desc.bEndpointAddress =
+ fs_status_desc.bEndpointAddress;
#endif
-#endif /* DUALSPEED */
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@ fail0:
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats, &dev->cdc_filter))
goto fail0;
- if (rndis_set_param_vendor (dev->rndis_config, vendorID,
- manufacturer))
+ if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+ manufacturer))
goto fail0;
- if (rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3,
- 0))
+ if (rndis_set_param_medium(dev->rndis_config,
+ NDIS_MEDIUM_802_3, 0))
goto fail0;
INFO (dev, "RNDIS ready\n");
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 965ad7bec7b..73726c570a6 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
*/
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/bitops.h>
#include <linux/blkdev.h>
-#include <linux/compiler.h>
#include <linux/completion.h>
#include <linux/dcache.h>
#include <linux/delay.h>
@@ -235,18 +229,10 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -254,7 +240,7 @@
#include <linux/utsname.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -263,7 +249,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "28 November 2005"
+#define DRIVER_VERSION "7 August 2007"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/
-#define xprintk(f,level,fmt,args...) \
- dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
- dev_printk(level , &(l)->dev , fmt , ## args)
-
#ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
- xprintk(fsg , KERN_DEBUG , fmt , ## args)
#define LDBG(lun,fmt,args...) \
- yprintk(lun , KERN_DEBUG , fmt , ## args)
+ dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else
-#define DBG(fsg,fmt,args...) \
- do { } while (0)
#define LDBG(lun,fmt,args...) \
do { } while (0)
#define MDBG(fmt,args...) \
do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
#undef DUMP_MSGS
#endif /* DEBUG */
-#ifdef VERBOSE
-#define VDBG DBG
+#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
#else
-#define VDBG(fsg,fmt,args...) \
- do { } while (0)
#define VLDBG(lun,fmt,args...) \
do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
-#define ERROR(fsg,fmt,args...) \
- xprintk(fsg , KERN_ERR , fmt , ## args)
#define LERROR(lun,fmt,args...) \
- yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
- xprintk(fsg , KERN_WARNING , fmt , ## args)
+ dev_err(&(lun)->dev , fmt , ## args)
#define LWARN(lun,fmt,args...) \
- yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
- xprintk(fsg , KERN_INFO , fmt , ## args)
+ dev_warn(&(lun)->dev , fmt , ## args)
#define LINFO(lun,fmt,args...) \
- yprintk(lun , KERN_INFO , fmt , ## args)
+ dev_info(&(lun)->dev , fmt , ## args)
#define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
+
/*-------------------------------------------------------------------------*/
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct {
char *file[MAX_LUNS];
int ro[MAX_LUNS];
- int num_filenames;
- int num_ros;
+ unsigned int num_filenames;
+ unsigned int num_ros;
unsigned int nluns;
int removable;
@@ -578,7 +555,7 @@ struct lun {
#define backing_file_is_open(curlun) ((curlun)->filp != NULL)
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
{
return container_of(dev, struct lun, dev);
}
@@ -711,13 +688,13 @@ struct fsg_dev {
typedef void (*fsg_routine_t)(struct fsg_dev *);
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
{
return (fsg->state > FSG_STATE_IDLE);
}
/* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
struct fsg_buffhd *bh, unsigned int length)
{
unsigned int rem;
@@ -743,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg);
static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{
- unsigned int start, num, i;
- char line[52], *p;
-
- if (length >= 512)
- return;
- DBG(fsg, "%s, length %u:\n", label, length);
-
- start = 0;
- while (length > 0) {
- num = min(length, 16u);
- p = line;
- for (i = 0; i < num; ++i) {
- if (i == 8)
- *p++ = ' ';
- sprintf(p, " %02x", buf[i]);
- p += 3;
- }
- *p = 0;
- printk(KERN_DEBUG "%6x: %s\n", start, line);
- buf += num;
- start += num;
- length -= num;
+ if (length < 512) {
+ DBG(fsg, "%s, length %u:\n", label, length);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, length, 0);
}
}
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
{}
#else
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{}
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
- int i;
- char cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
- for (i = 0; i < fsg->cmnd_size; ++i)
- sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
- VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+ 16, 1, fsg->cmnd, fsg->cmnd_size, 0);
}
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
#endif /* DUMP_MSGS */
@@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Routines for unaligned data access */
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
{
return ((u16) buf[0] << 8) | ((u16) buf[1]);
}
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
{
return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
((u32) buf[2] << 8) | ((u32) buf[3]);
}
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
{
buf[0] = val >> 8;
buf[1] = val;
}
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
#define FS_FUNCTION_PRE_EP_ENTRIES 2
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
#define HS_FUNCTION_PRE_EP_ENTRIES 2
/* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs) fs
-
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+ struct usb_endpoint_descriptor *hs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
/* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@ static struct usb_gadget_strings stringtab = {
static int populate_config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
-#ifdef CONFIG_USB_GADGET_DUALSPEED
enum usb_device_speed speed = gadget->speed;
-#endif
int len;
const struct usb_descriptor_header **function;
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
- if (speed == USB_SPEED_HIGH)
+ if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
function = hs_function;
else
-#endif
function = fs_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
goto get_config;
-#endif
case USB_DT_CONFIG:
VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- get_config:
-#endif
+get_config:
value = populate_config_buf(fsg->gadget,
req->buf,
w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
}
/* Wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
/* Wait for the next buffer to be free */
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
}
/* Otherwise wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available for data or status */
bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
fsg->phase_error = 0;
fsg->short_packet_received = 0;
@@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Is the CBW meaningful? */
if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
- cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
smp_rmb();
rc = received_cbw(fsg, bh);
bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next command to arrive */
while (fsg->cbbuf_cmnd_size == 0) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Is the previous status interrupt request still busy?
* The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
return sprintf(buf, "%d\n", curlun->ro);
}
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
- buf, PAGE_SIZE - 1);
+ p = d_path(curlun->filp->f_path.dentry,
+ curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
else {
@@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
}
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
return rc;
}
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Find out how many LUNs there should be */
i = mod_data.nluns;
if (i == 0)
- i = max(mod_data.num_filenames, 1);
+ i = max(mod_data.num_filenames, 1u);
if (i > MAX_LUNS) {
ERROR(fsg, "invalid number of LUNs: %d\n", i);
rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
intf_desc.bInterfaceProtocol = mod_data.transport_type;
fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ if (gadget_is_dualspeed(gadget)) {
+ hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
- /* Assume ep0 uses the same maxpacket value for both speeds */
- dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+ /* Assume ep0 uses the same maxpacket value for both speeds */
+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
- /* Assume that all endpoint addresses are the same for both speeds */
- hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
- hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
- hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+ /* Assume endpoint addresses are the same for both speeds */
+ hs_bulk_in_desc.bEndpointAddress =
+ fs_bulk_in_desc.bEndpointAddress;
+ hs_bulk_out_desc.bEndpointAddress =
+ fs_bulk_out_desc.bEndpointAddress;
+ hs_intr_in_desc.bEndpointAddress =
+ fs_intr_in_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget))
otg_desc.bmAttributes |= USB_OTG_HNP;
- }
rc = -ENOMEM;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index d57bcfbc08a..9bb7f64a85c 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -35,7 +35,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
*/
static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
-#ifdef CONFIG_USB_OTG
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
-
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
-#endif
return -ENOTSUPP;
}
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
| USB_TYPE_STANDARD)) {
/* Note: The driver has not include OTG support yet.
* This will be set when OTG support is added */
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
break;
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
else if (setup->bRequest ==
USB_DEVICE_A_ALT_HNP_SUPPORT)
udc->gadget.a_alt_hnp_support = 1;
+ else
+ break;
rc = 0;
} else
break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
-#ifdef CONFIG_USB_OTG
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 1c5aa49d743..0689189550b 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -18,17 +18,11 @@
* http://www.usb.org/developers/devclass_docs/midi10.pdf
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <sound/driver.h>
#include <sound/core.h>
@@ -36,7 +30,7 @@
#include <sound/rawmidi.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
@@ -139,30 +133,16 @@ struct gmidi_device {
static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
return len;
}
-static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
* Receives a chunk of MIDI data.
*/
static void gmidi_read_data(struct usb_ep *ep, int cable,
- uint8_t* data, int length)
+ uint8_t *data, int length)
{
struct gmidi_device *dev = ep->driver_data;
/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
{
int err = 0;
struct usb_request *req;
- struct usb_ep* ep;
+ struct usb_ep *ep;
unsigned i;
err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO(dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
{
struct gmidi_device *dev = get_gadget_data(gadget);
- struct snd_card* card;
+ struct snd_card *card;
DBG(dev, "unbind\n");
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
return 0;
}
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
uint8_t p1, uint8_t p2, uint8_t p3)
{
unsigned length = req->length;
+ u8 *buf = (u8 *)req->buf + length;
- uint8_t* buf = (uint8_t*)req->buf + length;
buf[0] = p0;
buf[1] = p1;
buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
/*
* Converts MIDI commands to USB MIDI packets.
*/
-static void gmidi_transmit_byte(struct usb_request* req,
- struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+ struct gmidi_in_port *port, uint8_t b)
{
uint8_t p0 = port->cable;
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
}
}
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
{
- struct usb_ep* ep = dev->in_ep;
- struct gmidi_in_port* port = &dev->in_port;
+ struct usb_ep *ep = dev->in_ep;
+ struct gmidi_in_port *port = &dev->in_port;
if (!ep) {
return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
static void gmidi_in_tasklet(unsigned long data)
{
- struct gmidi_device* dev = (struct gmidi_device*)data;
+ struct gmidi_device *dev = (struct gmidi_device *)data;
gmidi_transmit(dev, NULL);
}
static int gmidi_in_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_open\n");
dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
static int gmidi_in_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_in_close\n");
return 0;
}
static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_trigger %d\n", up);
dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
static int gmidi_out_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_open\n");
dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
static int gmidi_out_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_out_close\n");
return 0;
}
static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_trigger %d\n", up);
if (up) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 349b8166f34..2ec9d196a8c 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -37,7 +37,7 @@
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 173004f60fe..47ef8bd58a0 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,8 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
-// #define VERBOSE /* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
#include <linux/init.h>
#include <linux/module.h>
@@ -38,7 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
@@ -253,7 +252,7 @@ static const char *CHIP;
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
unsigned power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (dev->gadget->speed == USB_SPEED_HIGH)
+
+ if (gadget_is_dualspeed(dev->gadget)
+ && (dev->gadget->speed
+ == USB_SPEED_HIGH))
power = dev->hs_config->bMaxPower;
else
-#endif
power = dev->config->bMaxPower;
usb_gadget_vbus_draw(dev->gadget, 2 * power);
}
@@ -1355,24 +1355,21 @@ static int
config_buf (struct dev_data *dev, u8 type, unsigned index)
{
int len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs;
-#endif
+ int hs = 0;
/* only one configuration */
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs = (dev->gadget->speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(dev->gadget)) {
+ hs = (dev->gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs) {
dev->req->buf = dev->hs_config;
len = le16_to_cpu(dev->hs_config->wTotalLength);
- } else
-#endif
- {
+ } else {
dev->req->buf = dev->config;
len = le16_to_cpu(dev->config->wTotalLength);
}
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH
+ && dev->hs_config == NULL) {
spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
dev->state = STATE_DEV_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
// user mode expected to disable endpoints
} else {
u8 config, power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH) {
+
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue;
power = dev->hs_config->bMaxPower;
- } else
-#endif
- {
+ } else {
config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index b3fe197e1ee..1ecfd6366b9 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -50,7 +50,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
* Memory map
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 4b27d12f049..ebc5536aa27 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "m66592-udc.h"
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c3d364ecd4f..d5d473f8144 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -62,7 +62,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 9b0f0925ddd..87c4f50dfb6 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
udc->gadget.dev.parent->power.power_state = PMSG_ON;
udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
static void pullup_disable(struct omap_udc *udc)
{
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
{
u16 devstat;
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
return;
if (OTG_CTRL_REG & OTG_ID)
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 90d0d086b9b..3173b39f0bf 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -56,7 +56,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/mach/udc_pxa2xx.h>
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 0be80c635c4..e3e90f8a75e 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -42,7 +42,7 @@
#include <linux/seq_file.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ce4d2e09633..f5738eb8e76 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,34 +17,15 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -89,30 +70,29 @@
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
+
/* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
static int debug = 1;
+#else
+#define debug 0
+#endif
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
#define gs_debug_level(level, format, arg...) \
do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
-#else
-
-#define gs_debug(format, arg...) \
- do { } while(0)
-#define gs_debug_level(level, format, arg...) \
- do { } while(0)
-
-#endif /* GS_DEBUG */
/* Thanks to NetChip Technologies for donating this product ID.
*
@@ -147,10 +127,10 @@ struct gs_req_entry {
/* the port structure holds info for each port, one for each minor number */
struct gs_port {
- struct gs_dev *port_dev; /* pointer to device struct */
+ struct gs_dev *port_dev; /* pointer to device struct */
struct tty_struct *port_tty; /* pointer to tty struct */
spinlock_t port_lock;
- int port_num;
+ int port_num;
int port_open_count;
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
/* tty driver */
static int gs_open(struct tty_struct *tty, struct file *file);
static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty,
+static int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
static void gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
};
static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
- .bLength = sizeof(gs_call_mgmt_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
- .bmCapabilities = 0,
- .bDataInterface = 1, /* index of data interface */
+ .bLength = sizeof(gs_call_mgmt_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
+ .bmCapabilities = 0,
+ .bDataInterface = 1, /* index of data interface */
};
static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
- .bLength = sizeof(gs_acm_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0,
+ .bLength = sizeof(gs_acm_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
+ .bmCapabilities = 0,
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of data interface */
};
-
+
static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
NULL,
};
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
/* Module */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
-#ifdef GS_DEBUG
+#ifdef DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
return;
}
- gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+ gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+ port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
len = gs_send_packet(dev, req->buf, ep->maxpacket);
if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+ gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+ "0x%2.2x 0x%2.2x ...\n", len,
+ *((unsigned char *)req->buf),
+ *((unsigned char *)req->buf+1),
+ *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
switch(req->status) {
case 0:
- /* normal completion */
+ /* normal completion */
gs_recv_packet(dev, req->buf, req->actual);
requeue:
req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- gs_qualifier_desc.bDeviceClass = use_acm
- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
- /* assume ep0 uses the same packet size for both speeds */
- gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
- /* assume endpoints are dual-speed */
- gs_highspeed_notify_desc.bEndpointAddress =
- gs_fullspeed_notify_desc.bEndpointAddress;
- gs_highspeed_in_desc.bEndpointAddress =
- gs_fullspeed_in_desc.bEndpointAddress;
- gs_highspeed_out_desc.bEndpointAddress =
- gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ if (gadget_is_dualspeed(gadget)) {
+ gs_qualifier_desc.bDeviceClass = use_acm
+ ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+ /* assume ep0 uses the same packet size for both speeds */
+ gs_qualifier_desc.bMaxPacketSize0 =
+ gs_device_desc.bMaxPacketSize0;
+ /* assume endpoints are dual-speed */
+ gs_highspeed_notify_desc.bEndpointAddress =
+ gs_fullspeed_notify_desc.bEndpointAddress;
+ gs_highspeed_in_desc.bEndpointAddress =
+ gs_fullspeed_in_desc.bEndpointAddress;
+ gs_highspeed_out_desc.bEndpointAddress =
+ gs_fullspeed_out_desc.bEndpointAddress;
+ }
usb_gadget_set_selfpowered(gadget);
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
dev->dev_ctrl_req = NULL;
}
gs_free_ports(dev);
+ if (dev->dev_notify_ep)
+ usb_ep_disable(dev->dev_notify_ep);
+ if (dev->dev_in_ep)
+ usb_ep_disable(dev->dev_in_ep);
+ if (dev->dev_out_ep)
+ usb_ep_disable(dev->dev_out_ep);
kfree(dev);
set_gadget_data(gadget, NULL);
}
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
memcpy(req->buf, &gs_device_desc, ret);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
ret = min(wLength,
(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- ret = gs_build_config_buf(req->buf, gadget->speed,
+ ret = gs_build_config_buf(req->buf, gadget,
wValue >> 8, wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (ret >= 0)
ret = min(wLength, (u16)ret);
break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
if (EP_NOTIFY_NAME
&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_notify_desc,
&gs_fullspeed_notify_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_IN_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_in_desc,
+ ep_desc = choose_ep_desc(gadget,
+ &gs_highspeed_in_desc,
&gs_fullspeed_in_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
@@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_out_desc,
&gs_fullspeed_out_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
* Builds the config descriptors in the given buffer and returns the
* length, or a negative error number.
*/
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg)
{
int len;
- int high_speed;
+ int high_speed = 0;
const struct usb_config_descriptor *config_desc;
const struct usb_descriptor_header **function;
@@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
return -EINVAL;
/* other speed switches high and full speed */
- high_speed = (speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- high_speed = !high_speed;
+ if (gadget_is_dualspeed(g)) {
+ high_speed = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ high_speed = !high_speed;
+ }
if (use_acm) {
config_desc = &gs_acm_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_acm_highspeed_function,
- gs_acm_fullspeed_function);
+ function = high_speed
+ ? gs_acm_highspeed_function
+ : gs_acm_fullspeed_function;
} else {
config_desc = &gs_bulk_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_bulk_highspeed_function,
- gs_bulk_fullspeed_function);
+ function = high_speed
+ ? gs_bulk_highspeed_function
+ : gs_bulk_fullspeed_function;
}
/* for now, don't advertise srp-only devices */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 3459ea6c6c0..878e428a0ec 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index fcfe869acb9..fcde5d9c87d 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1,38 +1,22 @@
/*
* zero.c -- Gadget Zero, for USB development
*
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
* All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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
*/
@@ -57,40 +41,28 @@
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
* driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions? To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "St Patrick's Day 2004"
+#define DRIVER_VERSION "Lughnasadh, 2007"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
struct timer_list resume;
};
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
};
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
-static char manufacturer [50];
-static char serial [40];
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
int is_source_sink;
int len;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+ int hs = 0;
/* two configurations will always be index 0 and index 1 */
if (index > 1)
return -EINVAL;
is_source_sink = loopdefault ? (index == 1) : (index == 0);
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(gadget)) {
+ hs = (gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs)
function = is_source_sink
? hs_source_sink_function
: hs_loopback_function;
else
-#endif
function = is_source_sink
? fs_source_sink_function
: fs_loopback_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/*-------------------------------------------------------------------------*/
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic. The network
+ * link (g_ether) is probably the best option for that.
+ */
+
/* optionally require specific source/sink data patterns */
static int
@@ -534,12 +505,7 @@ check_read_data (
return 0;
}
-static void
-reinit_write_data (
- struct zero_dev *dev,
- struct usb_ep *ep,
- struct usb_request *req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
{
unsigned i;
u8 *buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
check_read_data (dev, ep, req);
memset (req->buf, 0x55, req->length);
} else
- reinit_write_data (dev, ep, req);
+ reinit_write_data(ep, req);
break;
/* this endpoint is normally active while we're configured */
- case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
int status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
req->complete = source_sink_complete;
if (strcmp (ep->name, EP_IN_NAME) == 0)
- reinit_write_data (ep->driver_data, ep, req);
+ reinit_write_data(ep, req);
else
memset (req->buf, 0x55, req->length);
- status = usb_ep_queue (ep, req, gfp_flags);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
return req;
}
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep(ep, gfp_flags)
- != NULL) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep(ep, gfp_flags)
- != NULL) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/
- case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req (ep, req);
@@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
* code can do, perhaps by disallowing more than one configuration or
* by limiting configuration choices (like the pxa2xx).
*/
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
@@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100 (gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO (dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
zero_reset_config (dev);
switch (number) {
case CONFIG_SOURCE_SINK:
- result = set_source_sink_config (dev, gfp_flags);
+ result = set_source_sink_config(dev);
break;
case CONFIG_LOOPBACK:
- result = set_loopback_config (dev, gfp_flags);
+ result = set_loopback_config(dev);
break;
default:
result = -EINVAL;
@@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
+ default: speed = "?"; break;
}
dev->config = number;
@@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (w_length, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (w_length, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget, req->buf,
w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
else
VDBG (dev, "HNP inactive\n");
spin_lock (&dev->lock);
- value = zero_set_config (dev, w_value, GFP_ATOMIC);
+ value = zero_set_config(dev, w_value);
spin_unlock (&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* use this "reset the config" shortcut.
*/
zero_reset_config (dev);
- zero_set_config (dev, config, GFP_ATOMIC);
+ zero_set_config(dev, config);
value = 0;
}
spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
}
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
-
+
ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- /* assume ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ if (gadget_is_dualspeed(gadget)) {
+ /* assume ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
.suspend = zero_suspend,
.resume = zero_resume,
- .driver = {
+ .driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
static int __init init (void)
{
- /* a real value would likely come through some id prom
- * or module option. this one takes at least two packets.
- */
- strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
return usb_gadget_register_driver (&zero_driver);
}
module_init (init);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 565d6ef4c4c..c978d622fa8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
+config USB_OHCI_HCD_SSB
+ bool "OHCI support for Broadcom SSB OHCI core"
+ depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+ default n
+ ---help---
+ Support for the Sonics Silicon Backplane (SSB) attached
+ Broadcom USB OHCI core.
+
+ This device is present in some embedded devices with
+ Broadcom based SSB bus.
+
+ If unsure, say N.
+
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index b1d19268cb2..766ef68a0b4 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 35cdba10411..c1514442883 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
* are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
+ *
+ * Turning on the CF flag will transfer ownership of all ports
+ * from the companions to the EHCI controller. If any of the
+ * companions are in the middle of a port reset at the time, it
+ * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
+ * guarantees that no resets are in progress.
*/
+ down_write(&ehci_cf_port_reset_rwsem);
hcd->state = HC_STATE_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ up_write(&ehci_cf_port_reset_rwsem);
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
*/
static int ehci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+ return submit_async(ehci, urb, &qtd_list, mem_flags);
case PIPE_INTERRUPT:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+ return intr_submit(ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
* completions normally happen asynchronously
*/
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
+ int rc;
spin_lock_irqsave (&ehci->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
// case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a7816e392a8..ad0d4965f2f 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if (!retval)
ehci_dbg(ehci, "MWI active\n");
- ehci_port_power(ehci, 0);
-
return 0;
}
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
}
- if (ehci_is_TDI(ehci))
- ehci_reset(ehci);
+ ehci_reset(ehci);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index 4f99b0eb27b..452d4b1bc85 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 829fe649a98..03a6b2f4e6e 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
if (result)
return result;
- ehci_port_power(ehci, 0);
+ ehci_reset(ehci);
return result;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 140bfa423e0..b10f39c047e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-static void qtd_copy_status (
+static int qtd_copy_status (
struct ehci_hcd *ehci,
struct urb *urb,
size_t length,
u32 token
)
{
+ int status = -EINPROGRESS;
+
/* count IN/OUT bytes, not SETUP (even short packets) */
if (likely (QTD_PID (token) != 2))
urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */
- if (unlikely (urb->status != -EINPROGRESS))
- return;
+ if (unlikely(urb->unlinked))
+ return status;
/* force cleanup after short read; not always an error */
if (unlikely (IS_SHORT_READ (token)))
- urb->status = -EREMOTEIO;
+ status = -EREMOTEIO;
/* serious "can't proceed" faults reported by the hardware */
if (token & QTD_STS_HALT) {
if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
- urb->status = -EOVERFLOW;
+ status = -EOVERFLOW;
} else if (token & QTD_STS_MMF) {
/* fs/ls interrupt xfer missed the complete-split */
- urb->status = -EPROTO;
+ status = -EPROTO;
} else if (token & QTD_STS_DBE) {
- urb->status = (QTD_PID (token) == 1) /* IN ? */
+ status = (QTD_PID (token) == 1) /* IN ? */
? -ENOSR /* hc couldn't read data */
: -ECOMM; /* hc couldn't write data */
} else if (token & QTD_STS_XACT) {
/* timeout, bad crc, wrong PID, etc; retried */
if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else {
ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out");
- urb->status = -EPROTO;
+ status = -EPROTO;
}
/* CERR nonzero + no errors + halt --> stall */
} else if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else /* unknown */
- urb->status = -EPROTO;
+ status = -EPROTO;
ehci_vdbg (ehci,
"dev%d ep%d%s qtd token %08x --> status %d\n",
usb_pipedevice (urb->pipe),
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- token, urb->status);
+ token, status);
/* if async CSPLIT failed, try cleaning out the TT buffer */
- if (urb->status != -EPIPE
+ if (status != -EPIPE
&& urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
}
}
+
+ return status;
}
static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
__releases(ehci->lock)
__acquires(ehci->lock)
{
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
qh_put (qh);
}
- spin_lock (&urb->lock);
- urb->hcpriv = NULL;
- switch (urb->status) {
- case -EINPROGRESS: /* success */
- urb->status = 0;
- default: /* fault */
- COUNT (ehci->stats.complete);
- break;
- case -EREMOTEIO: /* fault or normal */
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- urb->status = 0;
- COUNT (ehci->stats.complete);
- break;
- case -ECONNRESET: /* canceled */
- case -ENOENT:
- COUNT (ehci->stats.unlink);
- break;
+ if (unlikely(urb->unlinked)) {
+ COUNT(ehci->stats.unlink);
+ } else {
+ if (likely(status == -EINPROGRESS))
+ status = 0;
+ COUNT(ehci->stats.complete);
}
- spin_unlock (&urb->lock);
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
__FUNCTION__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- urb->status,
+ status,
urb->actual_length, urb->transfer_buffer_length);
#endif
/* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
- usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+ usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
spin_lock (&ehci->lock);
}
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
+ int last_status = -EINPROGRESS;
int stopped;
unsigned count = 0;
int do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qtd *qtd;
struct urb *urb;
u32 token = 0;
+ int qtd_status;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
}
ehci_qtd_free (ehci, last);
last = NULL;
+ last_status = -EINPROGRESS;
}
/* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
- urb->status = -ESHUTDOWN;
+ last_status = -ESHUTDOWN;
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
- if (likely (urb->status == -EINPROGRESS))
+ if (likely(last_status == -EINPROGRESS &&
+ !urb->unlinked))
continue;
/* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
}
/* remove it from the queue */
- spin_lock (&urb->lock);
- qtd_copy_status (ehci, urb, qtd->length, token);
- do_status = (urb->status == -EREMOTEIO)
- && usb_pipecontrol (urb->pipe);
- spin_unlock (&urb->lock);
+ qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+ if (unlikely(qtd_status == -EREMOTEIO)) {
+ do_status = (!urb->unlinked &&
+ usb_pipecontrol(urb->pipe));
+ qtd_status = 0;
+ }
+ if (likely(last_status == -EINPROGRESS))
+ last_status = qtd_status;
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
ehci_qtd_free (ehci, last);
}
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
static int
submit_async (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -922,10 +921,10 @@ submit_async (
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
- int rc = 0;
+ int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
__FUNCTION__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
- qtd, ep->hcpriv);
+ qtd, urb->ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
rc = -ESHUTDOWN;
goto done;
}
+ rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(rc))
+ goto done;
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
if (unlikely(qh == NULL)) {
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
rc = -ENOMEM;
goto done;
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index e682f2342ef..80d99bce2b3 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -797,7 +797,6 @@ done:
static int intr_submit (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -805,23 +804,26 @@ static int intr_submit (
unsigned epnum;
unsigned long flags;
struct ehci_qh *qh;
- int status = 0;
+ int status;
struct list_head empty;
/* get endpoint and transfer/schedule data */
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- goto done;
+ goto done_not_linked;
}
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
/* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty);
- qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
@@ -832,13 +834,16 @@ static int intr_submit (
}
/* then queue the urb's tds to the qh */
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
done:
+ if (unlikely(status))
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
if (status)
qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@ itd_complete (
/* give urb back to the driver ... can be out-of-order */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
@@ -1988,7 +2000,7 @@ sitd_complete (
/* give urb back to the driver */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 5c851a36de7..c27417f5b9d 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb)
+ struct urb *urb, int status)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;
- urb->hcpriv = NULL;
ep->error_count = 0;
if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
urb_dbg(urb, "Finish");
+ usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
spin_lock(&isp116x->lock);
/* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
- if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length <
- urb->transfer_buffer_length)
- status = -EREMOTEIO;
- else
- status = 0;
+ status = 0;
ep->nextpid = 0;
break;
default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
}
done:
- if (status != -EINPROGRESS) {
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock(&urb->lock);
- }
- if (urb->status != -EINPROGRESS)
- finish_request(isp116x, ep, urb);
+ if (status != -EINPROGRESS || urb->unlinked)
+ finish_request(isp116x, ep, urb, status);
}
}
@@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
/*-----------------------------------------------------------------*/
static int isp116x_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
gfp_t mem_flags)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
int is_out = !usb_pipein(pipe);
int type = usb_pipetype(pipe);
int epnum = usb_pipeendpoint(pipe);
+ struct usb_host_endpoint *hep = urb->ep;
struct isp116x_ep *ep = NULL;
unsigned long flags;
int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
if (!HC_IS_RUNNING(hcd->state)) {
kfree(ep);
ret = -ENODEV;
- goto fail;
+ goto fail_not_linked;
+ }
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv)
@@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
}
- /* in case of unlink-during-submit */
- if (urb->status != -EINPROGRESS) {
- finish_request(isp116x, ep, urb);
- ret = 0;
- goto fail;
- }
urb->hcpriv = hep;
start_atl_transfers(isp116x);
fail:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ fail_not_linked:
spin_unlock_irqrestore(&isp116x->lock, flags);
return ret;
}
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
/*
Dequeue URBs.
*/
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
struct usb_host_endpoint *hep;
struct isp116x_ep *ep, *ep_act;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&isp116x->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
hep = urb->hcpriv;
- /* URB already unlinked (or never linked)? */
- if (!hep) {
- spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
- }
ep = hep->hcpriv;
WARN_ON(hep != ep->hep);
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
- finish_request(isp116x, ep, urb);
-
+ finish_request(isp116x, ep, urb, status);
+ done:
spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
+ return rc;
}
static void isp116x_endpoint_disable(struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index f61c6cdd06f..ebab5ce8f5c 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -24,7 +24,7 @@
* small: 0) header + data packets 1) just header
*/
static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
{
unsigned int pipe= urb->pipe;
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
}
#ifndef OHCI_VERBOSE_DEBUG
- if (urb->status != 0)
+ if (status != 0)
#endif
dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_flags,
urb->actual_length,
urb->transfer_buffer_length,
- urb->status);
+ status);
#ifdef OHCI_VERBOSE_DEBUG
if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_buffer_length: urb->actual_length;
for (i = 0; i < 16 && i < len; i++)
printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
- printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+ printk ("%s stat:%d\n", i < len? "...": "", status);
}
}
#endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 6edf4097d2d..240c7f50754 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "SUB", usb_pipein (pipe));
+ urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
- if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+ if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +198,17 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
-
- /* in case of unlink-during-submit */
- spin_lock (&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock (&urb->lock);
- urb->hcpriv = urb_priv;
- finish_urb (ohci, urb);
- retval = 0;
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
goto fail;
- }
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
- if (retval < 0)
- goto fail0;
+ if (retval < 0) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ goto fail;
+ }
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
-fail0:
- spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
@@ -249,22 +240,26 @@ fail:
}
/*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status. reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
+ int rc;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "UNLINK", 1);
+ urb_print(urb, "UNLINK", 1, status);
#endif
spin_lock_irqsave (&ohci->lock, flags);
- if (HC_IS_RUNNING(hcd->state)) {
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc) {
+ ; /* Do nothing */
+ } else if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv)
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, status);
}
spin_unlock_irqrestore (&ohci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@ rescan:
if (!HC_IS_RUNNING (hcd->state)) {
sanitize:
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
finish_unlinks (ohci, 0);
}
@@ -321,7 +318,12 @@ sanitize:
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
if (limit-- == 0) {
- ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+ ohci_warn(ohci, "ED unlink timeout\n");
+ if (quirk_zfmicro(ohci)) {
+ ohci_warn(ohci, "Attempting ZF TD recovery\n");
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+ }
goto sanitize;
}
spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
}
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+ return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+ && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+ == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+ && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist. On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+ long flags;
+ unsigned max;
+ unsigned seen_count = 0;
+ unsigned i;
+ struct ed **seen = NULL;
+ struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+ max = ohci->eds_scheduled;
+ if (!max)
+ goto done;
+
+ if (ohci->ed_to_check)
+ goto out;
+
+ seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+ if (!seen)
+ goto out;
+
+ for (i = 0; i < NUM_INTS; i++) {
+ struct ed *ed = ohci->periodic[i];
+
+ while (ed) {
+ unsigned temp;
+
+ /* scan this branch of the periodic schedule tree */
+ for (temp = 0; temp < seen_count; temp++) {
+ if (seen[temp] == ed) {
+ /* we've checked it and what's after */
+ ed = NULL;
+ break;
+ }
+ }
+ if (!ed)
+ break;
+ seen[seen_count++] = ed;
+ if (!check_ed(ohci, ed)) {
+ ed = ed->ed_next;
+ continue;
+ }
+
+ /* HC's TD list is empty, but HCD sees at least one
+ * TD that's not been sent through the donelist.
+ */
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+
+ /* The HC may wait until the next frame to report the
+ * TD as done through the donelist and INTR_WDH. (We
+ * just *assume* it's not a multi-TD interrupt URB;
+ * those could defer the IRQ more than one frame, using
+ * DI...) Check again after the next INTR_SF.
+ */
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrstatus);
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrenable);
+
+ /* flush those writes */
+ (void) ohci_readl(ohci, &ohci->regs->control);
+
+ goto out;
+ }
+ }
+out:
+ kfree(seen);
+ if (ohci->eds_scheduled)
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@ retry:
mdelay ((temp >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
+ if (quirk_zfmicro(ohci)) {
+ /* Create timer to watch for bad queue state on ZF Micro */
+ setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+ (unsigned long) ohci);
+
+ ohci->eds_scheduled = 0;
+ ohci->ed_to_check = NULL;
+ }
+
ohci_dump (ohci, 1);
return 0;
@@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs __iomem *regs = ohci->regs;
- int ints;
+ int ints;
/* we can eliminate a (slow) ohci_readl()
- if _only_ WDH caused this irq */
+ * if _only_ WDH caused this irq
+ */
if ((ohci->hcca->done_head != 0)
&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
& 0x01)) {
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints & OHCI_INTR_UE) {
// e.g. due to PCI Master/Target Abort
- if (ohci->flags & OHCI_QUIRK_NEC) {
+ if (quirk_nec(ohci)) {
/* Workaround for a silicon bug in some NEC chips used
* in Apple's PowerBooks. Adapted from Darwin code.
*/
@@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
}
+ if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+ spin_lock(&ohci->lock);
+ if (ohci->ed_to_check) {
+ struct ed *ed = ohci->ed_to_check;
+
+ if (check_ed(ohci, ed)) {
+ /* HC thinks the TD list is empty; HCD knows
+ * at least one TD is outstanding
+ */
+ if (--ohci->zf_delay == 0) {
+ struct td *td = list_entry(
+ ed->td_list.next,
+ struct td, td_list);
+ ohci_warn(ohci,
+ "Reclaiming orphan TD %p\n",
+ td);
+ takeback_td(ohci, td);
+ ohci->ed_to_check = NULL;
+ }
+ } else
+ ohci->ed_to_check = NULL;
+ }
+ spin_unlock(&ohci->lock);
+ }
+
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, ohci_frame_no(ohci));
- if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+ if ((ints & OHCI_INTR_SF) != 0
+ && !ohci->ed_rm_list
+ && !ohci->ed_to_check
&& HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
free_irq(hcd->irq, hcd);
hcd->irq = -1;
+ if (quirk_zfmicro(ohci))
+ del_timer(&ohci->unlink_watchdog);
+
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
ed, ed->state);
}
- spin_lock (&urb->lock);
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
+ if (!urb->unlinked)
+ urb->unlinked = -ESHUTDOWN;
}
finish_unlinks (ohci, 0);
spin_unlock_irq(&ohci->lock);
@@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
- struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
- int status;
-
- status = ohci_init(ohci);
- if (status != 0) {
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_init, %d\n", status);
- return;
- }
-
- status = ohci_restart(ohci);
- if (status != 0)
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER ssb_ohci_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && \
+ !defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
+#ifdef SSB_OHCI_DRIVER
+ retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+ if (retval)
+ goto error_ssb;
+#endif
+
return retval;
/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
error_pci:
#endif
#ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef SSB_OHCI_DRIVER
+ ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 450c7b460c5..2f20d3dc895 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb85d07..d0360f65ebd 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+ ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
return 0;
}
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
/* Check for NEC chip and apply quirk for allegedly lost interrupts.
*/
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+ struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+ int status;
+
+ status = ohci_init(ohci);
+ if (status != 0) {
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_init", status);
+ return;
+ }
+
+ status = ohci_restart(ohci);
+ if (status != 0)
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_restart", status);
+}
+
static int ohci_quirk_nec(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_NEC;
+ INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
return 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index c43b66acd4d..0a742692015 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
ohci = hcd_to_ohci(hcd);
- if (is_bigendian)
+ if (is_bigendian) {
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ if (of_device_is_compatible(dn, "mpc5200-ohci"))
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ }
ohci_hcd_init(ohci);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e1777ca6..f95be1896b0 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+ /* MPC52xx doesn't need frame_no shift */
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe8615..51817322232 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
* PRECONDITION: ohci lock held, irqs blocked.
*/
static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
__releases(ohci->lock)
__acquires(ohci->lock)
{
// ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv);
- urb->hcpriv = NULL;
-
- spin_lock (&urb->lock);
- if (likely (urb->status == -EINPROGRESS))
- urb->status = 0;
- /* report short control reads right even though the data TD always
- * has TD_R set. (much simpler, but creates the 1-td limit.)
- */
- if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
- && unlikely (usb_pipecontrol (urb->pipe))
- && urb->actual_length < urb->transfer_buffer_length
- && usb_pipein (urb->pipe)
- && urb->status == 0) {
- urb->status = -EREMOTEIO;
- }
- spin_unlock (&urb->lock);
+ if (likely(status == -EINPROGRESS))
+ status = 0;
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
}
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "RET", usb_pipeout (urb->pipe));
+ urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
#endif
/* urb->complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
spin_unlock (&ohci->lock);
- usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+ usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
spin_lock (&ohci->lock);
/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ed->ed_prev = NULL;
ed->ed_next = NULL;
ed->hwNextED = 0;
+ if (quirk_zfmicro(ohci)
+ && (ed->type == PIPE_INTERRUPT)
+ && !(ohci->eds_scheduled++))
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
wmb ();
/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
* Done List handling functions
*-------------------------------------------------------------------------*/
-/* calculate transfer length/status and update the urb
- * PRECONDITION: irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
{
u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
int cc = 0;
+ int status = -EINPROGRESS;
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
- u16 tdPSW = ohci_hwPSW (ohci, td, 0);
+ u16 tdPSW = ohci_hwPSW(ohci, td, 0);
int dlen = 0;
/* NOTE: assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
cc = (tdPSW >> 12) & 0xF;
if (tdINFO & TD_CC) /* hc didn't touch? */
- return;
+ return status;
if (usb_pipeout (urb->pipe))
dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
if (cc == TD_DATAUNDERRUN
&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
cc = TD_CC_NOERROR;
- if (cc != TD_CC_NOERROR && cc < 0x0E) {
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error [cc];
- spin_unlock (&urb->lock);
- }
+ if (cc != TD_CC_NOERROR && cc < 0x0E)
+ status = cc_to_error[cc];
/* count all non-empty packets except control SETUP packet */
if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
urb->actual_length,
urb->transfer_buffer_length);
}
+ return status;
}
/*-------------------------------------------------------------------------*/
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
{
struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
wmb ();
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
- /* put any later tds from this urb onto the donelist, after 'td',
- * order won't matter here: no errors, and nothing was transferred.
- * also patch the ed so it looks as if those tds completed normally.
+ /* Get rid of all later tds from this urb. We don't have
+ * to be careful: no errors and nothing was transferred.
+ * Also patch the ed so it looks as if those tds completed normally.
*/
while (tmp != &ed->td_list) {
struct td *next;
- __hc32 info;
next = list_entry (tmp, struct td, td_list);
tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* then we need to leave the control STATUS packet queued
* and clear ED_SKIP.
*/
- info = next->hwINFO;
- info |= cpu_to_hc32 (ohci, TD_DONE);
- info &= ~cpu_to_hc32 (ohci, TD_CC);
- next->hwINFO = info;
-
- next->next_dl_td = rev;
- rev = next;
+ list_del(&next->td_list);
+ urb_priv->td_cnt++;
ed->hwHeadP = next->hwNextTD | toggle;
}
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
hc32_to_cpu (ohci, td->hwINFO),
cc, cc_to_error [cc]);
}
-
- return rev;
}
/* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
*/
if (cc != TD_CC_NOERROR
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
- td_rev = ed_halted (ohci, td, cc, td_rev);
+ ed_halted(ohci, td, cc);
td->next_dl_td = td_rev;
td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
TD_MASK;
/* INTR_WDH may need to clean up first */
- if (td->td_dma != head)
- goto skip_ed;
+ if (td->td_dma != head) {
+ if (ed == ohci->ed_to_check)
+ ohci->ed_to_check = NULL;
+ else
+ goto skip_ed;
+ }
}
}
@@ -974,7 +957,7 @@ rescan_this:
urb = td->urb;
urb_priv = td->urb->hcpriv;
- if (urb->status == -EINPROGRESS) {
+ if (!urb->unlinked) {
prev = &td->hwNextTD;
continue;
}
@@ -990,7 +973,7 @@ rescan_this:
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, 0);
}
}
if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
/* ED's now officially unlinked, hc doesn't see */
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
ed->hwNextED = 0;
wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
if (ohci->ed_controltail) {
command |= OHCI_CLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
}
if (ohci->ed_bulktail) {
command |= OHCI_BLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
if (control) {
ohci->hc_control |= control;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, ohci->hc_control,
&ohci->regs->control);
}
if (command) {
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
}
@@ -1061,11 +1046,60 @@ rescan_this:
/*-------------------------------------------------------------------------*/
/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames). This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct ed *ed = td->ed;
+ int status;
+
+ /* update URB's length and status from TD */
+ status = td_done(ohci, urb, td);
+ urb_priv->td_cnt++;
+
+ /* If all this urb's TDs are done, call complete() */
+ if (urb_priv->td_cnt == urb_priv->length)
+ finish_urb(ohci, urb, status);
+
+ /* clean schedule: unlink EDs that are no longer busy */
+ if (list_empty(&ed->td_list)) {
+ if (ed->state == ED_OPER)
+ start_ed_unlink(ohci, ed);
+
+ /* ... reenabling halted EDs only after fault cleanup */
+ } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+ == cpu_to_hc32(ohci, ED_SKIP)) {
+ td = list_entry(ed->td_list.next, struct td, td_list);
+ if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+ ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+ /* ... hc may need waking-up */
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ohci_writel(ohci, OHCI_CLF,
+ &ohci->regs->cmdstatus);
+ break;
+ case PIPE_BULK:
+ ohci_writel(ohci, OHCI_BLF,
+ &ohci->regs->cmdstatus);
+ break;
+ }
+ }
+ }
+}
+
+/*
* Process normal completions (error or success) and clean the schedules.
*
* This is the main path for handing urbs back to drivers. The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does. There's
+ * an abnormal path too, handling a quirk in some Compaq silicon: URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
*/
static void
dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
while (td) {
struct td *td_next = td->next_dl_td;
- struct urb *urb = td->urb;
- urb_priv_t *urb_priv = urb->hcpriv;
- struct ed *ed = td->ed;
-
- /* update URB's length and status from TD */
- td_done (ohci, urb, td);
- urb_priv->td_cnt++;
-
- /* If all this urb's TDs are done, call complete() */
- if (urb_priv->td_cnt == urb_priv->length)
- finish_urb (ohci, urb);
-
- /* clean schedule: unlink EDs that are no longer busy */
- if (list_empty (&ed->td_list)) {
- if (ed->state == ED_OPER)
- start_ed_unlink (ohci, ed);
-
- /* ... reenabling halted EDs only after fault cleanup */
- } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
- ED_SKIP | ED_DEQUEUE))
- == cpu_to_hc32 (ohci, ED_SKIP)) {
- td = list_entry (ed->td_list.next, struct td, td_list);
- if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
- ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
- /* ... hc may need waking-up */
- switch (ed->type) {
- case PIPE_CONTROL:
- ohci_writel (ohci, OHCI_CLF,
- &ohci->regs->cmdstatus);
- break;
- case PIPE_BULK:
- ohci_writel (ohci, OHCI_BLF,
- &ohci->regs->cmdstatus);
- break;
- }
- }
- }
-
+ takeback_td(ohci, td);
td = td_next;
}
}
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644
index 00000000000..fe70e72340d
--- /dev/null
+++ b/drivers/usb/host/ohci-ssb.c
@@ -0,0 +1,249 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
+
+struct ssb_ohci_device {
+ struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+ u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+ return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ ohci_hcd_init(ohci);
+ err = ohci_init(ohci);
+
+ return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ err = ohci_run(ohci);
+ if (err < 0) {
+ ohci_err(ohci, "can't start\n");
+ ohci_stop(hcd);
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW)
+ ohci_usb_reset(ohci);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ usb_hcd_resume_root_hub(hcd);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+ .description = "ssb-usb-ohci",
+ .product_desc = "SSB OHCI Controller",
+ .hcd_priv_size = sizeof(struct ssb_ohci_device),
+
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+
+ .reset = ssb_ohci_reset,
+ .start = ssb_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+#ifdef CONFIG_PM
+ .suspend = ssb_ohci_hcd_suspend,
+ .resume = ssb_ohci_hcd_resume,
+#endif
+
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ .get_frame_number = ohci_get_frame,
+
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ usb_put_hcd(hcd);
+ ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+ struct ssb_ohci_device *ohcidev;
+ struct usb_hcd *hcd;
+ int err = -ENOMEM;
+ u32 tmp, flags = 0;
+
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+ ssb_device_enable(dev, flags);
+
+ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+ dev->dev->bus_id);
+ if (!hcd)
+ goto err_dev_disable;
+ ohcidev = hcd_to_ssb_ohci(hcd);
+ ohcidev->enable_flags = flags;
+
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
+ hcd->rsrc_start = ssb_admatch_base(tmp);
+ hcd->rsrc_len = ssb_admatch_size(tmp);
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs)
+ goto err_put_hcd;
+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+ if (err)
+ goto err_iounmap;
+
+ ssb_set_drvdata(dev, hcd);
+
+ return err;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_put_hcd:
+ usb_put_hcd(hcd);
+err_dev_disable:
+ ssb_device_disable(dev, flags);
+ return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ int err;
+ u16 chipid_top;
+
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (dev->bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
+ * as HOST OHCI. If we want to attach it as Client device,
+ * we must branch here and call into the (yet to
+ * be written) Client mode driver. Same for remove(). */
+
+ err = ssb_ohci_attach(dev);
+
+ return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+ ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ ssb_device_disable(dev, 0);
+
+ return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+ ssb_device_enable(dev, ohcidev->enable_flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend NULL
+#define ssb_ohci_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ssb_ohci_table,
+ .probe = ssb_ohci_probe,
+ .remove = ssb_ohci_remove,
+ .suspend = ssb_ohci_suspend,
+ .resume = ssb_ohci_resume,
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 4ada43cf138..47c5c66a282 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -398,11 +398,38 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
+#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
+
+ /* Needed for ZF Micro quirk */
+ struct timer_list unlink_watchdog;
+ unsigned eds_scheduled;
+ struct ed *ed_to_check;
+ unsigned zf_delay;
};
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+#endif
+
/* convert between an hcd pointer and the corresponding ohci_hcd */
static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
{
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
*/
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT 16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO)
#else
-#define OHCI_BE_FRAME_NO_SHIFT 0
+#define big_endian_frame_no_quirk(ohci) 0
#endif
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
u32 tmp;
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
- tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+ if (!big_endian_frame_no_quirk(ohci))
+ tmp >>= 16;
} else
tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 40a1de4c256..ae8ec4474eb 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
kfree(td);
if (urb) {
- urb->status = -ENODEV;
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+ urb);
+
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+ -ENODEV);
spin_lock(&r8a66597->lock);
}
break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = ep->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
info.type = get_r8a66597_type(ep->bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, p[i], setup_addr);
+ r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
pipe_start(r8a66597, td->pipe);
}
+static int is_set_address(unsigned char *setup_packet)
+{
+ if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+ setup_packet[1] == USB_REQ_SET_ADDRESS)
+ return 1;
+ else
+ return 0;
+}
+
/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
@@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
switch (td->type) {
case USB_PID_SETUP:
- if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+ if (is_set_address(td->urb->setup_packet)) {
td->set_address = 1;
td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
td->urb);
@@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
}
/* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
int restart = 0;
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
r8a66597->timeout_map &= ~(1 << pipenum);
if (likely(td)) {
- if (td->set_address && urb->status != 0)
+ if (td->set_address && (status != 0 || urb->unlinked))
r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
}
@@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
}
}
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
- done(r8a66597, td, pipenum, urb);
-}
-
static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
u16 tmp;
@@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
struct urb *urb;
int finish = 0;
+ int status = 0;
if (unlikely(!td))
return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("in fifo not ready (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
/* prepare parameters */
rcv_len = tmp & DTLN;
- bufsize = td->maxpacket;
if (usb_pipeisoc(urb->pipe)) {
buf = (u16 *)(urb->transfer_buffer +
urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
- if (rcv_len < bufsize)
- size = min(rcv_len, urb_len);
- else
- size = min(bufsize, urb_len);
+ bufsize = min(urb_len, (int) td->maxpacket);
+ if (rcv_len <= bufsize) {
+ size = rcv_len;
+ } else {
+ size = bufsize;
+ status = -EOVERFLOW;
+ finish = 1;
+ }
/* update parameters */
urb->actual_length += size;
if (rcv_len == 0)
td->zero_packet = 1;
- if ((size % td->maxpacket) > 0) {
+ if (rcv_len < bufsize) {
td->short_packet = 1;
- if (urb->transfer_buffer_length != urb->actual_length &&
- urb->transfer_flags & URB_SHORT_NOT_OK)
- td->urb->status = -EREMOTEIO;
}
if (usb_pipeisoc(urb->pipe)) {
urb->iso_frame_desc[td->iso_cnt].actual_length = size;
- urb->iso_frame_desc[td->iso_cnt].status = 0;
+ urb->iso_frame_desc[td->iso_cnt].status = status;
td->iso_cnt++;
+ finish = 0;
}
/* check transfer finish */
- if (check_transfer_finish(td, urb)) {
+ if (finish || check_transfer_finish(td, urb)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf, size);
}
- if (finish && pipenum != 0) {
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, urb);
- }
+ if (finish && pipenum != 0)
+ finish_request(r8a66597, td, pipenum, urb, status);
}
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("out write fifo not ready. (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
@@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
}
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
switch (td->type) {
case USB_PID_IN:
case USB_PID_OUT:
- if (urb->status != -EINPROGRESS) {
- finish = 1;
- break;
- }
if (check_transfer_finish(td, urb))
td->type = USB_PID_ACK;
break;
case USB_PID_SETUP:
- if (urb->status != -EINPROGRESS)
- finish = 1;
- else if (urb->transfer_buffer_length == urb->actual_length) {
+ if (urb->transfer_buffer_length == urb->actual_length)
td->type = USB_PID_ACK;
- urb->status = 0;
- } else if (usb_pipeout(urb->pipe))
+ else if (usb_pipeout(urb->pipe))
td->type = USB_PID_OUT;
else
td->type = USB_PID_IN;
break;
case USB_PID_ACK:
finish = 1;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
break;
}
- if (finish)
- finish_request(r8a66597, td, 0, urb);
+ if (finish || status != 0 || urb->unlinked)
+ finish_request(r8a66597, td, 0, urb, status);
else
start_transfer(r8a66597, td);
}
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
- if (td && td->urb) {
+ if (td) {
u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
if (pid == PID_NAK)
- td->urb->status = -ECONNRESET;
+ return -ECONNRESET;
else
- td->urb->status = -EPIPE;
+ return -EPIPE;
}
+ return 0;
}
static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
packet_read(r8a66597, 0);
else
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type != USB_PID_OUT)
disable_irq_empty(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
if ((tmp & INBUFM) == 0) {
disable_irq_empty(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb,
+ 0);
}
}
}
@@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
u16 check;
u16 pipenum;
u16 mask;
+ int status;
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
- set_urb_error(r8a66597, 0);
+ status = get_urb_error(r8a66597, 0);
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, status);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
if (unlikely(!td))
continue;
- set_urb_error(r8a66597, pipenum);
+ status = get_urb_error(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
pipe_stop(r8a66597, td->pipe);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, status);
}
}
}
@@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
u16 intsts0, intsts1, intsts2;
u16 intenb0, intenb1, intenb2;
u16 mask0, mask1, mask2;
+ int status;
spin_lock(&r8a66597->lock);
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
}
if (mask1 & SIGN) {
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
- set_urb_error(r8a66597, 0);
- check_next_phase(r8a66597);
+ status = get_urb_error(r8a66597, 0);
+ check_next_phase(r8a66597, status);
}
if (mask1 & SACK) {
r8a66597_write(r8a66597, ~SACK, INTSTS1);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
}
if (mask0) {
@@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
+ struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
- int ret = 0, request = 0;
+ int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
- goto error;
+ goto error_not_linked;
}
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto error_not_linked;
+
if (!hep->hcpriv) {
hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- ret = -EPIPE;
- goto error;
- }
urb->hcpriv = td;
- spin_unlock(&urb->lock);
if (request) {
ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
set_td_timer(r8a66597, td);
error:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, td->pipenum);
disable_irq_empty(r8a66597, td->pipenum);
- done(r8a66597, td, td->pipenum, urb);
+ finish_request(r8a66597, td, td->pipenum, urb, status);
}
+ done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
- return 0;
+ return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
td = r8a66597_get_td(r8a66597, pipenum);
if (td)
urb = td->urb;
- done(r8a66597, td, pipenum, urb);
+ finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
kfree(hep->hcpriv);
hep->hcpriv = NULL;
spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
- *(u32 *)buf = rh->port;
+ *(u32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
- iounmap((void *)r8a66597->reg);
usb_remove_hcd(hcd);
+ iounmap((void *)r8a66597->reg);
usb_put_hcd(hcd);
return 0;
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4cfa3ff2c99..94d859aa73f 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -435,14 +435,9 @@ static void finish_request(
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- urb->hcpriv = NULL;
- spin_unlock(&urb->lock);
-
+ usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
spin_unlock(&sl811->lock);
- usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+ usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
spin_lock(&sl811->lock);
/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank + SL11H_XFERCNTREG);
if (len > ep->length) {
len = ep->length;
- urb->status = -EOVERFLOW;
+ urbstat = -EOVERFLOW;
}
urb->actual_length += len;
sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
buf, len);
usb_dotoggle(udev, ep->epnum, 0);
- if (urb->actual_length == urb->transfer_buffer_length)
- urbstat = 0;
- else if (len < ep->maxpacket) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
- urbstat = -EREMOTEIO;
+ if (urbstat == -EINPROGRESS &&
+ (len < ep->maxpacket ||
+ urb->actual_length ==
+ urb->transfer_buffer_length)) {
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_ACK;
else
urbstat = 0;
}
- if (usb_pipecontrol(urb->pipe)
- && (urbstat == -EREMOTEIO
- || urbstat == 0)) {
-
- /* NOTE if the status stage STALLs (why?),
- * this reports the wrong urb status.
- */
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = urbstat;
- spin_unlock(&urb->lock);
-
- urb = NULL;
- ep->nextpid = USB_PID_ACK;
- }
break;
case USB_PID_SETUP:
// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank, status, ep, urbstat);
}
- if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+ if (urbstat != -EINPROGRESS || urb->unlinked)
finish_request(sl811, ep, urb, urbstat);
}
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
struct sl811h_ep *ep = NULL;
unsigned long flags;
int i;
- int retval = 0;
+ int retval;
+ struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
|| !HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
kfree(ep);
- goto fail;
+ goto fail_not_linked;
+ }
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
sofirq_on(sl811);
}
- /* in case of unlink-during-submit */
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- finish_request(sl811, ep, urb, 0);
- retval = 0;
- goto fail;
- }
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
-
start_transfer(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
fail:
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
- int retval = 0;
+ int retval;
spin_lock_irqsave(&sl811->lock, flags);
- hep = urb->hcpriv;
- if (!hep)
+ retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (retval)
goto fail;
+ hep = urb->hcpriv;
ep = hep->hcpriv;
if (ep) {
/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
-fail:
retval = -EINVAL;
+ fail:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index b88eb3c62c0..ac283b09a63 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -51,7 +51,6 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
-#include <linux/pci_ids.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
struct u132 {
struct kref kref;
struct list_head u132_list;
- struct semaphore sw_lock;
+ struct mutex sw_lock;
struct semaphore scheduler_lock;
struct u132_platform_data *board;
struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
return;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = read_roothub_info(u132);
if (retval) {
struct usb_hcd *hcd = u132_to_hcd(u132);
u132_disable(u132);
u132->going = 1;
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_hc_died(hcd);
ftdi_elan_gone_away(u132->platform_dev);
u132_monitor_put_kref(u132);
return;
} else {
u132_monitor_requeue_work(u132, 500);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
}
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
u132_ring_queue_work(u132, ring, 0);
up(&u132->scheduler_lock);
u132_endp_put_kref(u132, endp);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
endp->active = 0;
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(urbq);
- } usb_hcd_giveback_urb(hcd, urb);
+ } usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
urb->actual_length += len;
endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
if (usb_pipein(urb->pipe)) {
int retval;
struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
u132->addr[0].address = 0;
endp->usb_addr = udev->usb_addr;
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
"ed\n", hcd);
} else {
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(100);
u132_power(u132, 0);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
}
}
@@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
(pdev->dev.platform_data))->vendor;
u16 device = ((struct u132_platform_data *)
(pdev->dev.platform_data))->device;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(10);
if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
u132->going = 1;
}
msleep(100);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
} else {
dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
return -ESHUTDOWN;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = u132_init(u132);
if (retval) {
u132_disable(u132);
u132->going = 1;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
static int create_endpoint_and_queue_int(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
u132_udev_get_kref(u132, udev);
}
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->delayed = 1;
endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
return 0;
}
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_bulk(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
int ring_number;
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
endp->dequeueing = 0;
endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
ring->length += 1;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->udev_number = address;
endp->usb_addr = usb_addr;
endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_control(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
gfp_t mem_flags)
{
struct u132_ring *ring;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ unsigned long irqs;
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
u132_endp_init_kref(u132, endp);
u132_endp_get_kref(u132, endp);
if (usb_addr == 0) {
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
u132_endp_queue_work(u132, endp, 0);
return 0;
} else { /*(usb_addr > 0) */
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
}
static int queue_control_on_old_endpoint(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp)
{
@@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
}
}
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
- struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
, u132->going);
return -ENODEV;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
return -ESHUTDOWN;
} else {
u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_int_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_int_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else { /*(endp == NULL) */
return create_endpoint_and_queue_int(u132, udev,
- hep, urb, usb_dev, usb_addr, usb_endp,
- address, mem_flags);
+ urb, usb_dev, usb_addr,
+ usb_endp, address, mem_flags);
}
} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_bulk_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_bulk_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_bulk(u132,
- udev, hep, urb, usb_dev, usb_addr,
+ udev, urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
} else {
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
u16 urb_size = 8;
u8 *b = urb->setup_packet;
int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_control_on_old_endpoint(u132,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_control_on_old_endpoint(
+ u132, urb, usb_dev,
+ endp, usb_addr,
+ usb_endp);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_control(u132,
- hep, urb, usb_dev, usb_addr, usb_endp,
+ urb, usb_dev, usb_addr, usb_endp,
mem_flags);
}
}
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
list_del(scan);
endp->queue_size -= 1;
urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
} else
continue;
@@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
}
static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb)
+ struct urb *urb, int status)
{
unsigned long irqs;
+ int rc;
+
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return rc;
+ }
if (endp->queue_size == 0) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
"=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
endp->edset_flush = 1;
u132_endp_queue_work(u132, endp, 0);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- urb->hcpriv = NULL;
return 0;
} else {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+ u132_hcd_abandon_urb(u132, endp, urb, status);
return 0;
}
} else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
if (urb_slot) {
struct usb_hcd *hcd = u132_to_hcd(u132);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_size -= 1;
if (list_empty(&endp->urb_more)) {
spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
irqs);
kfree(urbq);
} urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return 0;
} else if (list_empty(&endp->urb_more)) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return -EINVAL;
} else {
- int retval = dequeue_from_overflow_chain(u132, endp,
+ int retval;
+
+ usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+ retval = dequeue_from_overflow_chain(u132, endp,
urb);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return retval;
@@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
}
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (u132->going > 2) {
@@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
if (usb_pipein(urb->pipe)) {
u8 endp_number = udev->endp_number_in[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
} else {
u8 endp_number = udev->endp_number_out[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
}
}
}
@@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return -ESHUTDOWN;
} else {
int retval = 0;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
switch (typeReq) {
case ClearHubFeature:
switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
stall:retval = -EPIPE;
break;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
dev_err(&u132->platform_dev->dev, "removing device u132"
".%d\n", u132->sequence_num);
msleep(100);
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
u132_monitor_cancel_work(u132);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
u132->going += 1;
printk(KERN_INFO "removing device u132.%d\n",
u132->sequence_num);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_remove_hcd(hcd);
u132_u132_put_kref(u132);
return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
u132->platform_dev = pdev;
u132->power = 0;
u132->reset = 0;
- init_MUTEX(&u132->sw_lock);
+ mutex_init(&u132->sw_lock);
init_MUTEX(&u132->scheduler_lock);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
ring->curr_endp = NULL;
INIT_DELAYED_WORK(&ring->scheduler,
u132_hcd_ring_work_scheduler);
- } down(&u132->sw_lock);
+ } mutex_lock(&u132->sw_lock);
INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
while (ports-- > 0) {
struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
while (endps-- > 0) {
u132->endp[endps] = NULL;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371583b..20cc58b9780 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
- if (urbp->urb->status != -EINPROGRESS)
- out += sprintf(out, " Status=%d", urbp->urb->status);
+ if (urbp->urb->unlinked)
+ out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
out += sprintf(out, "\n");
i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1b3d23406ac..340d6ed3e6e 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -146,7 +146,6 @@ struct uhci_qh {
short phase; /* Between 0 and period-1 */
short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
- int iso_status; /* Status for Isochronous URBs */
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
};
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock. urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
/* Some special IDs */
#define PCI_VENDOR_ID_GENESYS 0x17a0
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 3bb908ca38e..e5d60d5b105 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
uhci_free_td(uhci, td);
}
- urbp->urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
}
@@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
if (list_empty(&qh->queue)) {
qh->iso_packet_desc = &urb->iso_frame_desc[0];
qh->iso_frame = urb->start_frame;
- qh->iso_status = 0;
}
qh->skel = SKEL_ISO;
@@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
qh->iso_packet_desc->actual_length = actlength;
qh->iso_packet_desc->status = status;
}
-
- if (status) {
+ if (status)
urb->error_count++;
- qh->iso_status = status;
- }
uhci_remove_td_from_urbp(td);
uhci_free_td(uhci, td);
qh->iso_frame += qh->period;
++qh->iso_packet_desc;
}
- return qh->iso_status;
+ return 0;
}
static int uhci_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
{
int ret;
@@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&uhci->lock, flags);
- ret = urb->status;
- if (ret != -EINPROGRESS) /* URB already unlinked! */
- goto done;
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto done_not_linked;
ret = -ENOMEM;
urbp = uhci_alloc_urb_priv(uhci, urb);
if (!urbp)
goto done;
- if (hep->hcpriv)
- qh = (struct uhci_qh *) hep->hcpriv;
+ if (urb->ep->hcpriv)
+ qh = urb->ep->hcpriv;
else {
- qh = uhci_alloc_qh(uhci, urb->dev, hep);
+ qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
if (!qh)
goto err_no_qh;
}
@@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
err_submit_failed:
if (qh->state == QH_STATE_IDLE)
uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
-
err_no_qh:
uhci_free_urb_priv(uhci, urbp);
-
done:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
spin_unlock_irqrestore(&uhci->lock, flags);
return ret;
}
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
- struct urb_priv *urbp;
struct uhci_qh *qh;
+ int rc;
spin_lock_irqsave(&uhci->lock, flags);
- urbp = urb->hcpriv;
- if (!urbp) /* URB was never linked! */
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
goto done;
- qh = urbp->qh;
+
+ qh = ((struct urb_priv *) urb->hcpriv)->qh;
/* Remove Isochronous TDs from the frame list ASAP */
if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
done:
spin_unlock_irqrestore(&uhci->lock, flags);
- return 0;
+ return rc;
}
/*
* Finish unlinking an URB and give it back
*/
static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
- struct urb *urb)
+ struct urb *urb, int status)
__releases(uhci->lock)
__acquires(uhci->lock)
{
@@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
* unlinked first. Regardless, don't confuse people with a
* negative length. */
urb->actual_length = max(urb->actual_length, 0);
-
- /* Report erroneous short transfers */
- if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length <
- urb->transfer_buffer_length &&
- urb->status == 0))
- urb->status = -EREMOTEIO;
}
/* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1505,6 @@ __acquires(uhci->lock)
qh->iso_packet_desc = &nurb->iso_frame_desc[0];
qh->iso_frame = nurb->start_frame;
- qh->iso_status = 0;
}
/* Take the URB off the QH's queue. If the queue is now empty,
@@ -1529,9 +1517,10 @@ __acquires(uhci->lock)
}
uhci_free_urb_priv(uhci, urbp);
+ usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
spin_unlock(&uhci->lock);
- usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
spin_lock(&uhci->lock);
/* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (status == -EINPROGRESS)
break;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) /* Not dequeued */
- urb->status = status;
- else
- status = ECONNRESET; /* Not -ECONNRESET */
- spin_unlock(&urb->lock);
-
/* Dequeued but completed URBs can't be given back unless
* the QH is stopped or has finished unlinking. */
- if (status == ECONNRESET) {
+ if (urb->unlinked) {
if (QH_FINISHED_UNLINKING(qh))
qh->is_stopped = 1;
else if (!qh->is_stopped)
return;
}
- uhci_giveback_urb(uhci, qh, urb);
- if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+ uhci_giveback_urb(uhci, qh, urb, status);
+ if (status < 0)
break;
}
@@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
restart:
list_for_each_entry(urbp, &qh->queue, node) {
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
+ if (urb->unlinked) {
/* Fix up the TD links and save the toggles for
* non-Isochronous queues. For Isochronous queues,
@@ -1608,7 +1590,7 @@ restart:
qh->is_stopped = 0;
return;
}
- uhci_giveback_urb(uhci, qh, urb);
+ uhci_giveback_urb(uhci, qh, urb, 0);
goto restart;
}
}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 768b2c11a23..e7d982a7154 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -446,7 +446,8 @@ static void mts_data_done( struct urb* transfer )
MTS_INT_INIT();
if ( context->data_length != transfer->actual_length ) {
- context->srb->resid = context->data_length - transfer->actual_length;
+ scsi_set_resid(context->srb, context->data_length -
+ transfer->actual_length);
} else if ( unlikely(status) ) {
context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
@@ -490,7 +491,8 @@ static void mts_command_done( struct urb *transfer )
context->data_pipe,
context->data,
context->data_length,
- context->srb->use_sg > 1 ? mts_do_sg : mts_data_done);
+ scsi_sg_count(context->srb) > 1 ?
+ mts_do_sg : mts_data_done);
} else {
mts_get_status(transfer);
}
@@ -505,21 +507,23 @@ static void mts_do_sg (struct urb* transfer)
int status = transfer->status;
MTS_INT_INIT();
- MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
+ MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,
+ scsi_sg_count(context->srb));
if (unlikely(status)) {
context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
- sg = context->srb->request_buffer;
+ sg = scsi_sglist(context->srb);
context->fragment++;
mts_int_submit_urb(transfer,
context->data_pipe,
page_address(sg[context->fragment].page) +
sg[context->fragment].offset,
sg[context->fragment].length,
- context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
+ context->fragment + 1 == scsi_sg_count(context->srb) ?
+ mts_data_done : mts_do_sg);
return;
}
@@ -547,20 +551,12 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
desc->context.srb = srb;
desc->context.fragment = 0;
- if (!srb->use_sg) {
- if ( !srb->request_bufflen ){
- desc->context.data = NULL;
- desc->context.data_length = 0;
- return;
- } else {
- desc->context.data = srb->request_buffer;
- desc->context.data_length = srb->request_bufflen;
- MTS_DEBUG("length = %d or %d\n",
- srb->request_bufflen, srb->bufflen);
- }
+ if (!scsi_bufflen(srb)) {
+ desc->context.data = NULL;
+ desc->context.data_length = 0;
+ return;
} else {
- MTS_DEBUG("Using scatter/gather\n");
- sg = srb->request_buffer;
+ sg = scsi_sglist(srb);
desc->context.data = page_address(sg[0].page) + sg[0].offset;
desc->context.data_length = sg[0].length;
}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index e9fdbc8997b..5131cbfb2f5 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
spin_lock(&dev->buflock);
if (status != 0) {
- if ((status != -ENOENT) && (status != -ECONNRESET)) {
+ if ((status != -ENOENT) && (status != -ECONNRESET) &&
+ (status != -ESHUTDOWN)) {
dbg(1," %s : nonzero status received: %d",
__FUNCTION__, status);
}
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 92c1d2768df..24e2dc3148a 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 2) {
dev_err(&udev->dev, "First magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 0) {
dev_err(&udev->dev, "Second magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+exit:
+ kfree(dummy_buffer);
return retval;
}
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+ kfree(dummy_buffer);
return retval;
}
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 538b535e955..d3d8cd6ff10 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
size_t buffer_size;
int i;
int retval = -ENOMEM;
- struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
- if (ftdi == NULL) {
+ struct usb_ftdi *ftdi;
+
+ ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+ if (!ftdi) {
printk(KERN_ERR "Out of memory\n");
return -ENOMEM;
}
- memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index b64ca91d9b0..9244d067cec 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
packet.address = 0x00000194;
packet.data = addr;
ret = sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
packet.header = 0x001f;
packet.address = 0x00000190;
packet.data = (length & ~3);
ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
if (sisusb->flagb0 != 0x16) {
packet.header = 0x001f;
packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (ret) {
msgcount++;
if (msgcount < 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Wrote %zd of "
- "%d bytes, error %d\n",
- sisusb->minor, *bytes_written,
- length, ret);
+ dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+ *bytes_written, length, ret);
else if (msgcount == 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Too many errors"
- ", logging stopped\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
}
addr += (*bytes_written);
length -= (*bytes_written);
}
if (ret)
- break;
+ break;
}
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
addr += 4;
length -= 4;
}
-#if 0 /* That does not work, as EP 2 is an OUT EP! */
- default:
- CLEARPACKET(&packet);
- packet.header = 0x001f;
- packet.address = 0x000001a0;
- packet.data = 0x00000006;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b0;
- packet.data = (length & ~3) | 0x40000000;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b4;
- packet.data = addr;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001a4;
- packet.data = 0x00000001;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- if (userbuffer) {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- NULL, userbuffer,
- bytes_read, 0);
- if (!ret) userbuffer += (*bytes_read);
- } else {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- kernbuffer, NULL,
- bytes_read, 0);
- if (!ret) kernbuffer += (*bytes_read);
- }
- addr += (*bytes_read);
- length -= (*bytes_read);
-#endif
}
if (ret)
- break;
+ break;
}
return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
}
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
- return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
- return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif /* 0 */
-
int
sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
for(i = 1; i <= 7; i++) {
- printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+ dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
for(j = 0; j < i; j++) {
- printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+ dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
}
}
}
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
static int
sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
SETIREG(SISSR, 0x26, 0x00);
}
- SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
+ SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
return ret;
}
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
if (ramtype <= 1) {
ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
if (iret) {
- printk(KERN_ERR "sisusbvga[%d]: RAM size "
- "detection failed, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* TODO */
}
} else {
- printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* *** TODO *** */
}
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
break;
}
- printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
- sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+ dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
ramtypetext2[ramtype], bw);
}
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
- if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
- printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
- subminor);
+ if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
return -ENODEV;
- }
if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to initialize "
- "device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Device not attached to "
- "USB 2.0 hub\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
return -EIO;
}
}
@@ -2586,7 +2508,6 @@ static int
sisusb_release(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
- int myminor;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
sisusb_kill_all_busy(sisusb);
}
- myminor = sisusb->minor;
-
sisusb->isopen = 0;
file->private_data = NULL;
@@ -2942,7 +2861,7 @@ static int
sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
unsigned long arg)
{
- int retval, port, length;
+ int retval, port, length;
u32 address;
/* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
static int
sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
struct sisusb_usb_data *sisusb;
struct sisusb_info x;
struct sisusb_command y;
- int retval = 0;
+ int retval = 0;
u32 __user *argp = (u32 __user *)arg;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case SISUSB_GET_CONFIG:
- x.sisusb_id = SISUSB_ID;
+ x.sisusb_id = SISUSB_ID;
x.sisusb_version = SISUSB_VERSION;
x.sisusb_revision = SISUSB_REVISION;
x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
.release = sisusb_release,
.read = sisusb_read,
.write = sisusb_write,
- .llseek = sisusb_lseek,
+ .llseek = sisusb_lseek,
#ifdef SISUSB_NEW_CONFIG_COMPAT
.compat_ioctl = sisusb_compat_ioctl,
#endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
- const char *memfail =
- KERN_ERR
- "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
- printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+ dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
dev->devnum);
/* Allocate memory for our private */
if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusb: Failed to allocate memory for private data\n");
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
return -ENOMEM;
}
kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Register device */
if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
- printk(KERN_ERR
- "sisusb: Failed to get a minor for device %d\n",
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
dev->devnum);
retval = -ENODEV;
goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->ibufsize = SISUSB_IBUF_SIZE;
if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
GFP_KERNEL, &sisusb->transfer_dma_in))) {
- printk(memfail, "input", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
retval = -ENOMEM;
goto error_2;
}
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
GFP_KERNEL,
&sisusb->transfer_dma_out[i]))) {
if (i == 0) {
- printk(memfail, "output", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate URBs */
if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
for (i = 0; i < sisusb->numobufs; i++) {
if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_4;
}
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->urbstatus[i] = 0;
}
- printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
- sisusb->minor, sisusb->numobufs);
+ dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
}
#endif
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
if (ret)
- printk(KERN_ERR
- "sisusbvga[%d]: Error registering ioctl32 "
- "translations\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
else
sisusb->ioctl32registered = 1;
}
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
initscreen = 0;
#endif
if (sisusb_init_gfxdevice(sisusb, initscreen))
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to early "
- "initialize device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
} else
- printk(KERN_INFO
- "sisusbvga[%d]: Not attached to USB 2.0 hub, "
- "deferring init\n",
- sisusb->minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
sisusb->ready = 1;
#ifdef SISUSBENDIANTEST
- printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
sisusb_testreadwrite(sisusb);
- printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
#endif
#ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
static void sisusb_disconnect(struct usb_interface *intf)
{
struct sisusb_usb_data *sisusb;
- int minor;
/* This should *not* happen */
if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
- minor = sisusb->minor;
-
usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
if (ret) {
- printk(KERN_ERR
- "sisusbvga[%d]: Error unregistering "
- "ioctl32 translations\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
}
}
#endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
- printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
}
static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
static int __init usb_sisusb_init(void)
{
- int retval;
#ifdef INCL_SISUSB_CON
sisusb_init_concode();
#endif
- if (!(retval = usb_register(&sisusb_driver))) {
-
- printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
- SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
- printk(KERN_INFO
- "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
- }
-
- return retval;
+ return usb_register(&sisusb_driver);
}
static void __exit usb_sisusb_exit(void)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 8e1120a6480..d2d7872cd02 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -8,29 +8,29 @@
*
* Otherwise, the following license terms apply:
*
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * * notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * * notice, this list of conditions and the following disclaimer in the
- * * documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * * derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -44,16 +44,14 @@
#include <linux/mutex.h>
/* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
*/
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
/* Version Information */
#define SISUSB_VERSION 0
-#define SISUSB_REVISION 0
+#define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
@@ -74,7 +72,7 @@
#define SISUSB_IBUF_SIZE 0x01000
#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
-#define NUMOBUFS 8 /* max number of output buffers/output URBs */
+#define NUMOBUFS 8 /* max number of output buffers/output URBs */
/* About endianness:
*
@@ -93,7 +91,7 @@
*/
#ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
do { \
p->header = cpu_to_le16(p->header); \
p->address = cpu_to_le32(p->address); \
@@ -105,7 +103,7 @@
struct sisusb_usb_data;
-struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
+struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
struct sisusb_usb_data *sisusb;
int urbindex;
int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
struct usb_interface *interface;
struct kref kref;
wait_queue_head_t wait_q; /* for syncind and timeouts */
- struct mutex lock; /* general race avoidance */
- unsigned int ifnum; /* interface number of the USB device */
- int minor; /* minor (for logging clarity) */
- int isopen; /* !=0 if open */
- int present; /* !=0 if device is present on the bus */
- int ready; /* !=0 if device is ready for userland */
+ struct mutex lock; /* general race avoidance */
+ unsigned int ifnum; /* interface number of the USB device */
+ int minor; /* minor (for logging clarity) */
+ int isopen; /* !=0 if open */
+ int present; /* !=0 if device is present on the bus */
+ int ready; /* !=0 if device is ready for userland */
#ifdef SISUSB_OLD_CONFIG_COMPAT
int ioctl32registered;
#endif
- int numobufs; /* number of obufs = number of out urbs */
+ int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize;
dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
unsigned char completein;
struct sisusb_urb_context urbout_context[NUMOBUFS];
unsigned long flagb0;
- unsigned long vrambase; /* framebuffer base */
- unsigned int vramsize; /* framebuffer size (bytes) */
+ unsigned long vrambase; /* framebuffer base */
+ unsigned int vramsize; /* framebuffer size (bytes) */
unsigned long mmiobase;
unsigned int mmiosize;
unsigned long ioportbase;
- unsigned char devinit; /* device initialized? */
- unsigned char gfxinit; /* graphics core initialized? */
+ unsigned char devinit; /* device initialized? */
+ unsigned char gfxinit; /* graphics core initialized? */
unsigned short chipid, chipvendor;
unsigned short chiprevision;
#ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
int haveconsole, con_first, con_last;
int havethisconsole[MAX_NR_CONSOLES];
int textmodedestroyed;
- unsigned int sisusb_num_columns; /* real number, not vt's idea */
+ unsigned int sisusb_num_columns; /* real number, not vt's idea */
int cur_start_addr, con_rolled_over;
int sisusb_cursor_loc, bad_cursor_pos;
int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
unsigned short header;
u32 address;
u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
#define CLEARPACKET(packet) memset(packet, 0, 10)
@@ -265,36 +263,36 @@ struct sisusb_packet {
/* Structure argument for SISUSB_GET_INFO ioctl */
struct sisusb_info {
- __u32 sisusb_id; /* for identifying sisusb */
-#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
- __u8 sisusb_version;
- __u8 sisusb_revision;
- __u8 sisusb_patchlevel;
- __u8 sisusb_gfxinit; /* graphics core initialized? */
+ __u32 sisusb_id; /* for identifying sisusb */
+#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
+ __u8 sisusb_version;
+ __u8 sisusb_revision;
+ __u8 sisusb_patchlevel;
+ __u8 sisusb_gfxinit; /* graphics core initialized? */
- __u32 sisusb_vrambase;
- __u32 sisusb_mmiobase;
- __u32 sisusb_iobase;
- __u32 sisusb_pcibase;
+ __u32 sisusb_vrambase;
+ __u32 sisusb_mmiobase;
+ __u32 sisusb_iobase;
+ __u32 sisusb_pcibase;
- __u32 sisusb_vramsize; /* framebuffer size in bytes */
+ __u32 sisusb_vramsize; /* framebuffer size in bytes */
- __u32 sisusb_minor;
+ __u32 sisusb_minor;
- __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
+ __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
- __u32 sisusb_conactive; /* != 0 if console driver active */
+ __u32 sisusb_conactive; /* != 0 if console driver active */
- __u8 sisusb_reserved[28]; /* for future use */
+ __u8 sisusb_reserved[28]; /* for future use */
};
struct sisusb_command {
- __u8 operation; /* see below */
- __u8 data0; /* operation dependent */
- __u8 data1; /* operation dependent */
- __u8 data2; /* operation dependent */
- __u32 data3; /* operation dependent */
- __u32 data4; /* for future use */
+ __u8 operation; /* see below */
+ __u8 data0; /* operation dependent */
+ __u8 data1; /* operation dependent */
+ __u8 data2; /* operation dependent */
+ __u32 data3; /* operation dependent */
+ __u32 data4; /* for future use */
};
#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
-
#endif /* SISUSB_H */
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 8d0edc867f3..43722e5a49d 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -52,6 +52,7 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/fs.h>
+#include <linux/usb.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
return;
/* sisusb->lock is down */
-
- /* Don't need to put the character into buffer ourselves,
- * because the vt does this BEFORE calling us.
- */
-#if 0
- sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
struct sisusb_usb_data *sisusb;
ssize_t written;
int cols, length;
-#if 0
- u16 *src, *dest;
- int i;
-#endif
if (width <= 0 || height <= 0)
return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
cols = sisusb->sisusb_num_columns;
- /* Don't need to move data outselves, because
- * vt does this BEFORE calling us.
- * This is only used by vt's insert/deletechar.
- */
-#if 0
- if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
- sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
- height * width * 2);
-
- } else if (dy < sy || (dy == sy && dx < sx)) {
-
- src = SISUSB_VADDR(sx, sy);
- dest = SISUSB_VADDR(dx, dy);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src += cols;
- dest += cols;
- }
-
- } else {
-
- src = SISUSB_VADDR(sx, sy + height - 1);
- dest = SISUSB_VADDR(dx, dy + height - 1);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src -= cols;
- dest -= cols;
- }
-
- }
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
*/
if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
mutex_unlock(&sisusb->lock);
- printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
return 0;
}
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
int
sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
- int i, ret, minor = sisusb->minor;
+ int i, ret;
mutex_lock(&sisusb->lock);
@@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Set up text mode (and upload default font) */
if (sisusb_reset_text_mode(sisusb, 1)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to set up text mode\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
return 1;
}
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Allocate screen buffer */
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate screen buffer\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
return 1;
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 9b30f896281..273de5d0934 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -55,109 +55,18 @@
/* POINTER INITIALIZATION */
/*********************************************/
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
{
- SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
- SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-
- SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
- SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
- SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
- SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
-
- SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/* HELPER: Get ModeID */
-/*********************************************/
+ SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+ SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
- unsigned short ModeIndex = 0;
-
- switch (HDisplay)
- {
- case 320:
- if (VDisplay == 200)
- ModeIndex = ModeIndex_320x200[Depth];
- else if (VDisplay == 240)
- ModeIndex = ModeIndex_320x240[Depth];
- break;
- case 400:
- if (VDisplay == 300)
- ModeIndex = ModeIndex_400x300[Depth];
- break;
- case 512:
- if (VDisplay == 384)
- ModeIndex = ModeIndex_512x384[Depth];
- break;
- case 640:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_640x480[Depth];
- else if (VDisplay == 400)
- ModeIndex = ModeIndex_640x400[Depth];
- break;
- case 720:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_720x480[Depth];
- else if (VDisplay == 576)
- ModeIndex = ModeIndex_720x576[Depth];
- break;
- case 768:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_768x576[Depth];
- break;
- case 800:
- if (VDisplay == 600)
- ModeIndex = ModeIndex_800x600[Depth];
- else if (VDisplay == 480)
- ModeIndex = ModeIndex_800x480[Depth];
- break;
- case 848:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_848x480[Depth];
- break;
- case 856:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_856x480[Depth];
- break;
- case 960:
- if (VDisplay == 540)
- ModeIndex = ModeIndex_960x540[Depth];
- else if (VDisplay == 600)
- ModeIndex = ModeIndex_960x600[Depth];
- break;
- case 1024:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_1024x576[Depth];
- else if (VDisplay == 768)
- ModeIndex = ModeIndex_1024x768[Depth];
- break;
- case 1152:
- if (VDisplay == 864)
- ModeIndex = ModeIndex_1152x864[Depth];
- break;
- case 1280:
- switch (VDisplay) {
- case 720:
- ModeIndex = ModeIndex_1280x720[Depth];
- break;
- case 768:
- ModeIndex = ModeIndex_1280x768[Depth];
- break;
- case 1024:
- ModeIndex = ModeIndex_1280x1024[Depth];
- break;
- }
- }
+ SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+ SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+ SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+ SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
- return ModeIndex;
+ SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
}
-#endif /* 0 */
/*********************************************/
/* HELPER: SetReg, GetReg */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
static void
SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short data)
+ unsigned short index, unsigned short data)
{
sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
}
static void
SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short data)
+ unsigned short data)
{
sisusb_setreg(SiS_Pr->sisusb, port, data);
}
static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
{
u8 data;
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
static void
SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND,
- unsigned short DataOR)
+ unsigned short index, unsigned short DataAND,
+ unsigned short DataOR)
{
sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
}
static void
SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND)
+ unsigned short index, unsigned short DataAND)
{
sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
}
static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
- unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+ unsigned short index, unsigned short DataOR)
{
sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
}
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
/* HELPER: DisplayOn, DisplayOff */
/*********************************************/
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
{
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
}
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
/* HELPER: Init Port Addresses */
/*********************************************/
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
{
SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
/* HELPER: GetSysFlags */
/*********************************************/
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_MyCR63 = 0x63;
}
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
/* HELPER: Init PCI & Engines */
/*********************************************/
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
/* - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
/* HELPER: SET SEGMENT REGISTERS */
/*********************************************/
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
{
SiS_SetSegRegLower(SiS_Pr, value);
SiS_SetSegRegUpper(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentReg(SiS_Pr, 0);
}
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetSegmentReg(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentRegOver(SiS_Pr, 0);
}
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
{
SiS_ResetSegmentReg(SiS_Pr);
SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
static int
SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
- unsigned short *ModeIdIndex)
+ unsigned short *ModeIdIndex)
{
if ((*ModeNo) <= 0x13) {
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
} else {
- for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ (*ModeNo))
break;
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ 0xFF)
return 0;
}
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
/* HELPER: ENABLE CRT1 */
/*********************************************/
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
{
/* Enable CRT1 gating */
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
static unsigned short
SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
- static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+ static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
unsigned short modeflag;
short index;
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
index = (modeflag & ModeTypeMask) - ModeEGA;
- if (index < 0) index = 0;
+ if (index < 0)
+ index = 0;
return ColorDepth[index];
}
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static unsigned short
SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short xres, temp, colordepth, infoflag;
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
- for(i = 2; i <= 4; i++) {
- SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+ for (i = 2; i <= 4; i++) {
+ SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
}
}
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
- for(i = 0; i <= 0x18; i++) {
+ for (i = 0; i <= 0x18; i++) {
CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
}
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char ARdata;
unsigned short i;
- for(i = 0; i <= 0x13; i++) {
+ for (i = 0; i <= 0x13; i++) {
ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char GRdata;
unsigned short i;
- for(i = 0; i <= 0x08; i++) {
+ for (i = 0; i <= 0x08; i++) {
GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
}
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
/* CLEAR EXTENDED REGISTERS */
/*********************************************/
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
int i;
- for(i = 0x0A; i <= 0x0E; i++) {
+ for (i = 0x0A; i <= 0x0E; i++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
}
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
static unsigned short
SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short rrti, i, index, temp;
if (ModeNo <= 0x13)
return 0xFFFF;
- index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
- if (index > 0) index--;
+ index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+ if (index > 0)
+ index--;
rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
break;
- temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+ temp =
+ SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
if (temp < SiS_Pr->SiS_ModeType)
break;
i++;
index--;
- } while(index != 0xFFFF);
+ } while (index != 0xFFFF);
i--;
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SYNC */
/*********************************************/
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
{
unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
static void
SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
- unsigned char index;
+ unsigned char index;
unsigned short temp, i, j, modeflag;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
- for(i = 0,j = 0; i <= 7; i++, j++) {
+ for (i = 0, j = 0; i <= 7; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x10; i <= 10; i++, j++) {
+ for (j = 0x10; i <= 10; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x15; i <= 12; i++, j++) {
+ for (j = 0x15; i <= 12; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x0A; i <= 15; i++, j++) {
+ for (j = 0x0A; i <= 15; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
- if (modeflag & DoubleScanMode) temp |= 0x80;
+ if (modeflag & DoubleScanMode)
+ temp |= 0x80;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
- unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+ unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
unsigned short temp;
temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
- if (infoflag & InterlaceMode) du >>= 1;
+ if (infoflag & InterlaceMode)
+ du >>= 1;
du <<= 5;
temp = (du >> 8) & 0xff;
- if (du & 0xff) temp++;
+ if (du & 0xff)
+ temp++;
temp++;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
}
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
}
/*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short mi)
+ unsigned short mi)
{
unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short data = 0, VCLK = 0, index = 0;
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
}
- if (VCLK >= 166) data |= 0x0c;
+ if (VCLK >= 166)
+ data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short data, infoflag = 0, modeflag;
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
data |= 0x02;
data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
}
- if (infoflag & InterlaceMode) data |= 0x20;
+ if (infoflag & InterlaceMode)
+ data |= 0x20;
}
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
data = 0;
if (infoflag & InterlaceMode) {
/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
- unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
- unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+ unsigned short hrs =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+ - 3;
+ unsigned short hto =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+ + 5;
data = hrs - (hto >> 1) + 3;
}
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
- unsigned short shiftflag, unsigned short dl, unsigned short ah,
- unsigned short al, unsigned short dh)
+ unsigned short shiftflag, unsigned short dl, unsigned short ah,
+ unsigned short al, unsigned short dh)
{
unsigned short d1, d2, d3;
switch (dl) {
- case 0:
- d1 = dh; d2 = ah; d3 = al;
- break;
- case 1:
- d1 = ah; d2 = al; d3 = dh;
- break;
- default:
- d1 = al; d2 = dh; d3 = ah;
+ case 0:
+ d1 = dh;
+ d2 = ah;
+ d3 = al;
+ break;
+ case 1:
+ d1 = ah;
+ d2 = al;
+ d3 = dh;
+ break;
+ default:
+ d1 = al;
+ d2 = dh;
+ d3 = ah;
}
SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
}
static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+ unsigned short mi)
{
unsigned short data, data2, time, i, j, k, m, n, o;
unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
- for(i = 0; i < j; i++) {
+ for (i = 0; i < j; i++) {
data = table[i];
- for(k = 0; k < 3; k++) {
+ for (k = 0; k < 3; k++) {
data2 = 0;
- if (data & 0x01) data2 += 0x2A;
- if (data & 0x02) data2 += 0x15;
+ if (data & 0x01)
+ data2 += 0x2A;
+ if (data & 0x02)
+ data2 += 0x15;
SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
data >>= 2;
}
}
if (time == 256) {
- for(i = 16; i < 32; i++) {
+ for (i = 16; i < 32; i++) {
data = table[i] << sf;
- for(k = 0; k < 3; k++)
+ for (k = 0; k < 3; k++)
SiS_SetRegByte(SiS_Pr, DACData, data);
}
si = 32;
- for(m = 0; m < 9; m++) {
+ for (m = 0; m < 9; m++) {
di = si;
bx = si + 4;
- for(n = 0; n < 3; n++) {
- for(o = 0; o < 5; o++) {
+ for (n = 0; n < 3; n++) {
+ for (o = 0; o < 5; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[bx], table[si]);
+ table[di], table[bx],
+ table[si]);
si++;
}
si -= 2;
- for(o = 0; o < 3; o++) {
+ for (o = 0; o < 3; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[si], table[bx]);
+ table[di], table[si],
+ table[bx]);
si--;
}
}
- si += 5;
+ si += 5;
}
}
}
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
static void
SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short StandTableIndex, rrti;
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SiSSetMode() */
/*********************************************/
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned short ModeIdIndex;
- unsigned long BaseAddr = SiS_Pr->IOAddress;
+ unsigned long BaseAddr = SiS_Pr->IOAddress;
SiSUSB_InitPtr(SiS_Pr);
SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
ModeNo &= 0x7f;
SiS_Pr->SiS_ModeType =
- SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+ SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
SiS_Pr->SiS_SetFlag = LowModeTests;
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
return 1;
}
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
{
unsigned short ModeNo = 0;
int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
}
#endif /* INCL_SISUSB_CON */
-
-
-
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index 864bc0e9659..c46ce42d448 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -46,7 +46,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -76,21 +76,21 @@
#define CRT2Mode 0x0800
#define HalfDCLK 0x1000
#define NoSupportSimuTV 0x2000
-#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
#define DoubleScanMode 0x8000
/* Infoflag */
#define SupportTV 0x0008
#define SupportTV1024 0x0800
-#define SupportCHTV 0x0800
-#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
+#define SupportCHTV 0x0800
+#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
#define SupportHiVision 0x0010
#define SupportYPbPr750p 0x1000
#define SupportLCD 0x0020
#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */
-#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
-#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
+#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
+#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
#define InterlaceMode 0x0080
#define SyncPP 0x0000
#define SyncPN 0x4000
@@ -129,7 +129,7 @@
#define SIS_RI_856x480 19
#define SIS_RI_1280x768 20
#define SIS_RI_1400x1050 21
-#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
+#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
#define SIS_RI_848x480 23
#define SIS_RI_1360x768 24
#define SIS_RI_1024x600 25
@@ -147,691 +147,691 @@
#define SIS_CRT2_PORT_04 0x04 - 0x30
/* Mode numbers */
-static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
-static const unsigned char SiS_MDA_DAC[] =
-{
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
};
-static const unsigned char SiS_CGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_EGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
- 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
- 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
- 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
- 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
- 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
- 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+ 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+ 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+ 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+ 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+ 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+ 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_VGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
- 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
- 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
- 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
- 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
- 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
- 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
- 0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+ 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+ 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+ 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+ 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+ 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+ 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+ 0x0B, 0x0C, 0x0D, 0x0F, 0x10
};
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
- {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
- {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+ {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+ {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
- { 640,400},
- { 640,350},
- { 720,400},
- { 720,350},
- { 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+ {640, 400},
+ {640, 350},
+ {720, 400},
+ {720, 350},
+ {640, 480}
};
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
- { 320, 200, 8, 8}, /* 0x00 */
- { 320, 240, 8, 8}, /* 0x01 */
- { 320, 400, 8, 8}, /* 0x02 */
- { 400, 300, 8, 8}, /* 0x03 */
- { 512, 384, 8, 8}, /* 0x04 */
- { 640, 400, 8,16}, /* 0x05 */
- { 640, 480, 8,16}, /* 0x06 */
- { 800, 600, 8,16}, /* 0x07 */
- { 1024, 768, 8,16}, /* 0x08 */
- { 1280,1024, 8,16}, /* 0x09 */
- { 1600,1200, 8,16}, /* 0x0a */
- { 1920,1440, 8,16}, /* 0x0b */
- { 2048,1536, 8,16}, /* 0x0c */
- { 720, 480, 8,16}, /* 0x0d */
- { 720, 576, 8,16}, /* 0x0e */
- { 1280, 960, 8,16}, /* 0x0f */
- { 800, 480, 8,16}, /* 0x10 */
- { 1024, 576, 8,16}, /* 0x11 */
- { 1280, 720, 8,16}, /* 0x12 */
- { 856, 480, 8,16}, /* 0x13 */
- { 1280, 768, 8,16}, /* 0x14 */
- { 1400,1050, 8,16}, /* 0x15 */
- { 1152, 864, 8,16}, /* 0x16 */
- { 848, 480, 8,16}, /* 0x17 */
- { 1360, 768, 8,16}, /* 0x18 */
- { 1024, 600, 8,16}, /* 0x19 */
- { 1152, 768, 8,16}, /* 0x1a */
- { 768, 576, 8,16}, /* 0x1b */
- { 1360,1024, 8,16}, /* 0x1c */
- { 1680,1050, 8,16}, /* 0x1d */
- { 1280, 800, 8,16}, /* 0x1e */
- { 1920,1080, 8,16}, /* 0x1f */
- { 960, 540, 8,16}, /* 0x20 */
- { 960, 600, 8,16} /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+ {320, 200, 8, 8}, /* 0x00 */
+ {320, 240, 8, 8}, /* 0x01 */
+ {320, 400, 8, 8}, /* 0x02 */
+ {400, 300, 8, 8}, /* 0x03 */
+ {512, 384, 8, 8}, /* 0x04 */
+ {640, 400, 8, 16}, /* 0x05 */
+ {640, 480, 8, 16}, /* 0x06 */
+ {800, 600, 8, 16}, /* 0x07 */
+ {1024, 768, 8, 16}, /* 0x08 */
+ {1280, 1024, 8, 16}, /* 0x09 */
+ {1600, 1200, 8, 16}, /* 0x0a */
+ {1920, 1440, 8, 16}, /* 0x0b */
+ {2048, 1536, 8, 16}, /* 0x0c */
+ {720, 480, 8, 16}, /* 0x0d */
+ {720, 576, 8, 16}, /* 0x0e */
+ {1280, 960, 8, 16}, /* 0x0f */
+ {800, 480, 8, 16}, /* 0x10 */
+ {1024, 576, 8, 16}, /* 0x11 */
+ {1280, 720, 8, 16}, /* 0x12 */
+ {856, 480, 8, 16}, /* 0x13 */
+ {1280, 768, 8, 16}, /* 0x14 */
+ {1400, 1050, 8, 16}, /* 0x15 */
+ {1152, 864, 8, 16}, /* 0x16 */
+ {848, 480, 8, 16}, /* 0x17 */
+ {1360, 768, 8, 16}, /* 0x18 */
+ {1024, 600, 8, 16}, /* 0x19 */
+ {1152, 768, 8, 16}, /* 0x1a */
+ {768, 576, 8, 16}, /* 0x1b */
+ {1360, 1024, 8, 16}, /* 0x1c */
+ {1680, 1050, 8, 16}, /* 0x1d */
+ {1280, 800, 8, 16}, /* 0x1e */
+ {1920, 1080, 8, 16}, /* 0x1f */
+ {960, 540, 8, 16}, /* 0x20 */
+ {960, 600, 8, 16} /* 0x21 */
};
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
/* MD_3_400 - mode 0x03 - 400 */
{
- 0x50,0x18,0x10,0x1000,
- { 0x00,0x03,0x00,0x02 },
- 0x67,
- { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
- 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
- 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
- 0x0c,0x00,0x0f,0x08 },
- { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
- },
+ 0x50, 0x18, 0x10, 0x1000,
+ {0x00, 0x03, 0x00, 0x02},
+ 0x67,
+ {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+ },
/* Generic for VGA and higher */
{
- 0x00,0x00,0x00,0x0000,
- { 0x01,0x0f,0x00,0x0e },
- 0x23,
- { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
- 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
- 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- 0x01,0x00,0x00,0x00 },
- { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
- }
+ 0x00, 0x00, 0x00, 0x0000,
+ {0x01, 0x0f, 0x00, 0x0e},
+ 0x23,
+ {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+ }
};
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
- {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
- {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
- {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
- {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
- {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
- {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
- {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
- {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
- {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
- {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
- {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
- {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
- {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
- {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
- {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
- {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
- {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */
- {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */
- {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */
- {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
- {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
- {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
- {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */
- {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
- {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
- {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
- {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
- {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
- {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
- {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
- {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
- {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
- {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
- {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
- {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
- {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
- {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
- {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
- {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
- {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
- {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
- {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
- {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
- {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
- {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
- {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
- {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
- {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
- {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
- {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
- {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
- {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+ {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */
+ {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */
+ {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */
+ {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */
+ {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */
+ {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */
+ {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */
+ {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */
+ {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */
+ {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */
+ {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */
+ {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */
+ {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */
+ {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */
+ {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */
+ {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */
+ {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */
+ {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */
+ {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */
+ {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */
+ {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */
+ {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */
+ {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */
+ {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */
+ {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */
+ {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */
+ {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */
+ {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */
+ {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */
+ {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */
+ {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */
+ {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */
+ {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */
+ {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */
+ {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */
+ {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */
+ {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */
+ {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */
+ {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */
+ {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */
+ {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */
+ {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */
+ {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */
+ {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */
+ {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */
+ {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */
+ {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */
+ {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */
+ {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */
+ {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */
+ {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */
+ {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
};
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
- {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
- {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
- {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
- {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
- {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
- {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
- {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
- {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
- {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
- {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
- {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
- {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
- {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
- {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
- {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
- {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
- {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
- {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
- {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
- {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
- {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
- {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
- {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
- {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
- {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
- {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
- {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
- {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
- {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
- {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
- {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
- {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
- {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
- {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
- {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
- {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
- {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
- {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
- {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
- {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
- {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
- {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
- {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
- {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
- {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
- {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
- {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
- {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
- {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
- {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
- {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
- {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
- {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
- {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
- {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+ {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
+ {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
+ {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
+ {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
+ {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
+ {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
+ {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
+ {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
+ {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
+ {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
+ {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
+ {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
+ {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
+ {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
+ {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
+ {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
+ {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
+ {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
+ {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
+ {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
+ {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
+ {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
+ {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
+ {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
+ {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
+ {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
+ {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
+ {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
+ {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
+ {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
+ {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
+ {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
+ {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
+ {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
+ {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
+ {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
+ {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
+ {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
+ {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
+ {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
+ {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
+ {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
+ {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
+ {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
+ {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
+ {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
+ {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
+ {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */
+ {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */
+ {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */
+ {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */
+ {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
+ {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
+ {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
+ {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
};
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
- 0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
- 0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
- 0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
- 0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
- 0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
- 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
- 0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
- 0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
- 0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
- 0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
- 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
- 0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
- 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
- 0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
- 0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
- 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
- 0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
- 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
- 0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
- 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
- 0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
- 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
- 0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
- 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
- 0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
- 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
- 0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
- 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
- 0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
- 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
- 0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
- 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
- 0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
- 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
- 0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
- 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
- 0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
- 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
- 0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
- 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
- 0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
- 0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
- 0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
- 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
- 0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
- 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
- 0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
- 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
- 0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
- 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
- 0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
- 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
- 0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
- 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
- 0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
- 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
- 0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
- 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
- 0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
- 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
- 0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
- 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
- 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
- 0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
- 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
- 0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
- 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
- 0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
- 0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
- 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
- 0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
- 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
- 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
- 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
- 0x01}}, /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
- 0x00}}, /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
- 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
- 0x01}}, /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
- 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
- 0x00}}, /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
- 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
- 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
- 0x01}}, /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
- 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
- 0x01}}, /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
- 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
- 0x00}}, /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
- 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
- 0x01}}, /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
- 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
- 0x21}}, /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
- 0x20}}, /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
- 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
- 0x61}}, /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
- 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
- 0x41}}, /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
- 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
- 0x01}}, /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
- 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
- 0x41}} /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+ 0x00}}, /* 0x0 */
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x1 */
+ {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0x2 */
+ {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+ 0x01}}, /* 0x3 */
+ {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+ 0x00}}, /* 0x4 */
+ {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x5 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+ 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+ 0x00}}, /* 0x6 */
+ {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0x7 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x00}}, /* 0x8 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x61}}, /* 0x9 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xa */
+ {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xb */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+ 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0xc */
+ {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+ 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0xd */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0xe */
+ {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+ 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0xf */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x10 */
+ {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x11 */
+ {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x12 */
+ {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x13 */
+ {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x14 */
+ {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+ 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+ 0x00}}, /* 0x15 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x16 */
+ {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x17 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x18 */
+ {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x19 */
+ {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1a */
+ {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1b */
+ {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+ 0x00}}, /* 0x1c */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1d */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1e */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1f */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x20 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x21 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x22 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x23 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x24 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x25 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x26 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x27 */
+ {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x28 */
+ {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x29 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2a */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2b */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2c */
+ {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2d */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2e */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2f */
+ {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x30 */
+ {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+ 0x00}}, /* 0x31 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+ 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x32 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+ 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x33 */
+ {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+ 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x34 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+ 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x35 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+ 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x36 */
+ {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+ 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x37 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x38 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x39 */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+ 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x3a */
+ {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x3b */
+ {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x3c */
+ {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}}, /* 0x3d */
+ {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+ 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x3e */
+ {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+ 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x3f */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+ 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x40 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x41 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+ 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x42 */
+ {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+ 0x00}}, /* 0x43 */
+ {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+ 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x44 */
+ {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x45 */
+ {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+ 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+ 0x00}}, /* 0x46 */
+ {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x47 */
+ {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+ 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x48 */
+ {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+ 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x49 */
+ {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+ 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x4a */
+ {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+ 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+ 0x00}}, /* 0x4b */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x4c */
+ {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}},
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x4e */
+ {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+ 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+ 0x21}}, /* 0x4f */
+ {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+ 0x20}}, /* 0x50 */
+ {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+ 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+ 0x61}}, /* 0x51 */
+ {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+ 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+ 0x41}}, /* 0x52 */
+ {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+ 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+ 0x01}}, /* 0x53 */
+ {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+ 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+ 0x41}} /* 0x54 */
};
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
- { 0x1b,0xe1, 25}, /* 0x00 */
- { 0x4e,0xe4, 28}, /* 0x01 */
- { 0x57,0xe4, 31}, /* 0x02 */
- { 0xc3,0xc8, 36}, /* 0x03 */
- { 0x42,0xe2, 40}, /* 0x04 */
- { 0xfe,0xcd, 43}, /* 0x05 */
- { 0x5d,0xc4, 44}, /* 0x06 */
- { 0x52,0xe2, 49}, /* 0x07 */
- { 0x53,0xe2, 50}, /* 0x08 */
- { 0x74,0x67, 52}, /* 0x09 */
- { 0x6d,0x66, 56}, /* 0x0a */
- { 0x5a,0x64, 65}, /* 0x0b */
- { 0x46,0x44, 67}, /* 0x0c */
- { 0xb1,0x46, 68}, /* 0x0d */
- { 0xd3,0x4a, 72}, /* 0x0e */
- { 0x29,0x61, 75}, /* 0x0f */
- { 0x6e,0x46, 76}, /* 0x10 */
- { 0x2b,0x61, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x41,104}, /* 0x17 */
- { 0x3a,0x23,105}, /* 0x18 */
- { 0x70,0x44,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0x54,0x42,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x62,0x06,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a 301 TV */
- { 0x52,0x6a, 27}, /* 0x3b 301 TV */
- { 0x62,0x24, 70}, /* 0x3c 301 TV */
- { 0x62,0x64, 70}, /* 0x3d 301 TV */
- { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
- { 0x20,0x26, 33}, /* 0x3f 301 TV */
- { 0x31,0xc2, 39}, /* 0x40 */
- { 0x60,0x36, 30}, /* 0x41 Chrontel */
- { 0x40,0x4a, 28}, /* 0x42 Chrontel */
- { 0x9f,0x46, 44}, /* 0x43 Chrontel */
- { 0x97,0x2c, 26}, /* 0x44 */
- { 0x44,0xe4, 25}, /* 0x45 Chrontel */
- { 0x7e,0x32, 47}, /* 0x46 Chrontel */
- { 0x8a,0x24, 31}, /* 0x47 Chrontel */
- { 0x97,0x2c, 26}, /* 0x48 Chrontel */
- { 0xce,0x3c, 39}, /* 0x49 */
- { 0x52,0x4a, 36}, /* 0x4a Chrontel */
- { 0x34,0x61, 95}, /* 0x4b */
- { 0x78,0x27,108}, /* 0x4c - was 102 */
- { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
- { 0x41,0x4e, 21}, /* 0x4e */
- { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
- { 0x19,0x42, 42}, /* 0x50 */
- { 0x54,0x46, 58}, /* 0x51 Chrontel */
- { 0x25,0x42, 61}, /* 0x52 */
- { 0x44,0x44, 66}, /* 0x53 Chrontel */
- { 0x3a,0x62, 70}, /* 0x54 Chrontel */
- { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
- { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
- { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
- { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
- { 0x52,0x07,149}, /* 0x59 1280x960-85 */
- { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
- { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
- { 0x45,0x25, 83}, /* 0x5c 1280x800 */
- { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
- { 0x70,0x24,162}, /* 0x5e 1600x1200 */
- { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
- { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
- { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
- { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
- { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
- { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
- { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
- { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
- { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
- { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
- { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
- { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
- { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
- { 0x45,0x25, 83}, /* 0x6c 1280x800 */
- { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
- { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
- { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
- { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
- { 0x2b,0xc2, 35} /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+ {0x1b, 0xe1, 25}, /* 0x00 */
+ {0x4e, 0xe4, 28}, /* 0x01 */
+ {0x57, 0xe4, 31}, /* 0x02 */
+ {0xc3, 0xc8, 36}, /* 0x03 */
+ {0x42, 0xe2, 40}, /* 0x04 */
+ {0xfe, 0xcd, 43}, /* 0x05 */
+ {0x5d, 0xc4, 44}, /* 0x06 */
+ {0x52, 0xe2, 49}, /* 0x07 */
+ {0x53, 0xe2, 50}, /* 0x08 */
+ {0x74, 0x67, 52}, /* 0x09 */
+ {0x6d, 0x66, 56}, /* 0x0a */
+ {0x5a, 0x64, 65}, /* 0x0b */
+ {0x46, 0x44, 67}, /* 0x0c */
+ {0xb1, 0x46, 68}, /* 0x0d */
+ {0xd3, 0x4a, 72}, /* 0x0e */
+ {0x29, 0x61, 75}, /* 0x0f */
+ {0x6e, 0x46, 76}, /* 0x10 */
+ {0x2b, 0x61, 78}, /* 0x11 */
+ {0x31, 0x42, 79}, /* 0x12 */
+ {0xab, 0x44, 83}, /* 0x13 */
+ {0x46, 0x25, 84}, /* 0x14 */
+ {0x78, 0x29, 86}, /* 0x15 */
+ {0x62, 0x44, 94}, /* 0x16 */
+ {0x2b, 0x41, 104}, /* 0x17 */
+ {0x3a, 0x23, 105}, /* 0x18 */
+ {0x70, 0x44, 108}, /* 0x19 */
+ {0x3c, 0x23, 109}, /* 0x1a */
+ {0x5e, 0x43, 113}, /* 0x1b */
+ {0xbc, 0x44, 116}, /* 0x1c */
+ {0xe0, 0x46, 132}, /* 0x1d */
+ {0x54, 0x42, 135}, /* 0x1e */
+ {0xea, 0x2a, 139}, /* 0x1f */
+ {0x41, 0x22, 157}, /* 0x20 */
+ {0x70, 0x24, 162}, /* 0x21 */
+ {0x30, 0x21, 175}, /* 0x22 */
+ {0x4e, 0x22, 189}, /* 0x23 */
+ {0xde, 0x26, 194}, /* 0x24 */
+ {0x62, 0x06, 202}, /* 0x25 */
+ {0x3f, 0x03, 229}, /* 0x26 */
+ {0xb8, 0x06, 234}, /* 0x27 */
+ {0x34, 0x02, 253}, /* 0x28 */
+ {0x58, 0x04, 255}, /* 0x29 */
+ {0x24, 0x01, 265}, /* 0x2a */
+ {0x9b, 0x02, 267}, /* 0x2b */
+ {0x70, 0x05, 270}, /* 0x2c */
+ {0x25, 0x01, 272}, /* 0x2d */
+ {0x9c, 0x02, 277}, /* 0x2e */
+ {0x27, 0x01, 286}, /* 0x2f */
+ {0x3c, 0x02, 291}, /* 0x30 */
+ {0xef, 0x0a, 292}, /* 0x31 */
+ {0xf6, 0x0a, 310}, /* 0x32 */
+ {0x95, 0x01, 315}, /* 0x33 */
+ {0xf0, 0x09, 324}, /* 0x34 */
+ {0xfe, 0x0a, 331}, /* 0x35 */
+ {0xf3, 0x09, 332}, /* 0x36 */
+ {0xea, 0x08, 340}, /* 0x37 */
+ {0xe8, 0x07, 376}, /* 0x38 */
+ {0xde, 0x06, 389}, /* 0x39 */
+ {0x52, 0x2a, 54}, /* 0x3a 301 TV */
+ {0x52, 0x6a, 27}, /* 0x3b 301 TV */
+ {0x62, 0x24, 70}, /* 0x3c 301 TV */
+ {0x62, 0x64, 70}, /* 0x3d 301 TV */
+ {0xa8, 0x4c, 30}, /* 0x3e 301 TV */
+ {0x20, 0x26, 33}, /* 0x3f 301 TV */
+ {0x31, 0xc2, 39}, /* 0x40 */
+ {0x60, 0x36, 30}, /* 0x41 Chrontel */
+ {0x40, 0x4a, 28}, /* 0x42 Chrontel */
+ {0x9f, 0x46, 44}, /* 0x43 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x44 */
+ {0x44, 0xe4, 25}, /* 0x45 Chrontel */
+ {0x7e, 0x32, 47}, /* 0x46 Chrontel */
+ {0x8a, 0x24, 31}, /* 0x47 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x48 Chrontel */
+ {0xce, 0x3c, 39}, /* 0x49 */
+ {0x52, 0x4a, 36}, /* 0x4a Chrontel */
+ {0x34, 0x61, 95}, /* 0x4b */
+ {0x78, 0x27, 108}, /* 0x4c - was 102 */
+ {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
+ {0x41, 0x4e, 21}, /* 0x4e */
+ {0xa1, 0x4a, 29}, /* 0x4f Chrontel */
+ {0x19, 0x42, 42}, /* 0x50 */
+ {0x54, 0x46, 58}, /* 0x51 Chrontel */
+ {0x25, 0x42, 61}, /* 0x52 */
+ {0x44, 0x44, 66}, /* 0x53 Chrontel */
+ {0x3a, 0x62, 70}, /* 0x54 Chrontel */
+ {0x62, 0xc6, 34}, /* 0x55 848x480-60 */
+ {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+ {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */
+ {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+ {0x52, 0x07, 149}, /* 0x59 1280x960-85 */
+ {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */
+ {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */
+ {0x45, 0x25, 83}, /* 0x5c 1280x800 */
+ {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */
+ {0x70, 0x24, 162}, /* 0x5e 1600x1200 */
+ {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */
+ {0x63, 0x46, 68}, /* 0x60 1280x768_2 */
+ {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */
+ {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
+ {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+ {0x70, 0x28, 90}, /* 0x64 1152x864@60 */
+ {0x41, 0xc4, 32}, /* 0x65 848x480@60 */
+ {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */
+ {0x76, 0xe7, 27}, /* 0x67 720x480@60 */
+ {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */
+ {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+ {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */
+ {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */
+ {0x45, 0x25, 83}, /* 0x6c 1280x800 */
+ {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */
+ {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
+ {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */
+ {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
+ {0x2b, 0xc2, 35} /* 0x71 768@576@60 */
};
-int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
-extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 data);
-extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 *data);
-extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand, u8 myor);
-extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 myor);
-extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand);
void sisusb_delete(struct kref *kref);
int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
- u32 dest, int length, size_t *bytes_written);
+ u32 dest, int length, size_t * bytes_written);
int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
- u8 *arg, int cmapsz, int ch512, int dorecalc,
+ u8 * arg, int cmapsz, int ch512, int dorecalc,
struct vc_data *c, int fh, int uplock);
void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb);
void sisusb_init_concode(void);
#endif
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
index f325ecb29a6..1c4240e802c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_struct.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -44,7 +44,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -52,85 +52,78 @@
#define _SISUSB_STRUCT_H_
struct SiS_St {
- unsigned char St_ModeID;
- unsigned short St_ModeFlag;
- unsigned char St_StTableIndex;
- unsigned char St_CRT2CRTC;
- unsigned char St_ResInfo;
- unsigned char VB_StTVFlickerIndex;
- unsigned char VB_StTVEdgeIndex;
- unsigned char VB_StTVYFilterIndex;
- unsigned char St_PDC;
+ unsigned char St_ModeID;
+ unsigned short St_ModeFlag;
+ unsigned char St_StTableIndex;
+ unsigned char St_CRT2CRTC;
+ unsigned char St_ResInfo;
+ unsigned char VB_StTVFlickerIndex;
+ unsigned char VB_StTVEdgeIndex;
+ unsigned char VB_StTVYFilterIndex;
+ unsigned char St_PDC;
};
-struct SiS_StandTable
-{
- unsigned char CRT_COLS;
- unsigned char ROWS;
- unsigned char CHAR_HEIGHT;
- unsigned short CRT_LEN;
- unsigned char SR[4];
- unsigned char MISC;
- unsigned char CRTC[0x19];
- unsigned char ATTR[0x14];
- unsigned char GRC[9];
+struct SiS_StandTable {
+ unsigned char CRT_COLS;
+ unsigned char ROWS;
+ unsigned char CHAR_HEIGHT;
+ unsigned short CRT_LEN;
+ unsigned char SR[4];
+ unsigned char MISC;
+ unsigned char CRTC[0x19];
+ unsigned char ATTR[0x14];
+ unsigned char GRC[9];
};
struct SiS_StResInfo_S {
- unsigned short HTotal;
- unsigned short VTotal;
+ unsigned short HTotal;
+ unsigned short VTotal;
};
-struct SiS_Ext
-{
- unsigned char Ext_ModeID;
- unsigned short Ext_ModeFlag;
- unsigned short Ext_VESAID;
- unsigned char Ext_RESINFO;
- unsigned char VB_ExtTVFlickerIndex;
- unsigned char VB_ExtTVEdgeIndex;
- unsigned char VB_ExtTVYFilterIndex;
- unsigned char VB_ExtTVYFilterIndexROM661;
- unsigned char REFindex;
- char ROMMODEIDX661;
+struct SiS_Ext {
+ unsigned char Ext_ModeID;
+ unsigned short Ext_ModeFlag;
+ unsigned short Ext_VESAID;
+ unsigned char Ext_RESINFO;
+ unsigned char VB_ExtTVFlickerIndex;
+ unsigned char VB_ExtTVEdgeIndex;
+ unsigned char VB_ExtTVYFilterIndex;
+ unsigned char VB_ExtTVYFilterIndexROM661;
+ unsigned char REFindex;
+ char ROMMODEIDX661;
};
-struct SiS_Ext2
-{
- unsigned short Ext_InfoFlag;
- unsigned char Ext_CRT1CRTC;
- unsigned char Ext_CRTVCLK;
- unsigned char Ext_CRT2CRTC;
- unsigned char Ext_CRT2CRTC_NS;
- unsigned char ModeID;
- unsigned short XRes;
- unsigned short YRes;
- unsigned char Ext_PDC;
- unsigned char Ext_FakeCRT2CRTC;
- unsigned char Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+ unsigned short Ext_InfoFlag;
+ unsigned char Ext_CRT1CRTC;
+ unsigned char Ext_CRTVCLK;
+ unsigned char Ext_CRT2CRTC;
+ unsigned char Ext_CRT2CRTC_NS;
+ unsigned char ModeID;
+ unsigned short XRes;
+ unsigned short YRes;
+ unsigned char Ext_PDC;
+ unsigned char Ext_FakeCRT2CRTC;
+ unsigned char Ext_FakeCRT2Clk;
};
-struct SiS_CRT1Table
-{
- unsigned char CR[17];
+struct SiS_CRT1Table {
+ unsigned char CR[17];
};
-struct SiS_VCLKData
-{
- unsigned char SR2B,SR2C;
- unsigned short CLOCK;
+struct SiS_VCLKData {
+ unsigned char SR2B, SR2C;
+ unsigned short CLOCK;
};
-struct SiS_ModeResInfo
-{
- unsigned short HTotal;
- unsigned short VTotal;
- unsigned char XChar;
- unsigned char YChar;
+struct SiS_ModeResInfo {
+ unsigned short HTotal;
+ unsigned short VTotal;
+ unsigned char XChar;
+ unsigned char YChar;
};
-struct SiS_Private
-{
+struct SiS_Private {
void *sisusb;
unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
unsigned long SiS_P3da;
unsigned long SiS_Part1Port;
- unsigned char SiS_MyCR63;
- unsigned short SiS_CRT1Mode;
- unsigned short SiS_ModeType;
- unsigned short SiS_SetFlag;
-
- const struct SiS_StandTable *SiS_StandTable;
- const struct SiS_St *SiS_SModeIDTable;
- const struct SiS_Ext *SiS_EModeIDTable;
- const struct SiS_Ext2 *SiS_RefIndex;
- const struct SiS_CRT1Table *SiS_CRT1Table;
- const struct SiS_VCLKData *SiS_VCLKData;
- const struct SiS_ModeResInfo *SiS_ModeResInfo;
+ unsigned char SiS_MyCR63;
+ unsigned short SiS_CRT1Mode;
+ unsigned short SiS_ModeType;
+ unsigned short SiS_SetFlag;
+
+ const struct SiS_StandTable *SiS_StandTable;
+ const struct SiS_St *SiS_SModeIDTable;
+ const struct SiS_Ext *SiS_EModeIDTable;
+ const struct SiS_Ext2 *SiS_RefIndex;
+ const struct SiS_CRT1Table *SiS_CRT1Table;
+ const struct SiS_VCLKData *SiS_VCLKData;
+ const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif
-
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c03dfd7a9d3..f06e4e2b49d 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+static unsigned char xfer_to_pipe[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
const struct urb *urb, char ev_type)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
- }
if (urb->setup_packet == NULL)
return 'Z';
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
}
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
+ const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
unsigned long flags;
struct timeval ts;
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned char dir;
struct mon_bin_hdr *ep;
char data_tag = 0;
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length >= rp->b_size/5)
length = rp->b_size/5;
- if (usb_pipein(urb->pipe)) {
+ if (usb_urb_dir_in(urb)) {
if (ev_type == 'S') {
length = 0;
data_tag = '<';
}
+ /* Cannot rely on endpoint number in case of control ep.0 */
+ dir = USB_DIR_IN;
} else {
if (ev_type == 'C') {
length = 0;
data_tag = '>';
}
+ dir = 0;
}
if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
*/
memset(ep, 0, PKT_SIZE);
ep->type = ev_type;
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+ ep->epnum = dir | usb_endpoint_num(epd);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
- ep->status = urb->status;
+ ep->status = status;
ep->len_urb = urb_length;
ep->len_cap = length;
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
static void mon_bin_submit(void *data, struct urb *urb)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'S');
+ mon_bin_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'C');
+ mon_bin_event(rp, urb, 'C', status);
}
static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
memset(ep, 0, PKT_SIZE);
ep->type = 'E';
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+ ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+ ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index ce61d8b0fd8..b371ffd39d3 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
/*
*/
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+ int status)
{
unsigned long flags;
struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
- r->rnf_complete(r->r_data, urb);
+ r->rnf_complete(r->r_data, urb, status);
}
spin_unlock_irqrestore(&mbus->lock, flags);
}
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
{
struct mon_bus *mbus;
- mbus = ubus->mon_bus;
- if (mbus == NULL) {
- /*
- * This should not happen.
- * At this point we do not even know the bus number...
- */
- printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
- urb->pipe);
- return;
- }
-
- mon_bus_complete(mbus, urb);
- mon_bus_complete(&mon_bus0, urb);
+ if ((mbus = ubus->mon_bus) != NULL)
+ mon_bus_complete(mbus, urb, status);
+ mon_bus_complete(&mon_bus0, urb, status);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
*/
static void mon_stop(struct mon_bus *mbus)
{
- struct usb_bus *ubus = mbus->u_bus;
+ struct usb_bus *ubus;
struct list_head *p;
if (mbus == &mon_bus0) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 8f27a9e1c36..ebb04ac4857 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -50,10 +50,13 @@ struct mon_iso_desc {
struct mon_event_text {
struct list_head e_link;
int type; /* submit, complete, etc. */
- unsigned int pipe; /* Pipe */
unsigned long id; /* From pointer, most of the time */
unsigned int tstamp;
int busnum;
+ char devnum;
+ char epnum;
+ char is_in;
+ char xfertype;
int length; /* Depends on type: xfer length or act length */
int status;
int interval;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
struct urb *urb, char ev_type, struct mon_bus *mbus)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
- }
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type, struct mon_bus *mbus)
{
- int pipe = urb->pipe;
-
if (len <= 0)
return 'L';
if (len >= DATA_MAX)
len = DATA_MAX;
- if (usb_pipein(pipe)) {
+ if (ep->is_in) {
if (ev_type != 'C')
return '<';
} else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
}
static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
struct mon_event_text *ep;
unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
}
ep->type = ev_type;
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = urb->dev->bus->busnum;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
/* Collecting status makes debugging sense for submits, too */
- ep->status = urb->status;
+ ep->status = status;
- if (usb_pipeint(urb->pipe)) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
ep->interval = urb->interval;
- } else if (usb_pipeisoc(urb->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
ep->interval = urb->interval;
ep->start_frame = urb->start_frame;
ep->error_count = urb->error_count;
}
ep->numdesc = urb->number_of_packets;
- if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+ urb->number_of_packets > 0) {
if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
ndesc = ISODESC_MAX;
fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
static void mon_text_submit(void *data, struct urb *urb)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'S');
+ mon_text_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'C');
+ mon_text_event(rp, urb, 'C', status);
}
static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
}
ep->type = 'E';
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = 0;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = 0;
ep->length = 0;
ep->status = error;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
mon_text_read_head_u(rp, &ptr, ep);
if (ep->type == 'E') {
mon_text_read_statset(rp, &ptr, ep);
- } else if (usb_pipeisoc(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
mon_text_read_isostat(rp, &ptr, ep);
mon_text_read_isodesc(rp, &ptr, ep);
- } else if (usb_pipeint(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
mon_text_read_intstat(rp, &ptr, ep);
} else {
mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->devnum, ep->epnum);
}
static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%d:%03u:%u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->busnum, ep->devnum, ep->epnum);
}
static void mon_text_read_statset(struct mon_reader_text *rp,
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index f68ad6d99ad..f5d84ff8c10 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -46,7 +46,7 @@ struct mon_reader {
void (*rnf_submit)(void *data, struct urb *urb);
void (*rnf_error)(void *data, struct urb *urb, int error);
- void (*rnf_complete)(void *data, struct urb *urb);
+ void (*rnf_complete)(void *data, struct urb *urb, int status);
};
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db696f9..99fefed7791 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
To compile this driver as a module, choose M here: the
module will be called belkin_sa.
+config USB_SERIAL_CH341
+ tristate "USB Winchiphead CH341 Single Port Serial Driver"
+ depends on USB_SERIAL
+ help
+ Say Y here if you want to use a Winchiphead CH341 single port
+ USB to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ch341.
+
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976eca6b..d6fb384e52b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index c9fd486c1c7..2a8e537cb04 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index a47a24f8820..0b14aea8ebd 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
return 0;
}
+static ssize_t show_port_number(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+
+ return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
goto exit;
}
+ retval = device_create_file(dev, &dev_attr_port_number);
+ if (retval)
+ goto exit;
+
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
return -ENODEV;
}
+ device_remove_file(&port->dev, &dev_attr_port_number);
+
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->driver.owner)) {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 00000000000..6b252ceb39a
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT 1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x4348, 0x5523) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+ unsigned baud_rate;
+ u8 dtr;
+ u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+ u16 value, u16 index)
+{
+ int r;
+ dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+ (int)request, (int)value, (int)index);
+
+ r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+ return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+ u8 request, u16 value, u16 index,
+ char *buf, unsigned bufsize)
+{
+ int r;
+ dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+ (int)request, (int)value, (int)index, buf, (int)bufsize);
+
+ r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ value, index, buf, bufsize, DEFAULT_TIMEOUT);
+ return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ short a, b;
+ int r;
+
+ dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+ switch (priv->baud_rate) {
+ case 2400:
+ a = 0xd901;
+ b = 0x0038;
+ break;
+ case 4800:
+ a = 0x6402;
+ b = 0x001f;
+ break;
+ case 9600:
+ a = 0xb202;
+ b = 0x0013;
+ break;
+ case 19200:
+ a = 0xd902;
+ b = 0x000d;
+ break;
+ case 38400:
+ a = 0x6403;
+ b = 0x000a;
+ break;
+ case 115200:
+ a = 0xcc03;
+ b = 0x0008;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ r = ch341_control_out(dev, 0x9a, 0x1312, a);
+ if (!r)
+ r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+ return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+ return ch341_control_out(dev, 0xa4,
+ ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_get_status()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+ if ( r < 0)
+ goto out;
+
+ /* Not having the datasheet for the CH341, we ignore the bytes returned
+ * from the device. Return error if the device did not respond in time.
+ */
+ r = 0;
+
+out: kfree(buffer);
+ return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_configure()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* expect two bytes 0x27 0x00 */
+ r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0, 0);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect two bytes 0x56 0x00 */
+ r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+ if (r < 0)
+ goto out;
+
+ /* expect 0xff 0xee */
+ r = ch341_get_status(dev);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_handshake(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect 0x9f 0xee */
+ r = ch341_get_status(dev);
+
+out: kfree(buffer);
+ return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+ struct ch341_private *priv;
+ int r;
+
+ dbg("ch341_attach()");
+
+ /* private data */
+ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r < 0)
+ goto error;
+
+ usb_set_serial_port_data(serial->port[0], priv);
+ return 0;
+
+error: kfree(priv);
+ return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+ int r;
+
+ dbg("ch341_open()");
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_handshake(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_baudrate(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = usb_serial_generic_open(port, filp);
+
+out: return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct ch341_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty = port->tty;
+ unsigned baud_rate;
+
+ dbg("ch341_set_termios()");
+
+ if (!tty || !tty->termios)
+ return;
+
+ baud_rate = tty_get_baud_rate(tty);
+
+ switch (baud_rate) {
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 115200:
+ priv->baud_rate = baud_rate;
+ break;
+ default:
+ dbg("Rate %d not supported, using %d",
+ baud_rate, DEFAULT_BAUD_RATE);
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ }
+
+ ch341_set_baudrate(port->serial->dev, priv);
+
+ /* Unimplemented:
+ * (cflag & CSIZE) : data bits [5, 8]
+ * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+ * (cflag & CSTOPB) : stop bits [1, 2]
+ */
+}
+
+static struct usb_driver ch341_driver = {
+ .name = "ch341",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ch341-uart",
+ },
+ .id_table = id_table,
+ .usb_driver = &ch341_driver,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ch341_open,
+ .set_termios = ch341_set_termios,
+ .attach = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&ch341_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&ch341_driver);
+ if (retval)
+ usb_serial_deregister(&ch341_device);
+ return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+ usb_deregister(&ch341_driver);
+ usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 33f6ee50b8d..eb7df1835c1 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
static int debug;
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 2d045857b18..e4c248c98e8 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+ if (priv->chip_type == FT232BM ||
+ priv->chip_type == FT2232C ||
+ priv->chip_type == FT232RL) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT8U232AM:
case FT232BM:
case FT2232C:
+ case FT232RL:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4092f6dc9ef..b5194dc7d3b 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ktermios t;
-
- dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
- if (cmd == TCSETSF) {
- if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
- return -EFAULT;
-
- dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
- t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
- if (!(t.c_lflag & ICANON))
- return -EINVAL;
- }
- return -ENOIOCTLCMD;
-}
-
static struct usb_driver funsoft_driver = {
.name = "funsoft",
.probe = usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
- .ioctl = funsoft_ioctl,
};
static int __init funsoft_init(void)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 6a3a704b584..e836ad07fdb 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+ { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
kfree(port->bulk_out_buffer);
port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_in_buffer == NULL) {
+ port->bulk_out_buffer = NULL; /* prevent double free */
goto enomem;
}
port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_out_buffer == NULL) {
kfree(port->bulk_in_buffer);
+ port->bulk_in_buffer = NULL;
goto enomem;
}
port->read_urb->transfer_buffer = port->bulk_in_buffer;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5a4127e62c4..90e3216abd1 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif
}
- switch(cflag & CBAUD) {
- case B0: /* handled below */
+ switch(tty_get_baud_rate(port->tty)) {
+ case 0: /* handled below */
break;
- case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+ case 1200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b1200;
break;
- case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+ case 2400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b2400;
break;
- case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+ case 4800:
+ priv->cfg.baudrate = kl5kusb105a_sio_b4800;
break;
- case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+ case 9600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b9600;
break;
- case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+ case 19200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b19200;
break;
- case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+ case 38400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b38400;
break;
- case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+ case 57600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b57600;
break;
- case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+ case 115200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
err("KLSI USB->Serial converter:"
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02a86dbc0e9..6f224195bd2 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback( struct urb *urb );
static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.attach = kobil_startup,
.shutdown = kobil_shutdown,
.ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
- struct ktermios internal_termios;
};
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
static int kobil_open (struct usb_serial_port *port, struct file *filp)
{
- int i, result = 0;
+ int result = 0;
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
- // set up internal termios structure
- priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
- priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
- priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
- priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
- for (i=0; i<NCCS; i++) {
- priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
- }
-
// allocate memory for transfer buffer
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
return (result < 0) ? result : 0;
}
-
-static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
{
struct kobil_private * priv;
int result;
unsigned short urb_val = 0;
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
- char *settings;
- void __user *user_arg = (void __user *)arg;
+ int c_cflag = port->tty->termios->c_cflag;
+ speed_t speed;
+ void * settings;
priv = usb_get_serial_port_data(port);
- if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
- return 0;
- }
-
- switch (cmd) {
- case TCGETS: // 0x5401
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
- &priv->internal_termios))
- return -EFAULT;
- return 0;
-
- case TCSETS: // 0x5402
- if (!(port->tty->termios)) {
- dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
- return -ENOTTY;
- }
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (user_termios_to_kernel_termios(&priv->internal_termios,
- (struct ktermios __user *)arg))
- return -EFAULT;
-
- settings = kzalloc(50, GFP_KERNEL);
- if (! settings) {
- return -ENOBUFS;
- }
+ return;
- switch (priv->internal_termios.c_cflag & CBAUD) {
- case B1200:
+ switch (speed = tty_get_baud_rate(port->tty)) {
+ case 1200:
urb_val = SUSBCR_SBR_1200;
- strcat(settings, "1200 ");
break;
- case B9600:
+ case 9600:
default:
urb_val = SUSBCR_SBR_9600;
- strcat(settings, "9600 ");
break;
- }
+ }
+ urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+ settings = kzalloc(50, GFP_KERNEL);
+ if (! settings)
+ return;
- urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
- strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+ sprintf(settings, "%d ", speed);
- if (priv->internal_termios.c_cflag & PARENB) {
- if (priv->internal_termios.c_cflag & PARODD) {
- urb_val |= SUSBCR_SPASB_OddParity;
- strcat(settings, "Odd Parity");
- } else {
- urb_val |= SUSBCR_SPASB_EvenParity;
- strcat(settings, "Even Parity");
- }
+ if (c_cflag & PARENB) {
+ if (c_cflag & PARODD) {
+ urb_val |= SUSBCR_SPASB_OddParity;
+ strcat(settings, "Odd Parity");
} else {
- urb_val |= SUSBCR_SPASB_NoParity;
- strcat(settings, "No Parity");
+ urb_val |= SUSBCR_SPASB_EvenParity;
+ strcat(settings, "Even Parity");
}
- dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+ } else {
+ urb_val |= SUSBCR_SPASB_NoParity;
+ strcat(settings, "No Parity");
+ }
- result = usb_control_msg( port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0 ),
- SUSBCRequest_SetBaudRateParityAndStopBits,
- USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
- urb_val,
- 0,
- settings,
- 0,
- KOBIL_TIMEOUT
- );
+ result = usb_control_msg( port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0 ),
+ SUSBCRequest_SetBaudRateParityAndStopBits,
+ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+ urb_val,
+ 0,
+ settings,
+ 0,
+ KOBIL_TIMEOUT
+ );
+ kfree(settings);
+}
- dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
- kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct kobil_private * priv = usb_get_serial_port_data(port);
+ unsigned char *transfer_buffer;
+ int transfer_buffer_length = 8;
+ int result;
+
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+ // This device doesn't support ioctl calls
return 0;
+ switch (cmd) {
case TCFLSH: // 0x540B
transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
- if (! transfer_buffer) {
+ if (! transfer_buffer)
return -ENOBUFS;
- }
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
@@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
);
dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
kfree(transfer_buffer);
- return ((result < 0) ? -EFAULT : 0);
-
+ return (result < 0) ? -EFAULT : 0;
+ default:
+ return -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
}
-
static int __init kobil_init (void)
{
int retval;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index e08c9bb403d..0dc99f75bb0 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
}
} else {
switch (value) {
- case 300: break;
- case 600: break;
- case 1200: break;
- case 2400: break;
- case 4800: break;
- case 9600: break;
- case 19200: break;
- case 38400: break;
- case 57600: break;
- case 115200: break;
- default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
- value = 9600;
+ case 300: break;
+ case 600: break;
+ case 1200: break;
+ case 2400: break;
+ case 4800: break;
+ case 9600: break;
+ case 19200: break;
+ case 38400: break;
+ case 57600: break;
+ case 115200: break;
+ default:
+ err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+ " using default of B9600", value);
+ value = 9600;
}
return 115200/value;
}
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 64f3f66a7a3..d19861166b5 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index f9f85f56f0d..1da57fd9ea2 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index f9a71d0c102..c39bace5cbc 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -59,6 +59,7 @@
#define SIEMENS_PRODUCT_ID_SX1 0x0001
#define SIEMENS_PRODUCT_ID_X65 0x0003
#define SIEMENS_PRODUCT_ID_X75 0x0004
+#define SIEMENS_PRODUCT_ID_EF81 0x0005
#define SYNTECH_VENDOR_ID 0x0745
#define SYNTECH_PRODUCT_ID 0x0001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 51669b7622b..4e6dcc199be 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE("GPL");
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
static __u16 vendor; // no default
static __u16 product; // no default
module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = {
{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
- {MY_USB_DEVICE
- (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
- LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
// extra null entry for module
// vendor/produc parameters
{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index f98626ae75f..1f0149495fb 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -214,13 +214,13 @@ static int debug;
static int low_latency = TI_DEFAULT_LOW_LATENCY;
static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static int vendor_3410_count;
+static unsigned int vendor_3410_count;
static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static int product_3410_count;
+static unsigned int product_3410_count;
static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static int vendor_5052_count;
+static unsigned int vendor_5052_count;
static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static int product_5052_count;
+static unsigned int product_5052_count;
/* supported devices */
/* the array dimension is the number of default entries plus */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 9bf01a5efc8..4b1bd7def4a 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
+ /*
+ * This is tricky.
+ * Some drivers submit the read_urb in the
+ * handler for the write_urb or vice versa
+ * this order determines the order in which
+ * usb_kill_urb() must be used to reliably
+ * kill the URBs. As it is unknown here,
+ * both orders must be used in turn.
+ * The call below is not redundant.
+ */
+ usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
}
@@ -651,16 +662,14 @@ exit:
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
- struct list_head *p;
const struct usb_device_id *id;
- struct usb_serial_driver *t;
+ struct usb_serial_driver *drv;
/* Check if the usb id matches a known device */
- list_for_each(p, &usb_serial_driver_list) {
- t = list_entry(p, struct usb_serial_driver, driver_list);
- id = get_iface_id(t, iface);
+ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+ id = get_iface_id(drv, iface);
if (id)
- return t;
+ return drv;
}
return NULL;
@@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface,
/* END HORRIBLE HACK FOR PL2303 */
#endif
- /* found all that we need */
- dev_info(&interface->dev, "%s converter detected\n", type->description);
-
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
@@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
+ /* check that the device meets the driver's requirements */
+ if ((type->num_interrupt_in != NUM_DONT_CARE &&
+ type->num_interrupt_in != num_interrupt_in)
+ || (type->num_interrupt_out != NUM_DONT_CARE &&
+ type->num_interrupt_out != num_interrupt_out)
+ || (type->num_bulk_in != NUM_DONT_CARE &&
+ type->num_bulk_in != num_bulk_in)
+ || (type->num_bulk_out != NUM_DONT_CARE &&
+ type->num_bulk_out != num_bulk_out)) {
+ dbg("wrong number of endpoints");
+ kfree(serial);
+ return -EIO;
+ }
+
+ /* found all that we need */
+ dev_info(&interface->dev, "%s converter detected\n",
+ type->description);
+
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 30e08c0bcdc..7ee087fed91 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id
static int visor_calc_num_ports(struct usb_serial *serial);
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
static void visor_read_bulk_callback (struct urb *urb);
static void visor_read_int_callback (struct urb *urb);
@@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = {
.unthrottle = visor_unthrottle,
.attach = clie_3_5_startup,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
return -ENOIOCTLCMD;
}
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
- unsigned int cflag;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
- cflag = port->tty->termios->c_cflag;
-
- /* get the byte size */
- switch (cflag & CSIZE) {
- case CS5: dbg("%s - data bits = 5", __FUNCTION__); break;
- case CS6: dbg("%s - data bits = 6", __FUNCTION__); break;
- case CS7: dbg("%s - data bits = 7", __FUNCTION__); break;
- default:
- case CS8: dbg("%s - data bits = 8", __FUNCTION__); break;
- }
-
- /* determine the parity */
- if (cflag & PARENB)
- if (cflag & PARODD)
- dbg("%s - parity = odd", __FUNCTION__);
- else
- dbg("%s - parity = even", __FUNCTION__);
- else
- dbg("%s - parity = none", __FUNCTION__);
-
- /* figure out the stop bits requested */
- if (cflag & CSTOPB)
- dbg("%s - stop bits = 2", __FUNCTION__);
- else
- dbg("%s - stop bits = 1", __FUNCTION__);
-
-
- /* figure out the flow control settings */
- if (cflag & CRTSCTS)
- dbg("%s - RTS/CTS is enabled", __FUNCTION__);
- else
- dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-
- /* determine software flow control */
- if (I_IXOFF(port->tty))
- dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
- __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
- else
- dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
- /* get the baud rate wanted */
- dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
- return;
-}
-
-
static int __init visor_init (void)
{
int i, retval;
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 3a41740cad9..ee5b42aa536 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return (res ? -1 : 0);
}
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+ int result;
+
+ us->iobuf[0] = 0x1;
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ USB_REQ_SET_FEATURE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 0x01, 0x0, us->iobuf, 0x1, 1000);
+ US_DEBUGP("usb_control_msg performing result is %d\n", result);
+ return (result ? 0 : -1);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index e2967a4d48a..ad3ffd4236c 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us);
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 5e27297c017..17ca4d73577 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us)
unsigned char *reply = us->iobuf;
int rc;
- if (!us)
- return USB_STOR_TRANSPORT_ERROR;
-
rc = usbat_get_status(us, reply);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 323293a3e61..c646750ccc3 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -50,7 +50,7 @@
#include <linux/slab.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
@@ -580,25 +580,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Now, if we need to do the auto-sense, let's do it */
if (need_auto_sense) {
int temp_result;
- void* old_request_buffer;
- unsigned short old_sg;
- unsigned old_request_bufflen;
- unsigned char old_sc_data_direction;
- unsigned char old_cmd_len;
- unsigned char old_cmnd[MAX_COMMAND_SIZE];
- int old_resid;
+ struct scsi_eh_save ses;
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
- /* save the old command */
- memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
- old_cmd_len = srb->cmd_len;
-
- /* set the command and the LUN */
- memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
- srb->cmnd[0] = REQUEST_SENSE;
- srb->cmnd[1] = old_cmnd[1] & 0xE0;
- srb->cmnd[4] = 18;
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
/* FIXME: we must do the protocol translation here */
if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
@@ -606,36 +592,12 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
else
srb->cmd_len = 12;
- /* set the transfer direction */
- old_sc_data_direction = srb->sc_data_direction;
- srb->sc_data_direction = DMA_FROM_DEVICE;
-
- /* use the new buffer we have */
- old_request_buffer = srb->request_buffer;
- srb->request_buffer = us->sensebuf;
-
- /* set the buffer length for transfer */
- old_request_bufflen = srb->request_bufflen;
- srb->request_bufflen = US_SENSE_SIZE;
-
- /* set up for no scatter-gather use */
- old_sg = srb->use_sg;
- srb->use_sg = 0;
-
/* issue the auto-sense command */
- old_resid = srb->resid;
srb->resid = 0;
temp_result = us->transport(us->srb, us);
/* let's clean up right away */
- memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE);
- srb->resid = old_resid;
- srb->request_buffer = old_request_buffer;
- srb->request_bufflen = old_request_bufflen;
- srb->use_sg = old_sg;
- srb->sc_data_direction = old_sc_data_direction;
- srb->cmd_len = old_cmd_len;
- memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+ scsi_eh_restore_cmnd(srb, &ses);
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- auto-sense aborted\n");
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index c6b78ba815e..9b656ec427d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
/* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610,
"Nokia",
"6131",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D200",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Emil Larsson <emil@swip.net> */
UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101,
"NIKON",
@@ -355,6 +362,20 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D2Xs",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D40X",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* BENQ DC5330
* Reported by Manuel Fombuena <mfombuena@ya.com> and
* Frank Copeland <fjc@thingy.apana.org.au> */
@@ -1463,6 +1484,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 59181667066..3451e8d03ab 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf,
return -ENOMEM;
}
+ /*
+ * Allow 16-byte CDBs and thus > 2TB
+ */
+ host->max_cmd_len = 16;
us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8de11deb5d1..c815a40e167 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file)
/* save our object in the file's private structure */
file->private_data = dev;
+ mutex_unlock(&dev->io_mutex);
exit:
return retval;
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 0899fccbd57..fbea2bd129c 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -125,8 +125,8 @@ static int hp680bl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
- hp680bl_data.brightness = 0;
- hp680bl_data.power = 0;
+ bd->props.brightness = 0;
+ bd->props.power = 0;
hp680bl_send_intensity(bd);
backlight_device_unregister(bd);
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index ee9046db9c7..549891d76ef 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/fbio.h>
@@ -38,6 +37,7 @@ static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
static int cg6_sync(struct fb_info *);
static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
/*
* Frame buffer operations
@@ -48,7 +48,7 @@ static struct fb_ops cg6_ops = {
.fb_setcolreg = cg6_setcolreg,
.fb_blank = cg6_blank,
.fb_fillrect = cg6_fillrect,
- .fb_copyarea = cfb_copyarea,
+ .fb_copyarea = cg6_copyarea,
.fb_imageblit = cg6_imageblit,
.fb_sync = cg6_sync,
.fb_mmap = cg6_mmap,
@@ -65,41 +65,41 @@ static struct fb_ops cg6_ops = {
* The FBC could be the frame buffer control
* The FHC could is the frame buffer hardware control.
*/
-#define CG6_ROM_OFFSET 0x0UL
-#define CG6_BROOKTREE_OFFSET 0x200000UL
-#define CG6_DHC_OFFSET 0x240000UL
-#define CG6_ALT_OFFSET 0x280000UL
-#define CG6_FHC_OFFSET 0x300000UL
-#define CG6_THC_OFFSET 0x301000UL
-#define CG6_FBC_OFFSET 0x700000UL
-#define CG6_TEC_OFFSET 0x701000UL
-#define CG6_RAM_OFFSET 0x800000UL
+#define CG6_ROM_OFFSET 0x0UL
+#define CG6_BROOKTREE_OFFSET 0x200000UL
+#define CG6_DHC_OFFSET 0x240000UL
+#define CG6_ALT_OFFSET 0x280000UL
+#define CG6_FHC_OFFSET 0x300000UL
+#define CG6_THC_OFFSET 0x301000UL
+#define CG6_FBC_OFFSET 0x700000UL
+#define CG6_TEC_OFFSET 0x701000UL
+#define CG6_RAM_OFFSET 0x800000UL
/* FHC definitions */
-#define CG6_FHC_FBID_SHIFT 24
-#define CG6_FHC_FBID_MASK 255
-#define CG6_FHC_REV_SHIFT 20
-#define CG6_FHC_REV_MASK 15
-#define CG6_FHC_FROP_DISABLE (1 << 19)
-#define CG6_FHC_ROW_DISABLE (1 << 18)
-#define CG6_FHC_SRC_DISABLE (1 << 17)
-#define CG6_FHC_DST_DISABLE (1 << 16)
-#define CG6_FHC_RESET (1 << 15)
-#define CG6_FHC_LITTLE_ENDIAN (1 << 13)
-#define CG6_FHC_RES_MASK (3 << 11)
-#define CG6_FHC_1024 (0 << 11)
-#define CG6_FHC_1152 (1 << 11)
-#define CG6_FHC_1280 (2 << 11)
-#define CG6_FHC_1600 (3 << 11)
-#define CG6_FHC_CPU_MASK (3 << 9)
-#define CG6_FHC_CPU_SPARC (0 << 9)
-#define CG6_FHC_CPU_68020 (1 << 9)
-#define CG6_FHC_CPU_386 (2 << 9)
-#define CG6_FHC_TEST (1 << 8)
-#define CG6_FHC_TEST_X_SHIFT 4
-#define CG6_FHC_TEST_X_MASK 15
-#define CG6_FHC_TEST_Y_SHIFT 0
-#define CG6_FHC_TEST_Y_MASK 15
+#define CG6_FHC_FBID_SHIFT 24
+#define CG6_FHC_FBID_MASK 255
+#define CG6_FHC_REV_SHIFT 20
+#define CG6_FHC_REV_MASK 15
+#define CG6_FHC_FROP_DISABLE (1 << 19)
+#define CG6_FHC_ROW_DISABLE (1 << 18)
+#define CG6_FHC_SRC_DISABLE (1 << 17)
+#define CG6_FHC_DST_DISABLE (1 << 16)
+#define CG6_FHC_RESET (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN (1 << 13)
+#define CG6_FHC_RES_MASK (3 << 11)
+#define CG6_FHC_1024 (0 << 11)
+#define CG6_FHC_1152 (1 << 11)
+#define CG6_FHC_1280 (2 << 11)
+#define CG6_FHC_1600 (3 << 11)
+#define CG6_FHC_CPU_MASK (3 << 9)
+#define CG6_FHC_CPU_SPARC (0 << 9)
+#define CG6_FHC_CPU_68020 (1 << 9)
+#define CG6_FHC_CPU_386 (2 << 9)
+#define CG6_FHC_TEST (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT 4
+#define CG6_FHC_TEST_X_MASK 15
+#define CG6_FHC_TEST_Y_SHIFT 0
+#define CG6_FHC_TEST_Y_MASK 15
/* FBC mode definitions */
#define CG6_FBC_BLIT_IGNORE 0x00000000
@@ -150,17 +150,17 @@ static struct fb_ops cg6_ops = {
#define CG6_FBC_INDEX_MASK 0x00000030
/* THC definitions */
-#define CG6_THC_MISC_REV_SHIFT 16
-#define CG6_THC_MISC_REV_MASK 15
-#define CG6_THC_MISC_RESET (1 << 12)
-#define CG6_THC_MISC_VIDEO (1 << 10)
-#define CG6_THC_MISC_SYNC (1 << 9)
-#define CG6_THC_MISC_VSYNC (1 << 8)
-#define CG6_THC_MISC_SYNC_ENAB (1 << 7)
-#define CG6_THC_MISC_CURS_RES (1 << 6)
-#define CG6_THC_MISC_INT_ENAB (1 << 5)
-#define CG6_THC_MISC_INT (1 << 4)
-#define CG6_THC_MISC_INIT 0x9f
+#define CG6_THC_MISC_REV_SHIFT 16
+#define CG6_THC_MISC_REV_MASK 15
+#define CG6_THC_MISC_RESET (1 << 12)
+#define CG6_THC_MISC_VIDEO (1 << 10)
+#define CG6_THC_MISC_SYNC (1 << 9)
+#define CG6_THC_MISC_VSYNC (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB (1 << 7)
+#define CG6_THC_MISC_CURS_RES (1 << 6)
+#define CG6_THC_MISC_INT_ENAB (1 << 5)
+#define CG6_THC_MISC_INT (1 << 4)
+#define CG6_THC_MISC_INIT 0x9f
/* The contents are unknown */
struct cg6_tec {
@@ -170,25 +170,25 @@ struct cg6_tec {
};
struct cg6_thc {
- u32 thc_pad0[512];
- u32 thc_hs; /* hsync timing */
- u32 thc_hsdvs;
- u32 thc_hd;
- u32 thc_vs; /* vsync timing */
- u32 thc_vd;
- u32 thc_refresh;
- u32 thc_misc;
- u32 thc_pad1[56];
- u32 thc_cursxy; /* cursor x,y position (16 bits each) */
- u32 thc_cursmask[32]; /* cursor mask bits */
- u32 thc_cursbits[32]; /* what to show where mask enabled */
+ u32 thc_pad0[512];
+ u32 thc_hs; /* hsync timing */
+ u32 thc_hsdvs;
+ u32 thc_hd;
+ u32 thc_vs; /* vsync timing */
+ u32 thc_vd;
+ u32 thc_refresh;
+ u32 thc_misc;
+ u32 thc_pad1[56];
+ u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ u32 thc_cursmask[32]; /* cursor mask bits */
+ u32 thc_cursbits[32]; /* what to show where mask enabled */
};
struct cg6_fbc {
u32 xxx0[1];
u32 mode;
u32 clip;
- u32 xxx1[1];
+ u32 xxx1[1];
u32 s;
u32 draw;
u32 blit;
@@ -243,10 +243,10 @@ struct cg6_fbc {
};
struct bt_regs {
- u32 addr;
- u32 color_map;
- u32 control;
- u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
struct cg6_par {
@@ -267,7 +267,7 @@ struct cg6_par {
static int cg6_sync(struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
int limit = 10000;
@@ -281,24 +281,24 @@ static int cg6_sync(struct fb_info *info)
}
/**
- * cg6_fillrect - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Draws a rectangle on the screen.
+ * cg6_fillrect - Draws a rectangle on the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @rect: structure defining the rectagle and operation.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @rect: structure defining the rectagle and operation.
*/
static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
unsigned long flags;
s32 val;
- /* XXX doesn't handle ROP_XOR */
+ /* CG6 doesn't handle ROP_XOR */
spin_lock_irqsave(&par->lock, flags);
+
cg6_sync(info);
+
sbus_writel(rect->color, &fbc->fg);
sbus_writel(~(u32)0, &fbc->pixelm);
sbus_writel(0xea80ff00, &fbc->alu);
@@ -316,16 +316,56 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
}
/**
- * cg6_imageblit - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies a image from system memory to the screen.
+ * cg6_copyarea - Copies one area of the screen to another area.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @area: Structure providing the data to copy the framebuffer contents
+ * from one region to another.
+ *
+ * This drawing operation copies a rectangular area from one area of the
+ * screen to another area.
+ */
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct cg6_par *par = (struct cg6_par *)info->par;
+ struct cg6_fbc __iomem *fbc = par->fbc;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ cg6_sync(info);
+
+ sbus_writel(0xff, &fbc->fg);
+ sbus_writel(0x00, &fbc->bg);
+ sbus_writel(~0, &fbc->pixelm);
+ sbus_writel(0xe880cccc, &fbc->alu);
+ sbus_writel(0, &fbc->s);
+ sbus_writel(0, &fbc->clip);
+
+ sbus_writel(area->sy, &fbc->y0);
+ sbus_writel(area->sx, &fbc->x0);
+ sbus_writel(area->sy + area->height - 1, &fbc->y1);
+ sbus_writel(area->sx + area->width - 1, &fbc->x1);
+ sbus_writel(area->dy, &fbc->y2);
+ sbus_writel(area->dx, &fbc->x2);
+ sbus_writel(area->dy + area->height - 1, &fbc->y3);
+ sbus_writel(area->dx + area->width - 1, &fbc->x3);
+ do {
+ i = sbus_readl(&fbc->blit);
+ } while (i < 0 && (i & 0x20000000));
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * cg6_imageblit - Copies a image from system memory to the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @image: structure defining the image.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
*/
static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
const u8 *data = image->data;
unsigned long flags;
@@ -363,7 +403,7 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
sbus_writel(y, &fbc->y0);
sbus_writel(x, &fbc->x0);
sbus_writel(x + 32 - 1, &fbc->x1);
-
+
val = ((u32)data[0] << 24) |
((u32)data[1] << 16) |
((u32)data[2] << 8) |
@@ -404,19 +444,20 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
}
/**
- * cg6_setcolreg - Optional function. Sets a color register.
- * @regno: boolean, 0 copy local, 1 get_user() function
- * @red: frame buffer colormap structure
- * @green: The green value which can be up to 16 bits wide
- * @blue: The blue value which can be up to 16 bits wide.
- * @transp: If supported the alpha value which can be up to 16 bits wide.
- * @info: frame buffer info structure
+ * cg6_setcolreg - Sets a color register.
+ *
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
*/
static int cg6_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct bt_regs __iomem *bt = par->bt;
unsigned long flags;
@@ -440,25 +481,24 @@ static int cg6_setcolreg(unsigned regno,
}
/**
- * cg6_blank - Optional function. Blanks the display.
- * @blank_mode: the blank mode we want.
- * @info: frame buffer structure that represents a single frame buffer
+ * cg6_blank - Blanks the display.
+ *
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
*/
-static int
-cg6_blank(int blank, struct fb_info *info)
+static int cg6_blank(int blank, struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_thc __iomem *thc = par->thc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&par->lock, flags);
+ val = sbus_readl(&thc->thc_misc);
switch (blank) {
case FB_BLANK_UNBLANK: /* Unblanking */
- val = sbus_readl(&thc->thc_misc);
val |= CG6_THC_MISC_VIDEO;
- sbus_writel(val, &thc->thc_misc);
par->flags &= ~CG6_FLAG_BLANKED;
break;
@@ -466,13 +506,12 @@ cg6_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
case FB_BLANK_POWERDOWN: /* Poweroff */
- val = sbus_readl(&thc->thc_misc);
val &= ~CG6_THC_MISC_VIDEO;
- sbus_writel(val, &thc->thc_misc);
par->flags |= CG6_FLAG_BLANKED;
break;
}
+ sbus_writel(val, &thc->thc_misc);
spin_unlock_irqrestore(&par->lock, flags);
return 0;
@@ -533,7 +572,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
return sbusfb_ioctl_helper(cmd, arg, info,
FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
@@ -543,15 +582,14 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-cg6_init_fix(struct fb_info *info, int linebytes)
+static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
{
struct cg6_par *par = (struct cg6_par *)info->par;
const char *cg6_cpu_name, *cg6_card_name;
u32 conf;
conf = sbus_readl(par->fhc);
- switch(conf & CG6_FHC_CPU_MASK) {
+ switch (conf & CG6_FHC_CPU_MASK) {
case CG6_FHC_CPU_SPARC:
cg6_cpu_name = "sparc";
break;
@@ -563,21 +601,19 @@ cg6_init_fix(struct fb_info *info, int linebytes)
break;
};
if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
- if (par->fbsize <= 0x100000) {
+ if (par->fbsize <= 0x100000)
cg6_card_name = "TGX";
- } else {
+ else
cg6_card_name = "TGX+";
- }
} else {
- if (par->fbsize <= 0x100000) {
+ if (par->fbsize <= 0x100000)
cg6_card_name = "GX";
- } else {
+ else
cg6_card_name = "GX+";
- }
}
sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
- info->fix.id[sizeof(info->fix.id)-1] = 0;
+ info->fix.id[sizeof(info->fix.id) - 1] = 0;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -588,28 +624,28 @@ cg6_init_fix(struct fb_info *info, int linebytes)
}
/* Initialize Brooktree DAC */
-static void cg6_bt_init(struct cg6_par *par)
+static void __devinit cg6_bt_init(struct cg6_par *par)
{
struct bt_regs __iomem *bt = par->bt;
- sbus_writel(0x04 << 24, &bt->addr); /* color planes */
+ sbus_writel(0x04 << 24, &bt->addr); /* color planes */
sbus_writel(0xff << 24, &bt->control);
sbus_writel(0x05 << 24, &bt->addr);
sbus_writel(0x00 << 24, &bt->control);
- sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */
+ sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */
sbus_writel(0x73 << 24, &bt->control);
sbus_writel(0x07 << 24, &bt->addr);
sbus_writel(0x00 << 24, &bt->control);
}
-static void cg6_chip_init(struct fb_info *info)
+static void __devinit cg6_chip_init(struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_tec __iomem *tec = par->tec;
struct cg6_fbc __iomem *fbc = par->fbc;
u32 rev, conf, mode;
int i;
-
+
/* Turn off stuff in the Transform Engine. */
sbus_writel(0, &tec->tec_matrix);
sbus_writel(0, &tec->tec_clip);
@@ -635,13 +671,13 @@ static void cg6_chip_init(struct fb_info *info)
i = sbus_readl(&fbc->s);
} while (i & 0x10000000);
mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
- CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
- CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
- CG6_FBC_BDISP_MASK);
+ CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+ CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+ CG6_FBC_BDISP_MASK);
mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
- CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
- CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
- CG6_FBC_BDISP_0);
+ CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+ CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+ CG6_FBC_BDISP_0);
sbus_writel(mode, &fbc->mode);
sbus_writel(0, &fbc->clip);
@@ -671,7 +707,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
}
-static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cg6_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct fb_info *info;
@@ -705,22 +742,23 @@ static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *
par->fbsize *= 4;
par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
- 4096, "cgsix fbc");
+ 4096, "cgsix fbc");
par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
- sizeof(struct cg6_tec), "cgsix tec");
+ sizeof(struct cg6_tec), "cgsix tec");
par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
- sizeof(struct cg6_thc), "cgsix thc");
+ sizeof(struct cg6_thc), "cgsix thc");
par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
- sizeof(struct bt_regs), "cgsix dac");
+ sizeof(struct bt_regs), "cgsix dac");
par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
- sizeof(u32), "cgsix fhc");
+ sizeof(u32), "cgsix fhc");
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
- FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+ FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+ FBINFO_READS_FAST;
info->fbops = &cg6_ops;
- info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
- par->fbsize, "cgsix ram");
+ info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+ par->fbsize, "cgsix ram");
if (!par->fbc || !par->tec || !par->thc ||
!par->bt || !par->fhc || !info->screen_base)
goto out_unmap_regs;
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 4b520b57391..d7e24889650 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -171,17 +171,17 @@ static struct fb_ops ffb_ops = {
#define FFB_PPC_CS_VAR 0x000002
#define FFB_PPC_CS_CONST 0x000003
-#define FFB_ROP_NEW 0x83
-#define FFB_ROP_OLD 0x85
-#define FFB_ROP_NEW_XOR_OLD 0x86
-
-#define FFB_UCSR_FIFO_MASK 0x00000fff
-#define FFB_UCSR_FB_BUSY 0x01000000
-#define FFB_UCSR_RP_BUSY 0x02000000
-#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
-#define FFB_UCSR_READ_ERR 0x40000000
-#define FFB_UCSR_FIFO_OVFL 0x80000000
-#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+#define FFB_ROP_NEW 0x83
+#define FFB_ROP_OLD 0x85
+#define FFB_ROP_NEW_XOR_OLD 0x86
+
+#define FFB_UCSR_FIFO_MASK 0x00000fff
+#define FFB_UCSR_FB_BUSY 0x01000000
+#define FFB_UCSR_RP_BUSY 0x02000000
+#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR 0x40000000
+#define FFB_UCSR_FIFO_OVFL 0x80000000
+#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
struct ffb_fbc {
/* Next vertex registers */
@@ -197,7 +197,7 @@ struct ffb_fbc {
u32 ryf;
u32 rxf;
u32 xxx3[2];
-
+
u32 dmyf;
u32 dmxf;
u32 xxx4[2];
@@ -211,13 +211,13 @@ struct ffb_fbc {
u32 bh;
u32 bw;
u32 xxx6[2];
-
+
u32 xxx7[32];
-
+
/* Setup unit vertex state register */
u32 suvtx;
u32 xxx8[63];
-
+
/* Control registers */
u32 ppc;
u32 wid;
@@ -235,7 +235,7 @@ struct ffb_fbc {
u32 dcsb;
u32 dczf;
u32 dczb;
-
+
u32 xxx9;
u32 blendc;
u32 blendc1;
@@ -252,7 +252,7 @@ struct ffb_fbc {
u32 fbcfg1;
u32 fbcfg2;
u32 fbcfg3;
-
+
u32 ppcfg;
u32 pick;
u32 fillmode;
@@ -269,7 +269,7 @@ struct ffb_fbc {
u32 clip2max;
u32 clip3min;
u32 clip3max;
-
+
/* New 3dRAM III support regs */
u32 rawblend2;
u32 rawpreblend;
@@ -287,7 +287,7 @@ struct ffb_fbc {
u32 rawcmp;
u32 rawwac;
u32 fbramid;
-
+
u32 drawop;
u32 xxx10[2];
u32 fontlpat;
@@ -302,7 +302,7 @@ struct ffb_fbc {
u32 stencil;
u32 stencilctl;
- u32 xxx13[4];
+ u32 xxx13[4];
u32 dcss1;
u32 dcss2;
u32 dcss3;
@@ -315,17 +315,17 @@ struct ffb_fbc {
u32 dcd3;
u32 dcd4;
u32 xxx15;
-
+
u32 pattern[32];
-
+
u32 xxx16[256];
-
+
u32 devid;
u32 xxx17[63];
-
+
u32 ucsr;
u32 xxx18[31];
-
+
u32 mer;
};
@@ -336,20 +336,20 @@ struct ffb_dac {
u32 value2;
};
-#define FFB_DAC_UCTRL 0x1001 /* User Control */
-#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
-#define FFB_DAC_UCTRL_MANREV_SHIFT 8
-#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
-#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */
-#define FFB_DAC_DID 0x8000 /* Device Identification */
-#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */
-#define FFB_DAC_DID_PNUM_SHIFT 12
-#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */
-#define FFB_DAC_DID_REV_SHIFT 28
+#define FFB_DAC_UCTRL 0x1001 /* User Control */
+#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
+#define FFB_DAC_UCTRL_MANREV_SHIFT 8
+#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
+#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */
+#define FFB_DAC_DID 0x8000 /* Device Identification */
+#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */
+#define FFB_DAC_DID_PNUM_SHIFT 12
+#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */
+#define FFB_DAC_DID_REV_SHIFT 28
#define FFB_DAC_CUR_CTRL 0x100
-#define FFB_DAC_CUR_CTRL_P0 0x00000001
-#define FFB_DAC_CUR_CTRL_P1 0x00000002
+#define FFB_DAC_CUR_CTRL_P0 0x00000001
+#define FFB_DAC_CUR_CTRL_P1 0x00000002
struct ffb_par {
spinlock_t lock;
@@ -382,7 +382,9 @@ static void FFBFifo(struct ffb_par *par, int n)
if (cache - n < 0) {
fbc = par->fbc;
- do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+ do {
+ cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);
+ cache -= 8;
} while (cache - n < 0);
}
par->fifo_cache = cache - n;
@@ -401,12 +403,12 @@ static void FFBWait(struct ffb_par *par)
upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
}
udelay(10);
- } while(--limit > 0);
+ } while (--limit > 0);
}
static int ffb_sync(struct fb_info *p)
{
- struct ffb_par *par = (struct ffb_par *) p->par;
+ struct ffb_par *par = (struct ffb_par *)p->par;
FFBWait(par);
return 0;
@@ -431,8 +433,8 @@ static void ffb_switch_from_graph(struct ffb_par *par)
FFBWait(par);
par->fifo_cache = 0;
FFBFifo(par, 7);
- upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
- FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+ upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |
+ FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
&fbc->ppc);
upa_writel(0x2000707f, &fbc->fbc);
upa_writel(par->rop_cache, &fbc->rop);
@@ -455,7 +457,7 @@ static void ffb_switch_from_graph(struct ffb_par *par)
static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
/* We just use this to catch switches out of
* graphics mode.
@@ -468,16 +470,14 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
/**
- * ffb_fillrect - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Draws a rectangle on the screen.
+ * ffb_fillrect - Draws a rectangle on the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @rect: structure defining the rectagle and operation.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @rect: structure defining the rectagle and operation.
*/
static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
u32 fg;
@@ -494,9 +494,9 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
par->fg_cache = fg;
}
- ffb_rop(par, (rect->rop == ROP_COPY ?
- FFB_ROP_NEW :
- FFB_ROP_NEW_XOR_OLD));
+ ffb_rop(par, rect->rop == ROP_COPY ?
+ FFB_ROP_NEW :
+ FFB_ROP_NEW_XOR_OLD);
FFBFifo(par, 5);
upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
@@ -509,18 +509,15 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
}
/**
- * ffb_copyarea - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies on area of the screen to another area.
+ * ffb_copyarea - Copies on area of the screen to another area.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @area: structure defining the source and destination.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @area: structure defining the source and destination.
*/
-static void
-ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
@@ -547,16 +544,14 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
}
/**
- * ffb_imageblit - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies a image from system memory to the screen.
+ * ffb_imageblit - Copies a image from system memory to the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @image: structure defining the image.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
*/
static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
const u8 *data = image->data;
unsigned long flags;
@@ -644,13 +639,14 @@ static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
}
/**
- * ffb_setcolreg - Optional function. Sets a color register.
- * @regno: boolean, 0 copy local, 1 get_user() function
- * @red: frame buffer colormap structure
- * @green: The green value which can be up to 16 bits wide
- * @blue: The blue value which can be up to 16 bits wide.
- * @transp: If supported the alpha value which can be up to 16 bits wide.
- * @info: frame buffer info structure
+ * ffb_setcolreg - Sets a color register.
+ *
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
*/
static int ffb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
@@ -672,14 +668,13 @@ static int ffb_setcolreg(unsigned regno,
}
/**
- * ffb_blank - Optional function. Blanks the display.
- * @blank_mode: the blank mode we want.
- * @info: frame buffer structure that represents a single frame buffer
+ * ffb_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
*/
-static int
-ffb_blank(int blank, struct fb_info *info)
+static int ffb_blank(int blank, struct fb_info *info)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_dac __iomem *dac = par->dac;
unsigned long flags;
u32 val;
@@ -867,7 +862,7 @@ static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
return sbusfb_ioctl_helper(cmd, arg, info,
FBTYPE_CREATOR, 24, par->fbsize);
@@ -877,8 +872,7 @@ static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-ffb_init_fix(struct fb_info *info)
+static void ffb_init_fix(struct fb_info *info)
{
struct ffb_par *par = (struct ffb_par *)info->par;
const char *ffb_type_name;
@@ -902,7 +896,8 @@ ffb_init_fix(struct fb_info *info)
info->fix.accel = FB_ACCEL_SUN_CREATOR;
}
-static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit ffb_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct ffb_fbc __iomem *fbc;
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 1473f2c892d..f2df5519c9c 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
ssize_t ret_size = 0;
struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf)
return ret_size;
}
-static ssize_t video_output_store_state(struct class_device *dev,
- const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,size_t count)
{
char *endp;
struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev,
return count;
}
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
{
struct output_device *od = to_output_device(dev);
kfree(od);
}
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
__ATTR(state, 0644, video_output_show_state, video_output_store_state),
__ATTR_NULL,
};
+
static struct class video_output_class = {
.name = "video_output",
- .release = video_output_class_release,
- .class_dev_attrs = video_output_attributes,
+ .dev_release = video_output_release,
+ .dev_attrs = video_output_attributes,
};
struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name,
goto error_return;
}
new_dev->props = op;
- new_dev->class_dev.class = &video_output_class;
- new_dev->class_dev.dev = dev;
- strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
- class_set_devdata(&new_dev->class_dev,devdata);
- ret_code = class_device_register(&new_dev->class_dev);
+ new_dev->dev.class = &video_output_class;
+ new_dev->dev.parent = dev;
+ strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_dev->dev, devdata);
+ ret_code = device_register(&new_dev->dev);
if (ret_code) {
kfree(new_dev);
goto error_return;
@@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev)
{
if (!dev)
return;
- class_device_unregister(&dev->class_dev);
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL(video_output_unregister);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 7d6c29800d1..06805c9b237 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -667,6 +667,8 @@ static int pvr2_init_cable(void)
related */
if (cable_type == CT_COMPOSITE)
fb_writel(3 << 8, VOUTC);
+ else if (cable_type == CT_RGB)
+ fb_writel(1 << 9, VOUTC);
else
fb_writel(0, VOUTC);
@@ -890,7 +892,7 @@ static int __init pvr2fb_dc_init(void)
pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */
pvr2_fix.mmio_len = 0x2000;
- if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+ if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED,
"pvr2 VBL handler", fb_info)) {
return -EBUSY;
}
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 6ef99b2d13c..e38d3b7c3ad 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -84,7 +84,7 @@ static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
.xres = 640,
.yres = 480,
.xvirt = 1024,
- .yvirt = 480;
+ .yvirt = 480,
};
/*
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index a593f900eff..070217322c9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -197,7 +197,7 @@ static struct w1_family w1_default_family = {
.fops = &w1_default_fops,
};
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
static struct bus_type w1_bus_type = {
.name = "w1",
@@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master)
}
#ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct w1_master *md = NULL;
struct w1_slave *sl = NULL;
char *event_owner, *name;
- int err, cur_index=0, cur_len=0;
+ int err;
if (dev->driver == &w1_master_driver) {
md = container_of(dev, struct w1_master, dev);
@@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp,
if (dev->driver != &w1_slave_driver || !sl)
return 0;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_FID=%02X", sl->reg_num.family);
+ err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
if (err)
return err;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_SLAVE_ID=%024LX",
- (unsigned long long)sl->reg_num.id);
- envp[cur_index] = NULL;
+ err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+ (unsigned long long)sl->reg_num.id);
if (err)
return err;
return 0;
};
#else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return 0;
}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 2a40c2946d0..716691689fd 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -105,7 +105,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
/* No mandatory locks */
- if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ if (__mandatory_lock(inode))
return -ENOLCK;
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
diff --git a/fs/Kconfig b/fs/Kconfig
index f9eed6d7906..815d201d860 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1225,6 +1225,14 @@ config JFFS2_FS_WRITEBUFFER
- NOR flash with transparent ECC
- DataFlash
+config JFFS2_FS_WBUF_VERIFY
+ bool "Verify JFFS2 write-buffer reads"
+ depends on JFFS2_FS_WRITEBUFFER
+ default n
+ help
+ This causes JFFS2 to read back every page written through the
+ write-buffer, and check for errors.
+
config JFFS2_SUMMARY
bool "JFFS2 summary support (EXPERIMENTAL)"
depends on JFFS2_FS && EXPERIMENTAL
@@ -1295,52 +1303,71 @@ config JFFS2_ZLIB
select ZLIB_DEFLATE
depends on JFFS2_FS
default y
- help
- Zlib is designed to be a free, general-purpose, legally unencumbered,
- lossless data-compression library for use on virtually any computer
- hardware and operating system. See <http://www.gzip.org/zlib/> for
- further information.
+ help
+ Zlib is designed to be a free, general-purpose, legally unencumbered,
+ lossless data-compression library for use on virtually any computer
+ hardware and operating system. See <http://www.gzip.org/zlib/> for
+ further information.
+
+ Say 'Y' if unsure.
+
+config JFFS2_LZO
+ bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+ depends on JFFS2_FS
+ default n
+ help
+ minilzo-based compression. Generally works better than Zlib.
- Say 'Y' if unsure.
+ This feature was added in July, 2007. Say 'N' if you need
+ compatibility with older bootloaders or kernels.
config JFFS2_RTIME
bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
depends on JFFS2_FS
default y
- help
- Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+ help
+ Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
config JFFS2_RUBIN
bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
depends on JFFS2_FS
default n
- help
- RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+ help
+ RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
choice
- prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
- default JFFS2_CMODE_PRIORITY
- depends on JFFS2_FS
- help
- You can set here the default compression mode of JFFS2 from
- the available compression modes. Don't touch if unsure.
+ prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
+ default JFFS2_CMODE_PRIORITY
+ depends on JFFS2_FS
+ help
+ You can set here the default compression mode of JFFS2 from
+ the available compression modes. Don't touch if unsure.
config JFFS2_CMODE_NONE
- bool "no compression"
- help
- Uses no compression.
+ bool "no compression"
+ help
+ Uses no compression.
config JFFS2_CMODE_PRIORITY
- bool "priority"
- help
- Tries the compressors in a predefined order and chooses the first
- successful one.
+ bool "priority"
+ help
+ Tries the compressors in a predefined order and chooses the first
+ successful one.
config JFFS2_CMODE_SIZE
- bool "size (EXPERIMENTAL)"
- help
- Tries all compressors and chooses the one which has the smallest
- result.
+ bool "size (EXPERIMENTAL)"
+ help
+ Tries all compressors and chooses the one which has the smallest
+ result.
+
+config JFFS2_CMODE_FAVOURLZO
+ bool "Favour LZO"
+ help
+ Tries all compressors and chooses the one which has the smallest
+ result but gives some preference to LZO (which has faster
+ decompression) at the expense of size.
endchoice
@@ -1728,6 +1755,14 @@ config SUNRPC
config SUNRPC_GSS
tristate
+config SUNRPC_XPRT_RDMA
+ tristate "RDMA transport for sunrpc (EXPERIMENTAL)"
+ depends on SUNRPC && INFINIBAND && EXPERIMENTAL
+ default m
+ help
+ Adds a client RPC transport for supporting kernel NFS over RDMA
+ mounts, including Infiniband and iWARP. Experimental.
+
config SUNRPC_BIND34
bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index af6952e39a1..210acafe4a9 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -524,8 +524,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)
(long long) fl->fl_start, (long long) fl->fl_end);
/* AFS doesn't support mandatory locks */
- if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- fl->fl_type != F_UNLCK)
+ if (__mandatory_lock(&vnode->vfs_inode) && fl->fl_type != F_UNLCK)
return -ENOLCK;
if (IS_GETLK(cmd))
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 2e124e0075c..a9b99c0dc2e 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -221,6 +221,42 @@ struct dentry *debugfs_create_u64(const char *name, mode_t mode,
}
EXPORT_SYMBOL_GPL(debugfs_create_u64);
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+
+/**
+ * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
+ * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value
+ * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value
+ *
+ * These functions are exactly the same as the above functions, (but use a hex
+ * output for the decimal challenged) for details look at the above unsigned
+ * decimal functions.
+ */
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+ struct dentry *parent, u8 *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_x8);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x8);
+
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+ struct dentry *parent, u16 *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_x16);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x16);
+
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+ struct dentry *parent, u32 *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_x32);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x32);
+
static ssize_t read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 74901e981e1..d2fc2384c3b 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -491,6 +491,7 @@ struct dlm_ls {
uint64_t ls_recover_seq;
struct dlm_recover *ls_recover_args;
struct rw_semaphore ls_in_recovery; /* block local requests */
+ struct rw_semaphore ls_recv_active; /* block dlm_recv */
struct list_head ls_requestqueue;/* queue remote requests */
struct mutex ls_requestqueue_mutex;
char *ls_recover_buf;
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 2082daf083d..3915b8e1414 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -3638,55 +3638,8 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
dlm_put_lkb(lkb);
}
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
{
- struct dlm_message *ms = (struct dlm_message *) hd;
- struct dlm_ls *ls;
- int error = 0;
-
- if (!recovery)
- dlm_message_in(ms);
-
- ls = dlm_find_lockspace_global(hd->h_lockspace);
- if (!ls) {
- log_print("drop message %d from %d for unknown lockspace %d",
- ms->m_type, nodeid, hd->h_lockspace);
- return -EINVAL;
- }
-
- /* recovery may have just ended leaving a bunch of backed-up requests
- in the requestqueue; wait while dlm_recoverd clears them */
-
- if (!recovery)
- dlm_wait_requestqueue(ls);
-
- /* recovery may have just started while there were a bunch of
- in-flight requests -- save them in requestqueue to be processed
- after recovery. we can't let dlm_recvd block on the recovery
- lock. if dlm_recoverd is calling this function to clear the
- requestqueue, it needs to be interrupted (-EINTR) if another
- recovery operation is starting. */
-
- while (1) {
- if (dlm_locking_stopped(ls)) {
- if (recovery) {
- error = -EINTR;
- goto out;
- }
- error = dlm_add_requestqueue(ls, nodeid, hd);
- if (error == -EAGAIN)
- continue;
- else {
- error = -EINTR;
- goto out;
- }
- }
-
- if (dlm_lock_recovery_try(ls))
- break;
- schedule();
- }
-
switch (ms->m_type) {
/* messages sent to a master node */
@@ -3761,17 +3714,90 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
log_error(ls, "unknown message type %d", ms->m_type);
}
- dlm_unlock_recovery(ls);
- out:
- dlm_put_lockspace(ls);
dlm_astd_wake();
- return error;
}
+/* If the lockspace is in recovery mode (locking stopped), then normal
+ messages are saved on the requestqueue for processing after recovery is
+ done. When not in recovery mode, we wait for dlm_recoverd to drain saved
+ messages off the requestqueue before we process new ones. This occurs right
+ after recovery completes when we transition from saving all messages on
+ requestqueue, to processing all the saved messages, to processing new
+ messages as they arrive. */
-/*
- * Recovery related
- */
+static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
+ int nodeid)
+{
+ if (dlm_locking_stopped(ls)) {
+ dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms);
+ } else {
+ dlm_wait_requestqueue(ls);
+ _receive_message(ls, ms);
+ }
+}
+
+/* This is called by dlm_recoverd to process messages that were saved on
+ the requestqueue. */
+
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ _receive_message(ls, ms);
+}
+
+/* This is called by the midcomms layer when something is received for
+ the lockspace. It could be either a MSG (normal message sent as part of
+ standard locking activity) or an RCOM (recovery message sent as part of
+ lockspace recovery). */
+
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
+{
+ struct dlm_message *ms = (struct dlm_message *) hd;
+ struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+ struct dlm_ls *ls;
+ int type = 0;
+
+ switch (hd->h_cmd) {
+ case DLM_MSG:
+ dlm_message_in(ms);
+ type = ms->m_type;
+ break;
+ case DLM_RCOM:
+ dlm_rcom_in(rc);
+ type = rc->rc_type;
+ break;
+ default:
+ log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid);
+ return;
+ }
+
+ if (hd->h_nodeid != nodeid) {
+ log_print("invalid h_nodeid %d from %d lockspace %x",
+ hd->h_nodeid, nodeid, hd->h_lockspace);
+ return;
+ }
+
+ ls = dlm_find_lockspace_global(hd->h_lockspace);
+ if (!ls) {
+ log_print("invalid h_lockspace %x from %d cmd %d type %d",
+ hd->h_lockspace, nodeid, hd->h_cmd, type);
+
+ if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
+ dlm_send_ls_not_ready(nodeid, rc);
+ return;
+ }
+
+ /* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to
+ be inactive (in this ls) before transitioning to recovery mode */
+
+ down_read(&ls->ls_recv_active);
+ if (hd->h_cmd == DLM_MSG)
+ dlm_receive_message(ls, ms, nodeid);
+ else
+ dlm_receive_rcom(ls, rc, nodeid);
+ up_read(&ls->ls_recv_active);
+
+ dlm_put_lockspace(ls);
+}
static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
{
@@ -4429,7 +4455,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
if (lvb_in && ua->lksb.sb_lvbptr)
memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
- ua->castparam = ua_tmp->castparam;
+ if (ua_tmp->castparam)
+ ua->castparam = ua_tmp->castparam;
ua->user_lksb = ua_tmp->user_lksb;
error = set_unlock_args(flags, ua, &args);
@@ -4474,7 +4501,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
goto out;
ua = (struct dlm_user_args *)lkb->lkb_astparam;
- ua->castparam = ua_tmp->castparam;
+ if (ua_tmp->castparam)
+ ua->castparam = ua_tmp->castparam;
ua->user_lksb = ua_tmp->user_lksb;
error = set_unlock_args(flags, ua, &args);
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 1720313c22d..ada04680a1e 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -16,7 +16,8 @@
void dlm_print_rsb(struct dlm_rsb *r);
void dlm_dump_rsb(struct dlm_rsb *r);
void dlm_print_lkb(struct dlm_lkb *lkb);
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid);
int dlm_modes_compat(int mode1, int mode2);
int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
unsigned int flags, struct dlm_rsb **r_ret);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 1dc72105ab1..6353a838452 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = {
};
static struct kset dlm_kset = {
- .kobj = {.name = "dlm",},
.ktype = &dlm_ktype,
};
@@ -228,6 +227,7 @@ int dlm_lockspace_init(void)
INIT_LIST_HEAD(&lslist);
spin_lock_init(&lslist_lock);
+ kobject_set_name(&dlm_kset.kobj, "dlm");
kobj_set_kset_s(&dlm_kset, kernel_subsys);
error = kset_register(&dlm_kset);
if (error)
@@ -519,6 +519,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
ls->ls_recover_seq = 0;
ls->ls_recover_args = NULL;
init_rwsem(&ls->ls_in_recovery);
+ init_rwsem(&ls->ls_recv_active);
INIT_LIST_HEAD(&ls->ls_requestqueue);
mutex_init(&ls->ls_requestqueue_mutex);
mutex_init(&ls->ls_clear_proc_locks);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 9e9d2e82f40..58bf3f5cdbe 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -334,18 +334,8 @@ static void close_connection(struct connection *con, bool and_other)
con->rx_page = NULL;
}
- /* If we are an 'othercon' then NULL the pointer to us
- from the parent and tidy ourself up */
- if (test_bit(CF_IS_OTHERCON, &con->flags)) {
- struct connection *parent = __nodeid2con(con->nodeid, 0);
- parent->othercon = NULL;
- kmem_cache_free(con_cache, con);
- }
- else {
- /* Parent connections get reused */
- con->retries = 0;
- mutex_unlock(&con->sock_mutex);
- }
+ con->retries = 0;
+ mutex_unlock(&con->sock_mutex);
}
/* We only send shutdown messages to nodes that are not part of the cluster */
@@ -731,6 +721,8 @@ static int tcp_accept_from_sock(struct connection *con)
INIT_WORK(&othercon->swork, process_send_sockets);
INIT_WORK(&othercon->rwork, process_recv_sockets);
set_bit(CF_IS_OTHERCON, &othercon->flags);
+ }
+ if (!othercon->sock) {
newcon->othercon = othercon;
othercon->sock = newsock;
newsock->sk->sk_user_data = othercon;
@@ -1272,14 +1264,15 @@ static void send_to_sock(struct connection *con)
if (len) {
ret = sendpage(con->sock, e->page, offset, len,
msg_flags);
- if (ret == -EAGAIN || ret == 0)
+ if (ret == -EAGAIN || ret == 0) {
+ cond_resched();
goto out;
+ }
if (ret <= 0)
goto send_error;
- } else {
+ }
/* Don't starve people filling buffers */
cond_resched();
- }
spin_lock(&con->writequeue_lock);
e->offset += ret;
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index d09977528f6..e9cdcab306e 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -18,10 +18,6 @@
#include "rcom.h"
#include "config.h"
-/*
- * Following called by dlm_recoverd thread
- */
-
static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
{
struct dlm_member *memb = NULL;
@@ -250,18 +246,30 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
return error;
}
-/*
- * Following called from lockspace.c
- */
+/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before
+ dlm_ls_start() is called on any of them to start the new recovery. */
int dlm_ls_stop(struct dlm_ls *ls)
{
int new;
/*
- * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
- * dlm_recovery_stopped()) and prevents any new locks from being
- * processed (see RUNNING, dlm_locking_stopped()).
+ * Prevent dlm_recv from being in the middle of something when we do
+ * the stop. This includes ensuring dlm_recv isn't processing a
+ * recovery message (rcom), while dlm_recoverd is aborting and
+ * resetting things from an in-progress recovery. i.e. we want
+ * dlm_recoverd to abort its recovery without worrying about dlm_recv
+ * processing an rcom at the same time. Stopping dlm_recv also makes
+ * it easy for dlm_receive_message() to check locking stopped and add a
+ * message to the requestqueue without races.
+ */
+
+ down_write(&ls->ls_recv_active);
+
+ /*
+ * Abort any recovery that's in progress (see RECOVERY_STOP,
+ * dlm_recovery_stopped()) and tell any other threads running in the
+ * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
*/
spin_lock(&ls->ls_recover_lock);
@@ -271,8 +279,14 @@ int dlm_ls_stop(struct dlm_ls *ls)
spin_unlock(&ls->ls_recover_lock);
/*
+ * Let dlm_recv run again, now any normal messages will be saved on the
+ * requestqueue for later.
+ */
+
+ up_write(&ls->ls_recv_active);
+
+ /*
* This in_recovery lock does two things:
- *
* 1) Keeps this function from returning until all threads are out
* of locking routines and locking is truely stopped.
* 2) Keeps any new requests from being processed until it's unlocked
@@ -284,9 +298,8 @@ int dlm_ls_stop(struct dlm_ls *ls)
/*
* The recoverd suspend/resume makes sure that dlm_recoverd (if
- * running) has noticed the clearing of RUNNING above and quit
- * processing the previous recovery. This will be true for all nodes
- * before any nodes start the new recovery.
+ * running) has noticed RECOVERY_STOP above and quit processing the
+ * previous recovery.
*/
dlm_recoverd_suspend(ls);
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
index a5126e0c68a..f8c69dda16a 100644
--- a/fs/dlm/midcomms.c
+++ b/fs/dlm/midcomms.c
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -27,7 +27,6 @@
#include "dlm_internal.h"
#include "lowcomms.h"
#include "config.h"
-#include "rcom.h"
#include "lock.h"
#include "midcomms.h"
@@ -117,19 +116,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
offset &= (limit - 1);
len -= msglen;
- switch (msg->h_cmd) {
- case DLM_MSG:
- dlm_receive_message(msg, nodeid, 0);
- break;
-
- case DLM_RCOM:
- dlm_receive_rcom(msg, nodeid);
- break;
-
- default:
- log_print("unknown msg type %x from %u: %u %u %u %u",
- msg->h_cmd, nodeid, msglen, len, offset, ret);
- }
+ dlm_receive_buffer(msg, nodeid);
}
if (msg != (struct dlm_header *) __tmp)
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 188b91c027e..ae2fd97fa4a 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -386,7 +386,10 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
dlm_recover_process_copy(ls, rc_in);
}
-static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+/* If the lockspace doesn't exist then still send a status message
+ back; it's possible that it just doesn't have its global_id yet. */
+
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
{
struct dlm_rcom *rc;
struct rcom_config *rf;
@@ -446,28 +449,11 @@ static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
return rv;
}
-/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+/* Called by dlm_recv; corresponds to dlm_receive_message() but special
recovery-only comms are sent through here. */
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
{
- struct dlm_rcom *rc = (struct dlm_rcom *) hd;
- struct dlm_ls *ls;
-
- dlm_rcom_in(rc);
-
- /* If the lockspace doesn't exist then still send a status message
- back; it's possible that it just doesn't have its global_id yet. */
-
- ls = dlm_find_lockspace_global(hd->h_lockspace);
- if (!ls) {
- log_print("lockspace %x from %d type %x not found",
- hd->h_lockspace, nodeid, rc->rc_type);
- if (rc->rc_type == DLM_RCOM_STATUS)
- send_ls_not_ready(nodeid, rc);
- return;
- }
-
if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
log_debug(ls, "ignoring recovery message %x from %d",
rc->rc_type, nodeid);
@@ -477,12 +463,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
if (is_old_reply(ls, rc))
goto out;
- if (nodeid != rc->rc_header.h_nodeid) {
- log_error(ls, "bad rcom nodeid %d from %d",
- rc->rc_header.h_nodeid, nodeid);
- goto out;
- }
-
switch (rc->rc_type) {
case DLM_RCOM_STATUS:
receive_rcom_status(ls, rc);
@@ -520,6 +500,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
}
out:
- dlm_put_lockspace(ls);
+ return;
}
diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h
index d7984321ff4..b09abd29ba3 100644
--- a/fs/dlm/rcom.h
+++ b/fs/dlm/rcom.h
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -18,7 +18,8 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid);
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in);
#endif
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 66575997861..4b89e20eebe 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -24,19 +24,28 @@
/* If the start for which we're re-enabling locking (seq) has been superseded
- by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+ by a newer stop (ls_recover_seq), we need to leave locking disabled.
+
+ We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees
+ locking stopped and b) adds a message to the requestqueue, but dlm_recoverd
+ enables locking and clears the requestqueue between a and b. */
static int enable_locking(struct dlm_ls *ls, uint64_t seq)
{
int error = -EINTR;
+ down_write(&ls->ls_recv_active);
+
spin_lock(&ls->ls_recover_lock);
if (ls->ls_recover_seq == seq) {
set_bit(LSFL_RUNNING, &ls->ls_flags);
+ /* unblocks processes waiting to enter the dlm */
up_write(&ls->ls_in_recovery);
error = 0;
}
spin_unlock(&ls->ls_recover_lock);
+
+ up_write(&ls->ls_recv_active);
return error;
}
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index 65008d79c96..0de04f17cce 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -1,7 +1,7 @@
/******************************************************************************
*******************************************************************************
**
-** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -20,7 +20,7 @@
struct rq_entry {
struct list_head list;
int nodeid;
- char request[1];
+ char request[0];
};
/*
@@ -30,42 +30,39 @@ struct rq_entry {
* lockspace is enabled on some while still suspended on others.
*/
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
{
struct rq_entry *e;
int length = hd->h_length;
- int rv = 0;
e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
if (!e) {
- log_print("dlm_add_requestqueue: out of memory\n");
- return 0;
+ log_print("dlm_add_requestqueue: out of memory len %d", length);
+ return;
}
e->nodeid = nodeid;
memcpy(e->request, hd, length);
- /* We need to check dlm_locking_stopped() after taking the mutex to
- avoid a race where dlm_recoverd enables locking and runs
- process_requestqueue between our earlier dlm_locking_stopped check
- and this addition to the requestqueue. */
-
mutex_lock(&ls->ls_requestqueue_mutex);
- if (dlm_locking_stopped(ls))
- list_add_tail(&e->list, &ls->ls_requestqueue);
- else {
- log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid);
- kfree(e);
- rv = -EAGAIN;
- }
+ list_add_tail(&e->list, &ls->ls_requestqueue);
mutex_unlock(&ls->ls_requestqueue_mutex);
- return rv;
}
+/*
+ * Called by dlm_recoverd to process normal messages saved while recovery was
+ * happening. Normal locking has been enabled before this is called. dlm_recv
+ * upon receiving a message, will wait for all saved messages to be drained
+ * here before processing the message it got. If a new dlm_ls_stop() arrives
+ * while we're processing these saved messages, it may block trying to suspend
+ * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue. In that
+ * case, we don't abort since locking_stopped is still 0. If dlm_recv is not
+ * waiting for us, then this processing may be aborted due to locking_stopped.
+ */
+
int dlm_process_requestqueue(struct dlm_ls *ls)
{
struct rq_entry *e;
- struct dlm_header *hd;
int error = 0;
mutex_lock(&ls->ls_requestqueue_mutex);
@@ -79,14 +76,7 @@ int dlm_process_requestqueue(struct dlm_ls *ls)
e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
mutex_unlock(&ls->ls_requestqueue_mutex);
- hd = (struct dlm_header *) e->request;
- error = dlm_receive_message(hd, e->nodeid, 1);
-
- if (error == -EINTR) {
- /* entry is left on requestqueue */
- log_debug(ls, "process_requestqueue abort eintr");
- break;
- }
+ dlm_receive_message_saved(ls, (struct dlm_message *)e->request);
mutex_lock(&ls->ls_requestqueue_mutex);
list_del(&e->list);
@@ -106,10 +96,12 @@ int dlm_process_requestqueue(struct dlm_ls *ls)
/*
* After recovery is done, locking is resumed and dlm_recoverd takes all the
- * saved requests and processes them as they would have been by dlm_recvd. At
- * the same time, dlm_recvd will start receiving new requests from remote
- * nodes. We want to delay dlm_recvd processing new requests until
- * dlm_recoverd has finished processing the old saved requests.
+ * saved requests and processes them as they would have been by dlm_recv. At
+ * the same time, dlm_recv will start receiving new requests from remote nodes.
+ * We want to delay dlm_recv processing new requests until dlm_recoverd has
+ * finished processing the old saved requests. We don't check for locking
+ * stopped here because dlm_ls_stop won't stop locking until it's suspended us
+ * (dlm_recv).
*/
void dlm_wait_requestqueue(struct dlm_ls *ls)
@@ -118,8 +110,6 @@ void dlm_wait_requestqueue(struct dlm_ls *ls)
mutex_lock(&ls->ls_requestqueue_mutex);
if (list_empty(&ls->ls_requestqueue))
break;
- if (dlm_locking_stopped(ls))
- break;
mutex_unlock(&ls->ls_requestqueue_mutex);
schedule();
}
diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h
index 6a53ea03335..aba34fc05ee 100644
--- a/fs/dlm/requestqueue.h
+++ b/fs/dlm/requestqueue.h
@@ -1,7 +1,7 @@
/******************************************************************************
*******************************************************************************
**
-** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -13,7 +13,7 @@
#ifndef __REQUESTQUEUE_DOT_H__
#define __REQUESTQUEUE_DOT_H__
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
int dlm_process_requestqueue(struct dlm_ls *ls);
void dlm_wait_requestqueue(struct dlm_ls *ls);
void dlm_purge_requestqueue(struct dlm_ls *ls);
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index cd805a66880..93fa427bb5f 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -93,9 +93,10 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
map_bh(bh, inode->i_sb, block);
set_buffer_uptodate(bh);
+ if (!gfs2_is_jdata(ip))
+ mark_buffer_dirty(bh);
if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
gfs2_trans_add_bh(ip->i_gl, bh, 0);
- mark_buffer_dirty(bh);
if (release) {
unlock_page(page);
@@ -1085,6 +1086,33 @@ static int do_shrink(struct gfs2_inode *ip, u64 size)
return error;
}
+static int do_touch(struct gfs2_inode *ip, u64 size)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ return error;
+
+ down_write(&ip->i_rw_mutex);
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto do_touch_out;
+
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(ip, dibh->b_data);
+ brelse(dibh);
+
+do_touch_out:
+ up_write(&ip->i_rw_mutex);
+ gfs2_trans_end(sdp);
+ return error;
+}
+
/**
* gfs2_truncatei - make a file a given size
* @ip: the inode
@@ -1105,8 +1133,11 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
if (size > ip->i_di.di_size)
error = do_grow(ip, size);
- else
+ else if (size < ip->i_di.di_size)
error = do_shrink(ip, size);
+ else
+ /* update time stamps */
+ error = do_touch(ip, size);
return error;
}
diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
index 3548d9f31e0..3731ab0771d 100644
--- a/fs/gfs2/daemon.c
+++ b/fs/gfs2/daemon.c
@@ -35,30 +35,6 @@
The kthread functions used to start these daemons block and flush signals. */
/**
- * gfs2_scand - Look for cached glocks and inodes to toss from memory
- * @sdp: Pointer to GFS2 superblock
- *
- * One of these daemons runs, finding candidates to add to sd_reclaim_list.
- * See gfs2_glockd()
- */
-
-int gfs2_scand(void *data)
-{
- struct gfs2_sbd *sdp = data;
- unsigned long t;
-
- while (!kthread_should_stop()) {
- gfs2_scand_internal(sdp);
- t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
- if (freezing(current))
- refrigerator();
- schedule_timeout_interruptible(t);
- }
-
- return 0;
-}
-
-/**
* gfs2_glockd - Reclaim unused glock structures
* @sdp: Pointer to GFS2 superblock
*
diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
index 801007120fb..0de9b355795 100644
--- a/fs/gfs2/daemon.h
+++ b/fs/gfs2/daemon.h
@@ -10,7 +10,6 @@
#ifndef __DAEMON_DOT_H__
#define __DAEMON_DOT_H__
-int gfs2_scand(void *data);
int gfs2_glockd(void *data);
int gfs2_recoverd(void *data);
int gfs2_logd(void *data);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 2beb2f401aa..9949bb746a5 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1043,6 +1043,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
error = gfs2_meta_inode_buffer(dip, &dibh);
if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
+ gfs2_trans_add_bh(dip->i_gl, dibh, 1);
dip->i_di.di_blocks++;
gfs2_set_inode_blocks(&dip->i_inode);
gfs2_dinode_out(dip, dibh->b_data);
@@ -1501,7 +1502,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name)
inode = gfs2_inode_lookup(dir->i_sb,
be16_to_cpu(dent->de_type),
be64_to_cpu(dent->de_inum.no_addr),
- be64_to_cpu(dent->de_inum.no_formal_ino));
+ be64_to_cpu(dent->de_inum.no_formal_ino), 0);
brelse(bh);
return inode;
}
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
index 1ab3e9d7388..aa8dbf303f6 100644
--- a/fs/gfs2/eaops.c
+++ b/fs/gfs2/eaops.c
@@ -200,28 +200,28 @@ static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
return gfs2_ea_remove_i(ip, er);
}
-static struct gfs2_eattr_operations gfs2_user_eaops = {
+static const struct gfs2_eattr_operations gfs2_user_eaops = {
.eo_get = user_eo_get,
.eo_set = user_eo_set,
.eo_remove = user_eo_remove,
.eo_name = "user",
};
-struct gfs2_eattr_operations gfs2_system_eaops = {
+const struct gfs2_eattr_operations gfs2_system_eaops = {
.eo_get = system_eo_get,
.eo_set = system_eo_set,
.eo_remove = system_eo_remove,
.eo_name = "system",
};
-static struct gfs2_eattr_operations gfs2_security_eaops = {
+static const struct gfs2_eattr_operations gfs2_security_eaops = {
.eo_get = security_eo_get,
.eo_set = security_eo_set,
.eo_remove = security_eo_remove,
.eo_name = "security",
};
-struct gfs2_eattr_operations *gfs2_ea_ops[] = {
+const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
NULL,
&gfs2_user_eaops,
&gfs2_system_eaops,
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h
index 508b4f7a244..da2f7fbbb40 100644
--- a/fs/gfs2/eaops.h
+++ b/fs/gfs2/eaops.h
@@ -22,9 +22,9 @@ struct gfs2_eattr_operations {
unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
-extern struct gfs2_eattr_operations gfs2_system_eaops;
+extern const struct gfs2_eattr_operations gfs2_system_eaops;
-extern struct gfs2_eattr_operations *gfs2_ea_ops[];
+extern const struct gfs2_eattr_operations *gfs2_ea_ops[];
#endif /* __EAOPS_DOT_H__ */
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 3f0974e1afe..a37efe4aae6 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -25,8 +25,10 @@
#include <asm/uaccess.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
#include "gfs2.h"
#include "incore.h"
@@ -48,7 +50,6 @@ struct glock_iter {
int hash; /* hash bucket index */
struct gfs2_sbd *sdp; /* incore superblock */
struct gfs2_glock *gl; /* current glock struct */
- struct hlist_head *hb_list; /* current hash bucket ptr */
struct seq_file *seq; /* sequence file for debugfs */
char string[512]; /* scratch space */
};
@@ -59,8 +60,13 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static void run_queue(struct gfs2_glock *gl);
+
static DECLARE_RWSEM(gfs2_umount_flush_sem);
static struct dentry *gfs2_root;
+static struct task_struct *scand_process;
+static unsigned int scand_secs = 5;
+static struct workqueue_struct *glock_workqueue;
#define GFS2_GL_HASH_SHIFT 15
#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
@@ -276,6 +282,18 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
return gl;
}
+static void glock_work_func(struct work_struct *work)
+{
+ struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
+
+ spin_lock(&gl->gl_spin);
+ if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags))
+ set_bit(GLF_DEMOTE, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ gfs2_glock_put(gl);
+}
+
/**
* gfs2_glock_get() - Get a glock, or create one if one doesn't exist
* @sdp: The GFS2 superblock
@@ -315,6 +333,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_name = name;
atomic_set(&gl->gl_ref, 1);
gl->gl_state = LM_ST_UNLOCKED;
+ gl->gl_demote_state = LM_ST_EXCLUSIVE;
gl->gl_hash = hash;
gl->gl_owner_pid = 0;
gl->gl_ip = 0;
@@ -323,10 +342,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_req_bh = NULL;
gl->gl_vn = 0;
gl->gl_stamp = jiffies;
+ gl->gl_tchange = jiffies;
gl->gl_object = NULL;
gl->gl_sbd = sdp;
gl->gl_aspace = NULL;
lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+ INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
/* If this glock protects actual on-disk data or metadata blocks,
create a VFS inode to manage the pages/buffers holding them. */
@@ -440,6 +461,8 @@ static void wait_on_holder(struct gfs2_holder *gh)
static void gfs2_demote_wake(struct gfs2_glock *gl)
{
+ BUG_ON(!spin_is_locked(&gl->gl_spin));
+ gl->gl_demote_state = LM_ST_EXCLUSIVE;
clear_bit(GLF_DEMOTE, &gl->gl_flags);
smp_mb__after_clear_bit();
wake_up_bit(&gl->gl_flags, GLF_DEMOTE);
@@ -545,12 +568,14 @@ static int rq_demote(struct gfs2_glock *gl)
return 0;
}
set_bit(GLF_LOCK, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
if (gl->gl_demote_state == LM_ST_UNLOCKED ||
- gl->gl_state != LM_ST_EXCLUSIVE)
+ gl->gl_state != LM_ST_EXCLUSIVE) {
+ spin_unlock(&gl->gl_spin);
gfs2_glock_drop_th(gl);
- else
+ } else {
+ spin_unlock(&gl->gl_spin);
gfs2_glock_xmote_th(gl, NULL);
+ }
spin_lock(&gl->gl_spin);
return 0;
@@ -679,24 +704,25 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
* practise: LM_ST_SHARED and LM_ST_UNLOCKED
*/
-static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote)
+static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+ int remote, unsigned long delay)
{
+ int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
+
spin_lock(&gl->gl_spin);
- if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+ set_bit(bit, &gl->gl_flags);
+ if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
gl->gl_demote_state = state;
gl->gl_demote_time = jiffies;
if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
gl->gl_object) {
- struct inode *inode = igrab(gl->gl_object);
+ gfs2_glock_schedule_for_reclaim(gl);
spin_unlock(&gl->gl_spin);
- if (inode) {
- d_prune_aliases(inode);
- iput(inode);
- }
return;
}
- } else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
- gl->gl_demote_state = state;
+ } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+ gl->gl_demote_state != state) {
+ gl->gl_demote_state = LM_ST_UNLOCKED;
}
spin_unlock(&gl->gl_spin);
}
@@ -723,6 +749,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
}
gl->gl_state = new_state;
+ gl->gl_tchange = jiffies;
}
/**
@@ -760,10 +787,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
if (!gh) {
gl->gl_stamp = jiffies;
- if (ret & LM_OUT_CANCELED)
+ if (ret & LM_OUT_CANCELED) {
op_done = 0;
- else
+ } else {
+ spin_lock(&gl->gl_spin);
+ if (gl->gl_state != gl->gl_demote_state) {
+ gl->gl_req_bh = NULL;
+ spin_unlock(&gl->gl_spin);
+ gfs2_glock_drop_th(gl);
+ gfs2_glock_put(gl);
+ return;
+ }
gfs2_demote_wake(gl);
+ spin_unlock(&gl->gl_spin);
+ }
} else {
spin_lock(&gl->gl_spin);
list_del_init(&gh->gh_list);
@@ -799,7 +836,6 @@ out:
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
}
@@ -817,7 +853,7 @@ out:
*
*/
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
int flags = gh ? gh->gh_flags : 0;
@@ -871,7 +907,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
- gfs2_demote_wake(gl);
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
@@ -884,10 +919,10 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
}
spin_lock(&gl->gl_spin);
+ gfs2_demote_wake(gl);
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
gfs2_glock_put(gl);
@@ -1067,24 +1102,31 @@ static void add_to_queue(struct gfs2_holder *gh)
if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
BUG();
- existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
- if (existing) {
- print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
- printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
- printk(KERN_INFO "lock type : %d lock state : %d\n",
- existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
- print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
- printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
- printk(KERN_INFO "lock type : %d lock state : %d\n",
- gl->gl_name.ln_type, gl->gl_state);
- BUG();
- }
-
- existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
- if (existing) {
- print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
- print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
- BUG();
+ if (!(gh->gh_flags & GL_FLOCK)) {
+ existing = find_holder_by_owner(&gl->gl_holders,
+ gh->gh_owner_pid);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n",
+ existing->gh_ip);
+ printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ existing->gh_gl->gl_name.ln_type,
+ existing->gh_gl->gl_state);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ gl->gl_name.ln_type, gl->gl_state);
+ BUG();
+ }
+
+ existing = find_holder_by_owner(&gl->gl_waiters3,
+ gh->gh_owner_pid);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n",
+ existing->gh_ip);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ BUG();
+ }
}
if (gh->gh_flags & LM_FLAG_PRIORITY)
@@ -1195,9 +1237,10 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
const struct gfs2_glock_operations *glops = gl->gl_ops;
+ unsigned delay = 0;
if (gh->gh_flags & GL_NOCACHE)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_lock(gl);
@@ -1215,8 +1258,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
}
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
+
+ gfs2_glock_hold(gl);
+ if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
+ !test_bit(GLF_DEMOTE, &gl->gl_flags))
+ delay = gl->gl_ops->go_min_hold_time;
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+ gfs2_glock_put(gl);
}
void gfs2_glock_dq_wait(struct gfs2_holder *gh)
@@ -1443,18 +1492,21 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
unsigned int state)
{
struct gfs2_glock *gl;
+ unsigned long delay = 0;
+ unsigned long holdtime;
+ unsigned long now = jiffies;
gl = gfs2_glock_find(sdp, name);
if (!gl)
return;
- handle_callback(gl, state, 1);
-
- spin_lock(&gl->gl_spin);
- run_queue(gl);
- spin_unlock(&gl->gl_spin);
+ holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
+ if (time_before(now, holdtime))
+ delay = holdtime - now;
- gfs2_glock_put(gl);
+ handle_callback(gl, state, 1, delay);
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+ gfs2_glock_put(gl);
}
/**
@@ -1495,7 +1547,8 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
return;
if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
gl->gl_req_bh(gl, async->lc_ret);
- gfs2_glock_put(gl);
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+ gfs2_glock_put(gl);
up_read(&gfs2_umount_flush_sem);
return;
}
@@ -1588,7 +1641,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
if (gfs2_glmutex_trylock(gl)) {
if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_unlock(gl);
}
@@ -1617,7 +1670,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
goto out;
gl = list_entry(head->first, struct gfs2_glock, gl_list);
while(1) {
- if (gl->gl_sbd == sdp) {
+ if (!sdp || gl->gl_sbd == sdp) {
gfs2_glock_hold(gl);
read_unlock(gl_lock_addr(hash));
if (prev)
@@ -1635,6 +1688,7 @@ out:
read_unlock(gl_lock_addr(hash));
if (prev)
gfs2_glock_put(prev);
+ cond_resched();
return has_entries;
}
@@ -1663,20 +1717,6 @@ out_schedule:
}
/**
- * gfs2_scand_internal - Look for glocks and inodes to toss from memory
- * @sdp: the filesystem
- *
- */
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp)
-{
- unsigned int x;
-
- for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
- examine_bucket(scan_glock, sdp, x);
-}
-
-/**
* clear_glock - look at a glock and see if we can free it from glock cache
* @gl: the glock to look at
*
@@ -1701,7 +1741,7 @@ static void clear_glock(struct gfs2_glock *gl)
if (gfs2_glmutex_trylock(gl)) {
if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_unlock(gl);
}
}
@@ -1843,7 +1883,7 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
spin_lock(&gl->gl_spin);
- print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+ print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type,
(unsigned long long)gl->gl_name.ln_number);
print_dbg(gi, " gl_flags =");
for (x = 0; x < 32; x++) {
@@ -1963,6 +2003,35 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
return error;
}
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+static int gfs2_scand(void *data)
+{
+ unsigned x;
+ unsigned delay;
+
+ while (!kthread_should_stop()) {
+ for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+ examine_bucket(scan_glock, NULL, x);
+ if (freezing(current))
+ refrigerator();
+ delay = scand_secs;
+ if (delay < 1)
+ delay = 1;
+ schedule_timeout_interruptible(delay * HZ);
+ }
+
+ return 0;
+}
+
+
+
int __init gfs2_glock_init(void)
{
unsigned i;
@@ -1974,52 +2043,69 @@ int __init gfs2_glock_init(void)
rwlock_init(&gl_hash_locks[i]);
}
#endif
+
+ scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand");
+ if (IS_ERR(scand_process))
+ return PTR_ERR(scand_process);
+
+ glock_workqueue = create_workqueue("glock_workqueue");
+ if (IS_ERR(glock_workqueue)) {
+ kthread_stop(scand_process);
+ return PTR_ERR(glock_workqueue);
+ }
+
return 0;
}
+void gfs2_glock_exit(void)
+{
+ destroy_workqueue(glock_workqueue);
+ kthread_stop(scand_process);
+}
+
+module_param(scand_secs, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs");
+
static int gfs2_glock_iter_next(struct glock_iter *gi)
{
+ struct gfs2_glock *gl;
+
+restart:
read_lock(gl_lock_addr(gi->hash));
- while (1) {
- if (!gi->hb_list) { /* If we don't have a hash bucket yet */
- gi->hb_list = &gl_hash_table[gi->hash].hb_list;
- if (hlist_empty(gi->hb_list)) {
- read_unlock(gl_lock_addr(gi->hash));
- gi->hash++;
- read_lock(gl_lock_addr(gi->hash));
- gi->hb_list = NULL;
- if (gi->hash >= GFS2_GL_HASH_SIZE) {
- read_unlock(gl_lock_addr(gi->hash));
- return 1;
- }
- else
- continue;
- }
- if (!hlist_empty(gi->hb_list)) {
- gi->gl = list_entry(gi->hb_list->first,
- struct gfs2_glock,
- gl_list);
- }
- } else {
- if (gi->gl->gl_list.next == NULL) {
- read_unlock(gl_lock_addr(gi->hash));
- gi->hash++;
- read_lock(gl_lock_addr(gi->hash));
- gi->hb_list = NULL;
- continue;
- }
- gi->gl = list_entry(gi->gl->gl_list.next,
- struct gfs2_glock, gl_list);
- }
+ gl = gi->gl;
+ if (gl) {
+ gi->gl = hlist_entry(gl->gl_list.next,
+ struct gfs2_glock, gl_list);
if (gi->gl)
- break;
+ gfs2_glock_hold(gi->gl);
}
read_unlock(gl_lock_addr(gi->hash));
+ if (gl)
+ gfs2_glock_put(gl);
+ if (gl && gi->gl == NULL)
+ gi->hash++;
+ while(gi->gl == NULL) {
+ if (gi->hash >= GFS2_GL_HASH_SIZE)
+ return 1;
+ read_lock(gl_lock_addr(gi->hash));
+ gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
+ struct gfs2_glock, gl_list);
+ if (gi->gl)
+ gfs2_glock_hold(gi->gl);
+ read_unlock(gl_lock_addr(gi->hash));
+ gi->hash++;
+ }
+
+ if (gi->sdp != gi->gl->gl_sbd)
+ goto restart;
+
return 0;
}
static void gfs2_glock_iter_free(struct glock_iter *gi)
{
+ if (gi->gl)
+ gfs2_glock_put(gi->gl);
kfree(gi);
}
@@ -2033,9 +2119,8 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)
gi->sdp = sdp;
gi->hash = 0;
- gi->gl = NULL;
- gi->hb_list = NULL;
gi->seq = NULL;
+ gi->gl = NULL;
memset(gi->string, 0, sizeof(gi->string));
if (gfs2_glock_iter_next(gi)) {
@@ -2055,7 +2140,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)
if (!gi)
return NULL;
- while (n--) {
+ while(n--) {
if (gfs2_glock_iter_next(gi)) {
gfs2_glock_iter_free(gi);
return NULL;
@@ -2082,7 +2167,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,
static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
{
- /* nothing for now */
+ struct glock_iter *gi = iter_ptr;
+ if (gi)
+ gfs2_glock_iter_free(gi);
}
static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
@@ -2095,7 +2182,7 @@ static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
return 0;
}
-static struct seq_operations gfs2_glock_seq_ops = {
+static const struct seq_operations gfs2_glock_seq_ops = {
.start = gfs2_glock_seq_start,
.next = gfs2_glock_seq_next,
.stop = gfs2_glock_seq_stop,
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 7721ca3fff9..b16f604eea9 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -26,6 +26,7 @@
#define GL_SKIP 0x00000100
#define GL_ATIME 0x00000200
#define GL_NOCACHE 0x00000400
+#define GL_FLOCK 0x00000800
#define GL_NOCANCEL 0x00001000
#define GLR_TRYFAILED 13
@@ -132,11 +133,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp);
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
int __init gfs2_glock_init(void);
+void gfs2_glock_exit(void);
+
int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
int gfs2_register_debugfs(void);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 777ca46010e..4670dcb2a87 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -41,7 +41,6 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
struct list_head *head = &gl->gl_ail_list;
struct gfs2_bufdata *bd;
struct buffer_head *bh;
- u64 blkno;
int error;
blocks = atomic_read(&gl->gl_ail_count);
@@ -57,19 +56,12 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
bd = list_entry(head->next, struct gfs2_bufdata,
bd_ail_gl_list);
bh = bd->bd_bh;
- blkno = bh->b_blocknr;
+ gfs2_remove_from_ail(NULL, bd);
+ bd->bd_bh = NULL;
+ bh->b_private = NULL;
+ bd->bd_blkno = bh->b_blocknr;
gfs2_assert_withdraw(sdp, !buffer_busy(bh));
-
- bd->bd_ail = NULL;
- list_del(&bd->bd_ail_st_list);
- list_del(&bd->bd_ail_gl_list);
- atomic_dec(&gl->gl_ail_count);
- brelse(bh);
- gfs2_log_unlock(sdp);
-
- gfs2_trans_add_revoke(sdp, blkno);
-
- gfs2_log_lock(sdp);
+ gfs2_trans_add_revoke(sdp, bd);
}
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
gfs2_log_unlock(sdp);
@@ -156,9 +148,11 @@ static void inode_go_sync(struct gfs2_glock *gl)
ip = NULL;
if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
- if (ip)
+ if (ip && !gfs2_is_jdata(ip))
filemap_fdatawrite(ip->i_inode.i_mapping);
gfs2_log_flush(gl->gl_sbd, gl);
+ if (ip && gfs2_is_jdata(ip))
+ filemap_fdatawrite(ip->i_inode.i_mapping);
gfs2_meta_sync(gl);
if (ip) {
struct address_space *mapping = ip->i_inode.i_mapping;
@@ -452,6 +446,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
.go_lock = inode_go_lock,
.go_unlock = inode_go_unlock,
.go_type = LM_TYPE_INODE,
+ .go_min_hold_time = HZ / 10,
};
const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -462,6 +457,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
.go_lock = rgrp_go_lock,
.go_unlock = rgrp_go_unlock,
.go_type = LM_TYPE_RGRP,
+ .go_min_hold_time = HZ / 10,
};
const struct gfs2_glock_operations gfs2_trans_glops = {
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 170ba93829c..eaddfb5a8e6 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -11,6 +11,7 @@
#define __INCORE_DOT_H__
#include <linux/fs.h>
+#include <linux/workqueue.h>
#define DIO_WAIT 0x00000010
#define DIO_METADATA 0x00000020
@@ -113,7 +114,13 @@ struct gfs2_bufdata {
struct buffer_head *bd_bh;
struct gfs2_glock *bd_gl;
- struct list_head bd_list_tr;
+ union {
+ struct list_head list_tr;
+ u64 blkno;
+ } u;
+#define bd_list_tr u.list_tr
+#define bd_blkno u.blkno
+
struct gfs2_log_element bd_le;
struct gfs2_ail *bd_ail;
@@ -130,6 +137,7 @@ struct gfs2_glock_operations {
int (*go_lock) (struct gfs2_holder *gh);
void (*go_unlock) (struct gfs2_holder *gh);
const int go_type;
+ const unsigned long go_min_hold_time;
};
enum {
@@ -161,6 +169,7 @@ enum {
GLF_LOCK = 1,
GLF_STICKY = 2,
GLF_DEMOTE = 3,
+ GLF_PENDING_DEMOTE = 4,
GLF_DIRTY = 5,
};
@@ -193,6 +202,7 @@ struct gfs2_glock {
u64 gl_vn;
unsigned long gl_stamp;
+ unsigned long gl_tchange;
void *gl_object;
struct list_head gl_reclaim;
@@ -203,6 +213,7 @@ struct gfs2_glock {
struct gfs2_log_element gl_le;
struct list_head gl_ail_list;
atomic_t gl_ail_count;
+ struct delayed_work gl_work;
};
struct gfs2_alloc {
@@ -293,11 +304,6 @@ struct gfs2_file {
struct gfs2_holder f_fl_gh;
};
-struct gfs2_revoke {
- struct gfs2_log_element rv_le;
- u64 rv_blkno;
-};
-
struct gfs2_revoke_replay {
struct list_head rr_list;
u64 rr_blkno;
@@ -335,12 +341,6 @@ struct gfs2_quota_data {
unsigned long qd_last_touched;
};
-struct gfs2_log_buf {
- struct list_head lb_list;
- struct buffer_head *lb_bh;
- struct buffer_head *lb_real;
-};
-
struct gfs2_trans {
unsigned long tr_ip;
@@ -429,7 +429,6 @@ struct gfs2_tune {
unsigned int gt_log_flush_secs;
unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
- unsigned int gt_scand_secs;
unsigned int gt_recoverd_secs;
unsigned int gt_logd_secs;
unsigned int gt_quotad_secs;
@@ -574,7 +573,6 @@ struct gfs2_sbd {
/* Daemon stuff */
- struct task_struct *sd_scand_process;
struct task_struct *sd_recoverd_process;
struct task_struct *sd_logd_process;
struct task_struct *sd_quotad_process;
@@ -609,13 +607,13 @@ struct gfs2_sbd {
unsigned int sd_log_num_revoke;
unsigned int sd_log_num_rg;
unsigned int sd_log_num_databuf;
- unsigned int sd_log_num_jdata;
struct list_head sd_log_le_gl;
struct list_head sd_log_le_buf;
struct list_head sd_log_le_revoke;
struct list_head sd_log_le_rg;
struct list_head sd_log_le_databuf;
+ struct list_head sd_log_le_ordered;
unsigned int sd_log_blks_free;
struct mutex sd_log_reserve_mutex;
@@ -627,7 +625,8 @@ struct gfs2_sbd {
unsigned long sd_log_flush_time;
struct rw_semaphore sd_log_flush_lock;
- struct list_head sd_log_flush_list;
+ atomic_t sd_log_in_flight;
+ wait_queue_head_t sd_log_flush_wait;
unsigned int sd_log_flush_head;
u64 sd_log_flush_wrapped;
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 34f7bcdea1e..5f6dc32946c 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -77,6 +77,49 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
}
+struct gfs2_skip_data {
+ u64 no_addr;
+ int skipped;
+};
+
+static int iget_skip_test(struct inode *inode, void *opaque)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_skip_data *data = opaque;
+
+ if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){
+ if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
+ data->skipped = 1;
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int iget_skip_set(struct inode *inode, void *opaque)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_skip_data *data = opaque;
+
+ if (data->skipped)
+ return 1;
+ inode->i_ino = (unsigned long)(data->no_addr);
+ ip->i_no_addr = data->no_addr;
+ return 0;
+}
+
+static struct inode *gfs2_iget_skip(struct super_block *sb,
+ u64 no_addr)
+{
+ struct gfs2_skip_data data;
+ unsigned long hash = (unsigned long)no_addr;
+
+ data.no_addr = no_addr;
+ data.skipped = 0;
+ return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);
+}
+
/**
* GFS2 lookup code fills in vfs inode contents based on info obtained
* from directory entry inside gfs2_inode_lookup(). This has caused issues
@@ -112,6 +155,7 @@ void gfs2_set_iop(struct inode *inode)
* @sb: The super block
* @no_addr: The inode number
* @type: The type of the inode
+ * @skip_freeing: set this not return an inode if it is currently being freed.
*
* Returns: A VFS inode, or an error
*/
@@ -119,13 +163,19 @@ void gfs2_set_iop(struct inode *inode)
struct inode *gfs2_inode_lookup(struct super_block *sb,
unsigned int type,
u64 no_addr,
- u64 no_formal_ino)
+ u64 no_formal_ino, int skip_freeing)
{
- struct inode *inode = gfs2_iget(sb, no_addr);
- struct gfs2_inode *ip = GFS2_I(inode);
+ struct inode *inode;
+ struct gfs2_inode *ip;
struct gfs2_glock *io_gl;
int error;
+ if (skip_freeing)
+ inode = gfs2_iget_skip(sb, no_addr);
+ else
+ inode = gfs2_iget(sb, no_addr);
+ ip = GFS2_I(inode);
+
if (!inode)
return ERR_PTR(-ENOBUFS);
@@ -244,6 +294,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
return 0;
}
+static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
+{
+ ip->i_cache[0] = bh;
+}
+
/**
* gfs2_inode_refresh - Refresh the incore copy of the dinode
* @ip: The GFS2 inode
@@ -688,7 +743,7 @@ out:
static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
const struct gfs2_inum_host *inum, unsigned int mode,
unsigned int uid, unsigned int gid,
- const u64 *generation, dev_t dev)
+ const u64 *generation, dev_t dev, struct buffer_head **bhp)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_dinode *di;
@@ -743,13 +798,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec);
di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec);
memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+
+ set_buffer_uptodate(dibh);
- brelse(dibh);
+ *bhp = dibh;
}
static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
unsigned int mode, const struct gfs2_inum_host *inum,
- const u64 *generation, dev_t dev)
+ const u64 *generation, dev_t dev, struct buffer_head **bhp)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
unsigned int uid, gid;
@@ -770,7 +827,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
if (error)
goto out_quota;
- init_dinode(dip, gl, inum, mode, uid, gid, generation, dev);
+ init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp);
gfs2_quota_change(dip, +1, uid, gid);
gfs2_trans_end(sdp);
@@ -909,6 +966,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
int error;
u64 generation;
+ struct buffer_head *bh=NULL;
if (!name->len || name->len > GFS2_FNAMESIZE)
return ERR_PTR(-ENAMETOOLONG);
@@ -935,16 +993,18 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
if (error)
goto fail_gunlock;
- error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
+ error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh);
if (error)
goto fail_gunlock2;
inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
inum.no_addr,
- inum.no_formal_ino);
+ inum.no_formal_ino, 0);
if (IS_ERR(inode))
goto fail_gunlock2;
+ gfs2_inode_bh(GFS2_I(inode), bh);
+
error = gfs2_inode_refresh(GFS2_I(inode));
if (error)
goto fail_gunlock2;
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 4517ac82c01..351ac87ab38 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -49,7 +49,8 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
void gfs2_inode_attr_in(struct gfs2_inode *ip);
void gfs2_set_iop(struct inode *inode);
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
- u64 no_addr, u64 no_formal_ino);
+ u64 no_addr, u64 no_formal_ino,
+ int skip_freeing);
struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
int gfs2_inode_refresh(struct gfs2_inode *ip);
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index 24d70f73b65..9e8265d2837 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/list.h>
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index fba1f1d87e4..1f7b038530b 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -346,15 +346,16 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
static unsigned int dev_poll(struct file *file, poll_table *wait)
{
+ unsigned int mask = 0;
+
poll_wait(file, &send_wq, wait);
spin_lock(&ops_lock);
- if (!list_empty(&send_list)) {
- spin_unlock(&ops_lock);
- return POLLIN | POLLRDNORM;
- }
+ if (!list_empty(&send_list))
+ mask = POLLIN | POLLRDNORM;
spin_unlock(&ops_lock);
- return 0;
+
+ return mask;
}
static const struct file_operations dev_fops = {
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index d9fe3ca40e1..ae9e6a25fe2 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = {
};
static struct kset gdlm_kset = {
- .kobj = {.name = "lock_dlm",},
.ktype = &gdlm_ktype,
};
@@ -224,6 +223,7 @@ int gdlm_sysfs_init(void)
{
int error;
+ kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
kobj_set_kset_s(&gdlm_kset, kernel_subsys);
error = kset_register(&gdlm_kset);
if (error)
diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
index 1aca51e4509..bd938f06481 100644
--- a/fs/gfs2/locking/dlm/thread.c
+++ b/fs/gfs2/locking/dlm/thread.c
@@ -268,20 +268,16 @@ static inline int check_drop(struct gdlm_ls *ls)
return 0;
}
-static int gdlm_thread(void *data)
+static int gdlm_thread(void *data, int blist)
{
struct gdlm_ls *ls = (struct gdlm_ls *) data;
struct gdlm_lock *lp = NULL;
- int blist = 0;
uint8_t complete, blocking, submit, drop;
DECLARE_WAITQUEUE(wait, current);
/* Only thread1 is allowed to do blocking callbacks since gfs
may wait for a completion callback within a blocking cb. */
- if (current == ls->thread1)
- blist = 1;
-
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&ls->thread_wait, &wait);
@@ -333,12 +329,22 @@ static int gdlm_thread(void *data)
return 0;
}
+static int gdlm_thread1(void *data)
+{
+ return gdlm_thread(data, 1);
+}
+
+static int gdlm_thread2(void *data)
+{
+ return gdlm_thread(data, 0);
+}
+
int gdlm_init_threads(struct gdlm_ls *ls)
{
struct task_struct *p;
int error;
- p = kthread_run(gdlm_thread, ls, "lock_dlm1");
+ p = kthread_run(gdlm_thread1, ls, "lock_dlm1");
error = IS_ERR(p);
if (error) {
log_error("can't start lock_dlm1 thread %d", error);
@@ -346,7 +352,7 @@ int gdlm_init_threads(struct gdlm_ls *ls)
}
ls->thread1 = p;
- p = kthread_run(gdlm_thread, ls, "lock_dlm2");
+ p = kthread_run(gdlm_thread2, ls, "lock_dlm2");
error = IS_ERR(p);
if (error) {
log_error("can't start lock_dlm2 thread %d", error);
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
index 0d149c8c493..d3b8ce6fbbe 100644
--- a/fs/gfs2/locking/nolock/main.c
+++ b/fs/gfs2/locking/nolock/main.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index f49a12e2408..7df70247325 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -60,6 +60,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
}
/**
+ * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters
+ * @mapping: The associated mapping (maybe NULL)
+ * @bd: The gfs2_bufdata to remove
+ *
+ * The log lock _must_ be held when calling this function
+ *
+ */
+
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
+{
+ bd->bd_ail = NULL;
+ list_del_init(&bd->bd_ail_st_list);
+ list_del_init(&bd->bd_ail_gl_list);
+ atomic_dec(&bd->bd_gl->gl_ail_count);
+ if (mapping)
+ gfs2_meta_cache_flush(GFS2_I(mapping->host));
+ brelse(bd->bd_bh);
+}
+
+/**
* gfs2_ail1_start_one - Start I/O on a part of the AIL
* @sdp: the filesystem
* @tr: the part of the AIL
@@ -83,17 +103,9 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
gfs2_assert(sdp, bd->bd_ail == ai);
- if (!bh){
- list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
- continue;
- }
-
if (!buffer_busy(bh)) {
- if (!buffer_uptodate(bh)) {
- gfs2_log_unlock(sdp);
+ if (!buffer_uptodate(bh))
gfs2_io_error_bh(sdp, bh);
- gfs2_log_lock(sdp);
- }
list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
continue;
}
@@ -103,9 +115,16 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+ get_bh(bh);
gfs2_log_unlock(sdp);
- wait_on_buffer(bh);
- ll_rw_block(WRITE, 1, &bh);
+ lock_buffer(bh);
+ if (test_clear_buffer_dirty(bh)) {
+ bh->b_end_io = end_buffer_write_sync;
+ submit_bh(WRITE, bh);
+ } else {
+ unlock_buffer(bh);
+ brelse(bh);
+ }
gfs2_log_lock(sdp);
retry = 1;
@@ -130,11 +149,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl
bd_ail_st_list) {
bh = bd->bd_bh;
- if (!bh){
- list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
- continue;
- }
-
gfs2_assert(sdp, bd->bd_ail == ai);
if (buffer_busy(bh)) {
@@ -155,13 +169,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl
static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
{
- struct list_head *head = &sdp->sd_ail1_list;
+ struct list_head *head;
u64 sync_gen;
struct list_head *first;
struct gfs2_ail *first_ai, *ai, *tmp;
int done = 0;
gfs2_log_lock(sdp);
+ head = &sdp->sd_ail1_list;
if (list_empty(head)) {
gfs2_log_unlock(sdp);
return;
@@ -233,11 +248,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
bd = list_entry(head->prev, struct gfs2_bufdata,
bd_ail_st_list);
gfs2_assert(sdp, bd->bd_ail == ai);
- bd->bd_ail = NULL;
- list_del(&bd->bd_ail_st_list);
- list_del(&bd->bd_ail_gl_list);
- atomic_dec(&bd->bd_gl->gl_ail_count);
- brelse(bd->bd_bh);
+ gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
}
}
@@ -439,10 +450,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
return tail;
}
-static inline void log_incr_head(struct gfs2_sbd *sdp)
+void gfs2_log_incr_head(struct gfs2_sbd *sdp)
{
if (sdp->sd_log_flush_head == sdp->sd_log_tail)
- gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
+ BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
sdp->sd_log_flush_head = 0;
@@ -451,6 +462,23 @@ static inline void log_incr_head(struct gfs2_sbd *sdp)
}
/**
+ * gfs2_log_write_endio - End of I/O for a log buffer
+ * @bh: The buffer head
+ * @uptodate: I/O Status
+ *
+ */
+
+static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
+{
+ struct gfs2_sbd *sdp = bh->b_private;
+ bh->b_private = NULL;
+
+ end_buffer_write_sync(bh, uptodate);
+ if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+ wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
* gfs2_log_get_buf - Get and initialize a buffer to use for log control data
* @sdp: The GFS2 superblock
*
@@ -460,25 +488,43 @@ static inline void log_incr_head(struct gfs2_sbd *sdp)
struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
{
u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
- struct gfs2_log_buf *lb;
struct buffer_head *bh;
- lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
- list_add(&lb->lb_list, &sdp->sd_log_flush_list);
-
- bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
+ bh = sb_getblk(sdp->sd_vfs, blkno);
lock_buffer(bh);
memset(bh->b_data, 0, bh->b_size);
set_buffer_uptodate(bh);
clear_buffer_dirty(bh);
- unlock_buffer(bh);
-
- log_incr_head(sdp);
+ gfs2_log_incr_head(sdp);
+ atomic_inc(&sdp->sd_log_in_flight);
+ bh->b_private = sdp;
+ bh->b_end_io = gfs2_log_write_endio;
return bh;
}
/**
+ * gfs2_fake_write_endio -
+ * @bh: The buffer head
+ * @uptodate: The I/O Status
+ *
+ */
+
+static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
+{
+ struct buffer_head *real_bh = bh->b_private;
+ struct gfs2_bufdata *bd = real_bh->b_private;
+ struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
+
+ end_buffer_write_sync(bh, uptodate);
+ free_buffer_head(bh);
+ unlock_buffer(real_bh);
+ brelse(real_bh);
+ if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+ wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
* gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
* @sdp: the filesystem
* @data: the data the buffer_head should point to
@@ -490,22 +536,20 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
struct buffer_head *real)
{
u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
- struct gfs2_log_buf *lb;
struct buffer_head *bh;
- lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
- list_add(&lb->lb_list, &sdp->sd_log_flush_list);
- lb->lb_real = real;
-
- bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
+ bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
atomic_set(&bh->b_count, 1);
- bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
+ bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
set_bh_page(bh, real->b_page, bh_offset(real));
bh->b_blocknr = blkno;
bh->b_size = sdp->sd_sb.sb_bsize;
bh->b_bdev = sdp->sd_vfs->s_bdev;
+ bh->b_private = real;
+ bh->b_end_io = gfs2_fake_write_endio;
- log_incr_head(sdp);
+ gfs2_log_incr_head(sdp);
+ atomic_inc(&sdp->sd_log_in_flight);
return bh;
}
@@ -572,45 +616,75 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
gfs2_assert_withdraw(sdp, !pull);
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
- log_incr_head(sdp);
+ gfs2_log_incr_head(sdp);
}
static void log_flush_commit(struct gfs2_sbd *sdp)
{
- struct list_head *head = &sdp->sd_log_flush_list;
- struct gfs2_log_buf *lb;
- struct buffer_head *bh;
- int flushcount = 0;
+ DEFINE_WAIT(wait);
+
+ if (atomic_read(&sdp->sd_log_in_flight)) {
+ do {
+ prepare_to_wait(&sdp->sd_log_flush_wait, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&sdp->sd_log_in_flight))
+ io_schedule();
+ } while(atomic_read(&sdp->sd_log_in_flight));
+ finish_wait(&sdp->sd_log_flush_wait, &wait);
+ }
- while (!list_empty(head)) {
- lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
- list_del(&lb->lb_list);
- bh = lb->lb_bh;
+ log_write_header(sdp, 0, 0);
+}
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- gfs2_io_error_bh(sdp, bh);
- if (lb->lb_real) {
- while (atomic_read(&bh->b_count) != 1) /* Grrrr... */
- schedule();
- free_buffer_head(bh);
- } else
+static void gfs2_ordered_write(struct gfs2_sbd *sdp)
+{
+ struct gfs2_bufdata *bd;
+ struct buffer_head *bh;
+ LIST_HEAD(written);
+
+ gfs2_log_lock(sdp);
+ while (!list_empty(&sdp->sd_log_le_ordered)) {
+ bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
+ list_move(&bd->bd_le.le_list, &written);
+ bh = bd->bd_bh;
+ if (!buffer_dirty(bh))
+ continue;
+ get_bh(bh);
+ gfs2_log_unlock(sdp);
+ lock_buffer(bh);
+ if (test_clear_buffer_dirty(bh)) {
+ bh->b_end_io = end_buffer_write_sync;
+ submit_bh(WRITE, bh);
+ } else {
+ unlock_buffer(bh);
brelse(bh);
- kfree(lb);
- flushcount++;
+ }
+ gfs2_log_lock(sdp);
}
+ list_splice(&written, &sdp->sd_log_le_ordered);
+ gfs2_log_unlock(sdp);
+}
- /* If nothing was journaled, the header is unplanned and unwanted. */
- if (flushcount) {
- log_write_header(sdp, 0, 0);
- } else {
- unsigned int tail;
- tail = current_tail(sdp);
+static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
+{
+ struct gfs2_bufdata *bd;
+ struct buffer_head *bh;
- gfs2_ail1_empty(sdp, 0);
- if (sdp->sd_log_tail != tail)
- log_pull_tail(sdp, tail);
+ gfs2_log_lock(sdp);
+ while (!list_empty(&sdp->sd_log_le_ordered)) {
+ bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list);
+ bh = bd->bd_bh;
+ if (buffer_locked(bh)) {
+ get_bh(bh);
+ gfs2_log_unlock(sdp);
+ wait_on_buffer(bh);
+ brelse(bh);
+ gfs2_log_lock(sdp);
+ continue;
+ }
+ list_del_init(&bd->bd_le.le_list);
}
+ gfs2_log_unlock(sdp);
}
/**
@@ -640,10 +714,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
INIT_LIST_HEAD(&ai->ai_ail1_list);
INIT_LIST_HEAD(&ai->ai_ail2_list);
- gfs2_assert_withdraw(sdp,
- sdp->sd_log_num_buf + sdp->sd_log_num_jdata ==
- sdp->sd_log_commited_buf +
- sdp->sd_log_commited_databuf);
+ if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) {
+ printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf,
+ sdp->sd_log_commited_buf);
+ gfs2_assert_withdraw(sdp, 0);
+ }
+ if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) {
+ printk(KERN_INFO "GFS2: log databuf %u %u\n",
+ sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf);
+ gfs2_assert_withdraw(sdp, 0);
+ }
gfs2_assert_withdraw(sdp,
sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
@@ -651,8 +731,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
sdp->sd_log_flush_wrapped = 0;
ai->ai_first = sdp->sd_log_flush_head;
+ gfs2_ordered_write(sdp);
lops_before_commit(sdp);
- if (!list_empty(&sdp->sd_log_flush_list))
+ gfs2_ordered_wait(sdp);
+
+ if (sdp->sd_log_head != sdp->sd_log_flush_head)
log_flush_commit(sdp);
else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
gfs2_log_lock(sdp);
@@ -744,7 +827,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
- gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index 8e7aa0f2910..dae28240062 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -52,12 +52,14 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+void gfs2_log_incr_head(struct gfs2_sbd *sdp);
struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
struct buffer_head *real);
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
void gfs2_log_shutdown(struct gfs2_sbd *sdp);
void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 3b395c41b2f..6c27cea761c 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -27,7 +27,104 @@
#include "trans.h"
#include "util.h"
-static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+/**
+ * gfs2_pin - Pin a buffer in memory
+ * @sdp: The superblock
+ * @bh: The buffer to be pinned
+ *
+ * The log lock must be held when calling this function
+ */
+static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+ struct gfs2_bufdata *bd;
+
+ gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
+
+ clear_buffer_dirty(bh);
+ if (test_set_buffer_pinned(bh))
+ gfs2_assert_withdraw(sdp, 0);
+ if (!buffer_uptodate(bh))
+ gfs2_io_error_bh(sdp, bh);
+ bd = bh->b_private;
+ /* If this buffer is in the AIL and it has already been written
+ * to in-place disk block, remove it from the AIL.
+ */
+ if (bd->bd_ail)
+ list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+ get_bh(bh);
+}
+
+/**
+ * gfs2_unpin - Unpin a buffer
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to unpin
+ * @ai:
+ *
+ */
+
+static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ struct gfs2_ail *ai)
+{
+ struct gfs2_bufdata *bd = bh->b_private;
+
+ gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
+
+ if (!buffer_pinned(bh))
+ gfs2_assert_withdraw(sdp, 0);
+
+ lock_buffer(bh);
+ mark_buffer_dirty(bh);
+ clear_buffer_pinned(bh);
+
+ gfs2_log_lock(sdp);
+ if (bd->bd_ail) {
+ list_del(&bd->bd_ail_st_list);
+ brelse(bh);
+ } else {
+ struct gfs2_glock *gl = bd->bd_gl;
+ list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
+ atomic_inc(&gl->gl_ail_count);
+ }
+ bd->bd_ail = ai;
+ list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+ gfs2_log_unlock(sdp);
+ unlock_buffer(bh);
+}
+
+
+static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh)
+{
+ return (struct gfs2_log_descriptor *)bh->b_data;
+}
+
+static inline __be64 *bh_log_ptr(struct buffer_head *bh)
+{
+ struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+ return (__force __be64 *)(ld + 1);
+}
+
+static inline __be64 *bh_ptr_end(struct buffer_head *bh)
+{
+ return (__force __be64 *)(bh->b_data + bh->b_size);
+}
+
+
+static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
+{
+ struct buffer_head *bh = gfs2_log_get_buf(sdp);
+ struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+ ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+ ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+ ld->ld_type = cpu_to_be32(ld_type);
+ ld->ld_length = 0;
+ ld->ld_data1 = 0;
+ ld->ld_data2 = 0;
+ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+ return bh;
+}
+
+static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
{
struct gfs2_glock *gl;
struct gfs2_trans *tr = current->journal_info;
@@ -38,15 +135,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
return;
- gfs2_log_lock(sdp);
- if (!list_empty(&le->le_list)){
- gfs2_log_unlock(sdp);
+ if (!list_empty(&le->le_list))
return;
- }
+
gfs2_glock_hold(gl);
set_bit(GLF_DIRTY, &gl->gl_flags);
sdp->sd_log_num_gl++;
list_add(&le->le_list, &sdp->sd_log_le_gl);
+}
+
+static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ gfs2_log_lock(sdp);
+ __glock_lo_add(sdp, le);
gfs2_log_unlock(sdp);
}
@@ -71,30 +172,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
struct gfs2_trans *tr;
+ lock_buffer(bd->bd_bh);
gfs2_log_lock(sdp);
- if (!list_empty(&bd->bd_list_tr)) {
- gfs2_log_unlock(sdp);
- return;
- }
+ if (!list_empty(&bd->bd_list_tr))
+ goto out;
tr = current->journal_info;
tr->tr_touched = 1;
tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf);
- gfs2_log_unlock(sdp);
-
if (!list_empty(&le->le_list))
- return;
-
- gfs2_trans_add_gl(bd->bd_gl);
-
+ goto out;
+ __glock_lo_add(sdp, &bd->bd_gl->gl_le);
gfs2_meta_check(sdp, bd->bd_bh);
gfs2_pin(sdp, bd->bd_bh);
- gfs2_log_lock(sdp);
sdp->sd_log_num_buf++;
list_add(&le->le_list, &sdp->sd_log_le_buf);
- gfs2_log_unlock(sdp);
-
tr->tr_num_buf_new++;
+out:
+ gfs2_log_unlock(sdp);
+ unlock_buffer(bd->bd_bh);
}
static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
@@ -117,8 +213,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
struct buffer_head *bh;
struct gfs2_log_descriptor *ld;
struct gfs2_bufdata *bd1 = NULL, *bd2;
- unsigned int total = sdp->sd_log_num_buf;
- unsigned int offset = BUF_OFFSET;
+ unsigned int total;
unsigned int limit;
unsigned int num;
unsigned n;
@@ -127,22 +222,20 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
limit = buf_limit(sdp);
/* for 4k blocks, limit = 503 */
+ gfs2_log_lock(sdp);
+ total = sdp->sd_log_num_buf;
bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
while(total) {
num = total;
if (total > limit)
num = limit;
- bh = gfs2_log_get_buf(sdp);
- ld = (struct gfs2_log_descriptor *)bh->b_data;
- ptr = (__be64 *)(bh->b_data + offset);
- ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
- ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
- ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
- ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
+ gfs2_log_unlock(sdp);
+ bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA);
+ gfs2_log_lock(sdp);
+ ld = bh_log_desc(bh);
+ ptr = bh_log_ptr(bh);
ld->ld_length = cpu_to_be32(num + 1);
ld->ld_data1 = cpu_to_be32(num);
- ld->ld_data2 = cpu_to_be32(0);
- memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
n = 0;
list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
@@ -152,21 +245,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
break;
}
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ gfs2_log_unlock(sdp);
+ submit_bh(WRITE, bh);
+ gfs2_log_lock(sdp);
n = 0;
list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
bd_le.le_list) {
+ get_bh(bd2->bd_bh);
+ gfs2_log_unlock(sdp);
+ lock_buffer(bd2->bd_bh);
bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ submit_bh(WRITE, bh);
+ gfs2_log_lock(sdp);
if (++n >= num)
break;
}
+ BUG_ON(total < num);
total -= num;
}
+ gfs2_log_unlock(sdp);
}
static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
@@ -270,11 +369,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
tr = current->journal_info;
tr->tr_touched = 1;
tr->tr_num_revoke++;
-
- gfs2_log_lock(sdp);
sdp->sd_log_num_revoke++;
list_add(&le->le_list, &sdp->sd_log_le_revoke);
- gfs2_log_unlock(sdp);
}
static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
@@ -284,32 +380,25 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
struct buffer_head *bh;
unsigned int offset;
struct list_head *head = &sdp->sd_log_le_revoke;
- struct gfs2_revoke *rv;
+ struct gfs2_bufdata *bd;
if (!sdp->sd_log_num_revoke)
return;
- bh = gfs2_log_get_buf(sdp);
- ld = (struct gfs2_log_descriptor *)bh->b_data;
- ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
- ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
- ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
- ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
+ bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE);
+ ld = bh_log_desc(bh);
ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
sizeof(u64)));
ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
- ld->ld_data2 = cpu_to_be32(0);
- memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
offset = sizeof(struct gfs2_log_descriptor);
while (!list_empty(head)) {
- rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
- list_del_init(&rv->rv_le.le_list);
+ bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+ list_del_init(&bd->bd_le.le_list);
sdp->sd_log_num_revoke--;
if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ submit_bh(WRITE, bh);
bh = gfs2_log_get_buf(sdp);
mh = (struct gfs2_meta_header *)bh->b_data;
@@ -319,15 +408,14 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
offset = sizeof(struct gfs2_meta_header);
}
- *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
- kfree(rv);
+ *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno);
+ kmem_cache_free(gfs2_bufdata_cachep, bd);
offset += sizeof(u64);
}
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ submit_bh(WRITE, bh);
}
static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
@@ -466,222 +554,136 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
struct address_space *mapping = bd->bd_bh->b_page->mapping;
struct gfs2_inode *ip = GFS2_I(mapping->host);
+ lock_buffer(bd->bd_bh);
gfs2_log_lock(sdp);
- if (!list_empty(&bd->bd_list_tr)) {
- gfs2_log_unlock(sdp);
- return;
- }
+ if (!list_empty(&bd->bd_list_tr))
+ goto out;
tr->tr_touched = 1;
if (gfs2_is_jdata(ip)) {
tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf);
}
- gfs2_log_unlock(sdp);
if (!list_empty(&le->le_list))
- return;
+ goto out;
- gfs2_trans_add_gl(bd->bd_gl);
+ __glock_lo_add(sdp, &bd->bd_gl->gl_le);
if (gfs2_is_jdata(ip)) {
- sdp->sd_log_num_jdata++;
gfs2_pin(sdp, bd->bd_bh);
tr->tr_num_databuf_new++;
+ sdp->sd_log_num_databuf++;
+ list_add(&le->le_list, &sdp->sd_log_le_databuf);
+ } else {
+ list_add(&le->le_list, &sdp->sd_log_le_ordered);
}
- gfs2_log_lock(sdp);
- sdp->sd_log_num_databuf++;
- list_add(&le->le_list, &sdp->sd_log_le_databuf);
+out:
gfs2_log_unlock(sdp);
+ unlock_buffer(bd->bd_bh);
}
-static int gfs2_check_magic(struct buffer_head *bh)
+static void gfs2_check_magic(struct buffer_head *bh)
{
- struct page *page = bh->b_page;
void *kaddr;
__be32 *ptr;
- int rv = 0;
- kaddr = kmap_atomic(page, KM_USER0);
+ clear_buffer_escaped(bh);
+ kaddr = kmap_atomic(bh->b_page, KM_USER0);
ptr = kaddr + bh_offset(bh);
if (*ptr == cpu_to_be32(GFS2_MAGIC))
- rv = 1;
+ set_buffer_escaped(bh);
kunmap_atomic(kaddr, KM_USER0);
-
- return rv;
}
-/**
- * databuf_lo_before_commit - Scan the data buffers, writing as we go
- *
- * Here we scan through the lists of buffers and make the assumption
- * that any buffer thats been pinned is being journaled, and that
- * any unpinned buffer is an ordered write data buffer and therefore
- * will be written back rather than journaled.
- */
-static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ struct list_head *list, struct list_head *done,
+ unsigned int n)
{
- LIST_HEAD(started);
- struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
- struct buffer_head *bh = NULL,*bh1 = NULL;
+ struct buffer_head *bh1;
struct gfs2_log_descriptor *ld;
- unsigned int limit;
- unsigned int total_dbuf;
- unsigned int total_jdata = sdp->sd_log_num_jdata;
- unsigned int num, n;
- __be64 *ptr = NULL;
+ struct gfs2_bufdata *bd;
+ __be64 *ptr;
+
+ if (!bh)
+ return;
- limit = databuf_limit(sdp);
+ ld = bh_log_desc(bh);
+ ld->ld_length = cpu_to_be32(n + 1);
+ ld->ld_data1 = cpu_to_be32(n);
- /*
- * Start writing ordered buffers, write journaled buffers
- * into the log along with a header
- */
+ ptr = bh_log_ptr(bh);
+
+ get_bh(bh);
+ submit_bh(WRITE, bh);
gfs2_log_lock(sdp);
- total_dbuf = sdp->sd_log_num_databuf;
- bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
- bd_le.le_list);
- while(total_dbuf) {
- num = total_jdata;
- if (num > limit)
- num = limit;
- n = 0;
- list_for_each_entry_safe_continue(bd1, bdt,
- &sdp->sd_log_le_databuf,
- bd_le.le_list) {
- /* store off the buffer head in a local ptr since
- * gfs2_bufdata might change when we drop the log lock
- */
- bh1 = bd1->bd_bh;
-
- /* An ordered write buffer */
- if (bh1 && !buffer_pinned(bh1)) {
- list_move(&bd1->bd_le.le_list, &started);
- if (bd1 == bd2) {
- bd2 = NULL;
- bd2 = list_prepare_entry(bd2,
- &sdp->sd_log_le_databuf,
- bd_le.le_list);
- }
- total_dbuf--;
- if (bh1) {
- if (buffer_dirty(bh1)) {
- get_bh(bh1);
-
- gfs2_log_unlock(sdp);
-
- ll_rw_block(SWRITE, 1, &bh1);
- brelse(bh1);
-
- gfs2_log_lock(sdp);
- }
- continue;
- }
- continue;
- } else if (bh1) { /* A journaled buffer */
- int magic;
- gfs2_log_unlock(sdp);
- if (!bh) {
- bh = gfs2_log_get_buf(sdp);
- ld = (struct gfs2_log_descriptor *)
- bh->b_data;
- ptr = (__be64 *)(bh->b_data +
- DATABUF_OFFSET);
- ld->ld_header.mh_magic =
- cpu_to_be32(GFS2_MAGIC);
- ld->ld_header.mh_type =
- cpu_to_be32(GFS2_METATYPE_LD);
- ld->ld_header.mh_format =
- cpu_to_be32(GFS2_FORMAT_LD);
- ld->ld_type =
- cpu_to_be32(GFS2_LOG_DESC_JDATA);
- ld->ld_length = cpu_to_be32(num + 1);
- ld->ld_data1 = cpu_to_be32(num);
- ld->ld_data2 = cpu_to_be32(0);
- memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
- }
- magic = gfs2_check_magic(bh1);
- *ptr++ = cpu_to_be64(bh1->b_blocknr);
- *ptr++ = cpu_to_be64((__u64)magic);
- clear_buffer_escaped(bh1);
- if (unlikely(magic != 0))
- set_buffer_escaped(bh1);
- gfs2_log_lock(sdp);
- if (++n >= num)
- break;
- } else if (!bh1) {
- total_dbuf--;
- sdp->sd_log_num_databuf--;
- list_del_init(&bd1->bd_le.le_list);
- if (bd1 == bd2) {
- bd2 = NULL;
- bd2 = list_prepare_entry(bd2,
- &sdp->sd_log_le_databuf,
- bd_le.le_list);
- }
- kmem_cache_free(gfs2_bufdata_cachep, bd1);
- }
+ while(!list_empty(list)) {
+ bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list);
+ list_move_tail(&bd->bd_le.le_list, done);
+ get_bh(bd->bd_bh);
+ while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) {
+ gfs2_log_incr_head(sdp);
+ ptr += 2;
}
gfs2_log_unlock(sdp);
- if (bh) {
- set_buffer_mapped(bh);
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
- bh = NULL;
+ lock_buffer(bd->bd_bh);
+ if (buffer_escaped(bd->bd_bh)) {
+ void *kaddr;
+ bh1 = gfs2_log_get_buf(sdp);
+ kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0);
+ memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh),
+ bh1->b_size);
+ kunmap_atomic(kaddr, KM_USER0);
+ *(__be32 *)bh1->b_data = 0;
+ clear_buffer_escaped(bd->bd_bh);
+ unlock_buffer(bd->bd_bh);
+ brelse(bd->bd_bh);
+ } else {
+ bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh);
}
- n = 0;
+ submit_bh(WRITE, bh1);
gfs2_log_lock(sdp);
- list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
- bd_le.le_list) {
- if (!bd2->bd_bh)
- continue;
- /* copy buffer if it needs escaping */
- gfs2_log_unlock(sdp);
- if (unlikely(buffer_escaped(bd2->bd_bh))) {
- void *kaddr;
- struct page *page = bd2->bd_bh->b_page;
- bh = gfs2_log_get_buf(sdp);
- kaddr = kmap_atomic(page, KM_USER0);
- memcpy(bh->b_data,
- kaddr + bh_offset(bd2->bd_bh),
- sdp->sd_sb.sb_bsize);
- kunmap_atomic(kaddr, KM_USER0);
- *(__be32 *)bh->b_data = 0;
- } else {
- bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
- }
- set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
- gfs2_log_lock(sdp);
- if (++n >= num)
- break;
- }
- bh = NULL;
- BUG_ON(total_dbuf < num);
- total_dbuf -= num;
- total_jdata -= num;
+ ptr += 2;
}
gfs2_log_unlock(sdp);
+ brelse(bh);
+}
- /* Wait on all ordered buffers */
- while (!list_empty(&started)) {
- gfs2_log_lock(sdp);
- bd1 = list_entry(started.next, struct gfs2_bufdata,
- bd_le.le_list);
- list_del_init(&bd1->bd_le.le_list);
- sdp->sd_log_num_databuf--;
- bh = bd1->bd_bh;
- if (bh) {
- bh->b_private = NULL;
- get_bh(bh);
- gfs2_log_unlock(sdp);
- wait_on_buffer(bh);
- brelse(bh);
- } else
- gfs2_log_unlock(sdp);
+/**
+ * databuf_lo_before_commit - Scan the data buffers, writing as we go
+ *
+ */
- kmem_cache_free(gfs2_bufdata_cachep, bd1);
- }
+static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+ struct gfs2_bufdata *bd = NULL;
+ struct buffer_head *bh = NULL;
+ unsigned int n = 0;
+ __be64 *ptr = NULL, *end = NULL;
+ LIST_HEAD(processed);
+ LIST_HEAD(in_progress);
- /* We've removed all the ordered write bufs here, so only jdata left */
- gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
+ gfs2_log_lock(sdp);
+ while (!list_empty(&sdp->sd_log_le_databuf)) {
+ if (ptr == end) {
+ gfs2_log_unlock(sdp);
+ gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+ n = 0;
+ bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA);
+ ptr = bh_log_ptr(bh);
+ end = bh_ptr_end(bh) - 1;
+ gfs2_log_lock(sdp);
+ continue;
+ }
+ bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list);
+ list_move_tail(&bd->bd_le.le_list, &in_progress);
+ gfs2_check_magic(bd->bd_bh);
+ *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr);
+ *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0);
+ n++;
+ }
+ gfs2_log_unlock(sdp);
+ gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+ gfs2_log_lock(sdp);
+ list_splice(&processed, &sdp->sd_log_le_databuf);
+ gfs2_log_unlock(sdp);
}
static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
@@ -765,11 +767,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
list_del_init(&bd->bd_le.le_list);
sdp->sd_log_num_databuf--;
- sdp->sd_log_num_jdata--;
gfs2_unpin(sdp, bd->bd_bh, ai);
}
gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
- gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
}
@@ -817,10 +817,10 @@ const struct gfs2_log_operations gfs2_databuf_lops = {
const struct gfs2_log_operations *gfs2_log_ops[] = {
&gfs2_glock_lops,
+ &gfs2_databuf_lops,
&gfs2_buf_lops,
- &gfs2_revoke_lops,
&gfs2_rg_lops,
- &gfs2_databuf_lops,
+ &gfs2_revoke_lops,
NULL,
};
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index d5d4e68b880..79c91fd8381 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -107,6 +107,8 @@ static int __init init_gfs2_fs(void)
fail_unregister:
unregister_filesystem(&gfs2_fs_type);
fail:
+ gfs2_glock_exit();
+
if (gfs2_bufdata_cachep)
kmem_cache_destroy(gfs2_bufdata_cachep);
@@ -127,6 +129,7 @@ fail:
static void __exit exit_gfs2_fs(void)
{
+ gfs2_glock_exit();
gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type);
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 8da343b34ae..4da423985e4 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -297,74 +297,35 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
unlock_page(bh->b_page);
}
-/**
- * gfs2_pin - Pin a buffer in memory
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to be pinned
- *
- */
-
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta)
{
+ struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host);
struct gfs2_bufdata *bd = bh->b_private;
-
- gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
-
- if (test_set_buffer_pinned(bh))
- gfs2_assert_withdraw(sdp, 0);
-
- wait_on_buffer(bh);
-
- /* If this buffer is in the AIL and it has already been written
- to in-place disk block, remove it from the AIL. */
-
- gfs2_log_lock(sdp);
- if (bd->bd_ail && !buffer_in_io(bh))
- list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
- gfs2_log_unlock(sdp);
-
- clear_buffer_dirty(bh);
- wait_on_buffer(bh);
-
- if (!buffer_uptodate(bh))
- gfs2_io_error_bh(sdp, bh);
-
- get_bh(bh);
-}
-
-/**
- * gfs2_unpin - Unpin a buffer
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to unpin
- * @ai:
- *
- */
-
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
- struct gfs2_ail *ai)
-{
- struct gfs2_bufdata *bd = bh->b_private;
-
- gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
-
- if (!buffer_pinned(bh))
- gfs2_assert_withdraw(sdp, 0);
-
- mark_buffer_dirty(bh);
- clear_buffer_pinned(bh);
-
- gfs2_log_lock(sdp);
- if (bd->bd_ail) {
- list_del(&bd->bd_ail_st_list);
+ if (test_clear_buffer_pinned(bh)) {
+ list_del_init(&bd->bd_le.le_list);
+ if (meta) {
+ gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
+ sdp->sd_log_num_buf--;
+ tr->tr_num_buf_rm++;
+ } else {
+ gfs2_assert_warn(sdp, sdp->sd_log_num_databuf);
+ sdp->sd_log_num_databuf--;
+ tr->tr_num_databuf_rm++;
+ }
+ tr->tr_touched = 1;
brelse(bh);
- } else {
- struct gfs2_glock *gl = bd->bd_gl;
- list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
- atomic_inc(&gl->gl_ail_count);
}
- bd->bd_ail = ai;
- list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
- gfs2_log_unlock(sdp);
+ if (bd) {
+ if (bd->bd_ail) {
+ gfs2_remove_from_ail(NULL, bd);
+ bh->b_private = NULL;
+ bd->bd_bh = NULL;
+ bd->bd_blkno = bh->b_blocknr;
+ gfs2_trans_add_revoke(sdp, bd);
+ }
+ }
+ clear_buffer_dirty(bh);
+ clear_buffer_uptodate(bh);
}
/**
@@ -383,44 +344,11 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
while (blen) {
bh = getbuf(ip->i_gl, bstart, NO_CREATE);
if (bh) {
- struct gfs2_bufdata *bd = bh->b_private;
-
- if (test_clear_buffer_pinned(bh)) {
- struct gfs2_trans *tr = current->journal_info;
- struct gfs2_inode *bh_ip =
- GFS2_I(bh->b_page->mapping->host);
-
- gfs2_log_lock(sdp);
- list_del_init(&bd->bd_le.le_list);
- gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
- sdp->sd_log_num_buf--;
- gfs2_log_unlock(sdp);
- if (bh_ip->i_inode.i_private != NULL)
- tr->tr_num_databuf_rm++;
- else
- tr->tr_num_buf_rm++;
- brelse(bh);
- }
- if (bd) {
- gfs2_log_lock(sdp);
- if (bd->bd_ail) {
- u64 blkno = bh->b_blocknr;
- bd->bd_ail = NULL;
- list_del(&bd->bd_ail_st_list);
- list_del(&bd->bd_ail_gl_list);
- atomic_dec(&bd->bd_gl->gl_ail_count);
- brelse(bh);
- gfs2_log_unlock(sdp);
- gfs2_trans_add_revoke(sdp, blkno);
- } else
- gfs2_log_unlock(sdp);
- }
-
lock_buffer(bh);
- clear_buffer_dirty(bh);
- clear_buffer_uptodate(bh);
+ gfs2_log_lock(sdp);
+ gfs2_remove_from_journal(bh, current->journal_info, 1);
+ gfs2_log_unlock(sdp);
unlock_buffer(bh);
-
brelse(bh);
}
@@ -446,10 +374,10 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)
for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
bh_slot = &ip->i_cache[x];
- if (!*bh_slot)
- break;
- brelse(*bh_slot);
- *bh_slot = NULL;
+ if (*bh_slot) {
+ brelse(*bh_slot);
+ *bh_slot = NULL;
+ }
}
spin_unlock(&ip->i_spin);
diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
index 527bf19d969..b7048222ebb 100644
--- a/fs/gfs2/meta_io.h
+++ b/fs/gfs2/meta_io.h
@@ -50,9 +50,9 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
int meta);
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
- struct gfs2_ail *ai);
+
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
+ int meta);
void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index 4864659555d..b941f9f9f95 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -42,6 +42,7 @@ enum {
Opt_nosuiddir,
Opt_data_writeback,
Opt_data_ordered,
+ Opt_err,
};
static match_table_t tokens = {
@@ -64,7 +65,8 @@ static match_table_t tokens = {
{Opt_suiddir, "suiddir"},
{Opt_nosuiddir, "nosuiddir"},
{Opt_data_writeback, "data=writeback"},
- {Opt_data_ordered, "data=ordered"}
+ {Opt_data_ordered, "data=ordered"},
+ {Opt_err, NULL}
};
/**
@@ -237,6 +239,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
case Opt_data_ordered:
args->ar_data = GFS2_DATA_ORDERED;
break;
+ case Opt_err:
default:
fs_info(sdp, "unknown option: %s\n", o);
error = -EINVAL;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 42a5f58f6fc..873a511ef2b 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -90,7 +90,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
error = gfs2_block_map(inode, lblock, 0, bh_result);
if (error)
return error;
- if (bh_result->b_blocknr == 0)
+ if (!buffer_mapped(bh_result))
return -EIO;
return 0;
}
@@ -414,7 +414,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
if (ind_blocks || data_blocks)
rblocks += RES_STATFS + RES_QUOTA;
- error = gfs2_trans_begin(sdp, rblocks, 0);
+ error = gfs2_trans_begin(sdp, rblocks,
+ PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
if (error)
goto out_trans_fail;
@@ -616,58 +617,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
return dblock;
}
-static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
+static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)
{
struct gfs2_bufdata *bd;
+ lock_buffer(bh);
gfs2_log_lock(sdp);
+ clear_buffer_dirty(bh);
bd = bh->b_private;
if (bd) {
- bd->bd_bh = NULL;
- bh->b_private = NULL;
- if (!bd->bd_ail && list_empty(&bd->bd_le.le_list))
- kmem_cache_free(gfs2_bufdata_cachep, bd);
+ if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh))
+ list_del_init(&bd->bd_le.le_list);
+ else
+ gfs2_remove_from_journal(bh, current->journal_info, 0);
}
- gfs2_log_unlock(sdp);
-
- lock_buffer(bh);
- clear_buffer_dirty(bh);
bh->b_bdev = NULL;
clear_buffer_mapped(bh);
clear_buffer_req(bh);
clear_buffer_new(bh);
- clear_buffer_delay(bh);
+ gfs2_log_unlock(sdp);
unlock_buffer(bh);
}
static void gfs2_invalidatepage(struct page *page, unsigned long offset)
{
struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
- struct buffer_head *head, *bh, *next;
- unsigned int curr_off = 0;
+ struct buffer_head *bh, *head;
+ unsigned long pos = 0;
BUG_ON(!PageLocked(page));
if (offset == 0)
ClearPageChecked(page);
if (!page_has_buffers(page))
- return;
+ goto out;
bh = head = page_buffers(page);
do {
- unsigned int next_off = curr_off + bh->b_size;
- next = bh->b_this_page;
-
- if (offset <= curr_off)
- discard_buffer(sdp, bh);
-
- curr_off = next_off;
- bh = next;
+ if (offset <= pos)
+ gfs2_discard(sdp, bh);
+ pos += bh->b_size;
+ bh = bh->b_this_page;
} while (bh != head);
-
- if (!offset)
+out:
+ if (offset == 0)
try_to_release_page(page, 0);
-
- return;
}
/**
@@ -736,59 +729,6 @@ out:
}
/**
- * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out.
- * @bh: the buffer we're stuck on
- *
- */
-
-static void stuck_releasepage(struct buffer_head *bh)
-{
- struct inode *inode = bh->b_page->mapping->host;
- struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
- struct gfs2_bufdata *bd = bh->b_private;
- struct gfs2_glock *gl;
-static unsigned limit = 0;
-
- if (limit > 3)
- return;
- limit++;
-
- fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
- fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
- (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
- fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
- fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
-
- if (!bd)
- return;
-
- gl = bd->bd_gl;
-
- fs_warn(sdp, "gl = (%u, %llu)\n",
- gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
-
- fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
- (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
- (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
-
- if (gl->gl_ops == &gfs2_inode_glops) {
- struct gfs2_inode *ip = gl->gl_object;
- unsigned int x;
-
- if (!ip)
- return;
-
- fs_warn(sdp, "ip = %llu %llu\n",
- (unsigned long long)ip->i_no_formal_ino,
- (unsigned long long)ip->i_no_addr);
-
- for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
- fs_warn(sdp, "ip->i_cache[%u] = %s\n",
- x, (ip->i_cache[x]) ? "!NULL" : "NULL");
- }
-}
-
-/**
* gfs2_releasepage - free the metadata associated with a page
* @page: the page that's being released
* @gfp_mask: passed from Linux VFS, ignored by us
@@ -805,41 +745,39 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
struct buffer_head *bh, *head;
struct gfs2_bufdata *bd;
- unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
if (!page_has_buffers(page))
- goto out;
+ return 0;
+ gfs2_log_lock(sdp);
head = bh = page_buffers(page);
do {
- while (atomic_read(&bh->b_count)) {
- if (!atomic_read(&aspace->i_writecount))
- return 0;
-
- if (!(gfp_mask & __GFP_WAIT))
- return 0;
-
- if (time_after_eq(jiffies, t)) {
- stuck_releasepage(bh);
- /* should we withdraw here? */
- return 0;
- }
-
- yield();
- }
-
+ if (atomic_read(&bh->b_count))
+ goto cannot_release;
+ bd = bh->b_private;
+ if (bd && bd->bd_ail)
+ goto cannot_release;
gfs2_assert_warn(sdp, !buffer_pinned(bh));
gfs2_assert_warn(sdp, !buffer_dirty(bh));
+ bh = bh->b_this_page;
+ } while(bh != head);
+ gfs2_log_unlock(sdp);
+ head = bh = page_buffers(page);
+ do {
gfs2_log_lock(sdp);
bd = bh->b_private;
if (bd) {
gfs2_assert_warn(sdp, bd->bd_bh == bh);
gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
- gfs2_assert_warn(sdp, !bd->bd_ail);
- bd->bd_bh = NULL;
- if (!list_empty(&bd->bd_le.le_list))
- bd = NULL;
+ if (!list_empty(&bd->bd_le.le_list)) {
+ if (!buffer_pinned(bh))
+ list_del_init(&bd->bd_le.le_list);
+ else
+ bd = NULL;
+ }
+ if (bd)
+ bd->bd_bh = NULL;
bh->b_private = NULL;
}
gfs2_log_unlock(sdp);
@@ -849,8 +787,10 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
bh = bh->b_this_page;
} while (bh != head);
-out:
return try_to_free_buffers(page);
+cannot_release:
+ gfs2_log_unlock(sdp);
+ return 0;
}
const struct address_space_operations gfs2_file_aops = {
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index b8312edee0e..e2d1347796a 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -237,7 +237,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
inum->no_addr,
- 0);
+ 0, 0);
if (!inode)
goto fail;
if (IS_ERR(inode)) {
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 94d76ace0b9..7eb4b280ac6 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_POSIX))
return -ENOLCK;
- if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ if (__mandatory_lock(&ip->i_inode))
return -ENOLCK;
if (sdp->sd_args.ar_localflocks) {
@@ -571,7 +571,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
int error = 0;
state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
- flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
+ flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE
+ | GL_FLOCK;
mutex_lock(&fp->f_fl_mutex);
@@ -579,21 +580,19 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
if (gl) {
if (fl_gh->gh_state == state)
goto out;
- gfs2_glock_hold(gl);
flock_lock_file_wait(file,
&(struct file_lock){.fl_type = F_UNLCK});
- gfs2_glock_dq_uninit(fl_gh);
+ gfs2_glock_dq_wait(fl_gh);
+ gfs2_holder_reinit(state, flags, fl_gh);
} else {
error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
ip->i_no_addr, &gfs2_flock_glops,
CREATE, &gl);
if (error)
goto out;
+ gfs2_holder_init(gl, state, flags, fl_gh);
+ gfs2_glock_put(gl);
}
-
- gfs2_holder_init(gl, state, flags, fl_gh);
- gfs2_glock_put(gl);
-
error = gfs2_glock_nq(fl_gh);
if (error) {
gfs2_holder_uninit(fl_gh);
@@ -637,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_FLOCK))
return -ENOLCK;
- if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ if (__mandatory_lock(&ip->i_inode))
return -ENOLCK;
if (sdp->sd_args.ar_localflocks)
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index cf5aa505054..17de58e83d9 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -28,18 +28,18 @@
#include "lm.h"
#include "mount.h"
#include "ops_fstype.h"
+#include "ops_dentry.h"
#include "ops_super.h"
#include "recovery.h"
#include "rgrp.h"
#include "super.h"
#include "sys.h"
#include "util.h"
+#include "log.h"
#define DO 0
#define UNDO 1
-extern struct dentry_operations gfs2_dops;
-
static struct gfs2_sbd *init_sbd(struct super_block *sb)
{
struct gfs2_sbd *sdp;
@@ -82,13 +82,15 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
INIT_LIST_HEAD(&sdp->sd_log_le_rg);
INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
+ INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
mutex_init(&sdp->sd_log_reserve_mutex);
INIT_LIST_HEAD(&sdp->sd_ail1_list);
INIT_LIST_HEAD(&sdp->sd_ail2_list);
init_rwsem(&sdp->sd_log_flush_lock);
- INIT_LIST_HEAD(&sdp->sd_log_flush_list);
+ atomic_set(&sdp->sd_log_in_flight, 0);
+ init_waitqueue_head(&sdp->sd_log_flush_wait);
INIT_LIST_HEAD(&sdp->sd_revoke_list);
@@ -145,7 +147,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent)
snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
- while ((table = strchr(sdp->sd_table_name, '/')))
+ table = sdp->sd_table_name;
+ while ((table = strchr(table, '/')))
*table = '_';
out:
@@ -161,14 +164,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
if (undo)
goto fail_trans;
- p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
- error = IS_ERR(p);
- if (error) {
- fs_err(sdp, "can't start scand thread: %d\n", error);
- return error;
- }
- sdp->sd_scand_process = p;
-
for (sdp->sd_glockd_num = 0;
sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
sdp->sd_glockd_num++) {
@@ -229,14 +224,13 @@ fail:
while (sdp->sd_glockd_num--)
kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
- kthread_stop(sdp->sd_scand_process);
return error;
}
static inline struct inode *gfs2_lookup_root(struct super_block *sb,
u64 no_addr)
{
- return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0);
+ return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
}
static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
@@ -301,8 +295,9 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
fs_err(sdp, "can't get root dentry\n");
error = -ENOMEM;
iput(inode);
- }
- sb->s_root->d_op = &gfs2_dops;
+ } else
+ sb->s_root->d_op = &gfs2_dops;
+
out:
gfs2_glock_dq_uninit(&sb_gh);
return error;
@@ -368,7 +363,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
ip = GFS2_I(sdp->sd_jdesc->jd_inode);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
- LM_FLAG_NOEXP | GL_EXACT,
+ LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE,
&sdp->sd_jinode_gh);
if (error) {
fs_err(sdp, "can't acquire journal inode glock: %d\n",
@@ -818,7 +813,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
struct nameidata nd;
struct file_system_type *fstype;
struct super_block *sb = NULL, *s;
- struct list_head *l;
int error;
error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
@@ -830,8 +824,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
error = vfs_getattr(nd.mnt, nd.dentry, &stat);
fstype = get_fs_type("gfs2");
- list_for_each(l, &fstype->fs_supers) {
- s = list_entry(l, struct super_block, s_instances);
+ list_for_each_entry(s, &fstype->fs_supers, s_instances) {
if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
(S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
sb = s;
@@ -861,7 +854,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
error = -ENOENT;
goto error;
}
- sdp = (struct gfs2_sbd*) sb->s_fs_info;
+ sdp = sb->s_fs_info;
if (sdp->sd_vfs_meta) {
printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
error = -EBUSY;
@@ -896,7 +889,10 @@ error:
static void gfs2_kill_sb(struct super_block *sb)
{
- gfs2_delete_debugfs_file(sb->s_fs_info);
+ if (sb->s_fs_info) {
+ gfs2_delete_debugfs_file(sb->s_fs_info);
+ gfs2_meta_syncfs(sb->s_fs_info);
+ }
kill_block_super(sb);
}
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 911c115b5c6..291f0c7eaa3 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
mark_inode_dirty(inode);
break;
} else if (PTR_ERR(inode) != -EEXIST ||
- (nd->intent.open.flags & O_EXCL)) {
+ (nd && (nd->intent.open.flags & O_EXCL))) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
@@ -278,17 +278,25 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
- error = gfs2_glock_nq_m(3, ghs);
+ error = gfs2_glock_nq(ghs); /* parent */
if (error)
- goto out;
+ goto out_parent;
+
+ error = gfs2_glock_nq(ghs + 1); /* child */
+ if (error)
+ goto out_child;
+
+ error = gfs2_glock_nq(ghs + 2); /* rgrp */
+ if (error)
+ goto out_rgrp;
error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
if (error)
- goto out_gunlock;
+ goto out_rgrp;
error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
if (error)
- goto out_gunlock;
+ goto out_rgrp;
error = gfs2_dir_del(dip, &dentry->d_name);
if (error)
@@ -298,12 +306,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
out_end_trans:
gfs2_trans_end(sdp);
-out_gunlock:
- gfs2_glock_dq_m(3, ghs);
-out:
- gfs2_holder_uninit(ghs);
- gfs2_holder_uninit(ghs + 1);
+ gfs2_glock_dq(ghs + 2);
+out_rgrp:
gfs2_holder_uninit(ghs + 2);
+ gfs2_glock_dq(ghs + 1);
+out_child:
+ gfs2_holder_uninit(ghs + 1);
+ gfs2_glock_dq(ghs);
+out_parent:
+ gfs2_holder_uninit(ghs);
gfs2_glock_dq_uninit(&ri_gh);
return error;
}
@@ -894,12 +905,17 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
static int setattr_size(struct inode *inode, struct iattr *attr)
{
struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;
if (attr->ia_size != ip->i_di.di_size) {
- error = vmtruncate(inode, attr->ia_size);
+ error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error)
return error;
+ error = vmtruncate(inode, attr->ia_size);
+ gfs2_trans_end(sdp);
+ if (error)
+ return error;
}
error = gfs2_truncatei(ip, attr->ia_size);
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 603d940f115..950f31460e8 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb)
kthread_stop(sdp->sd_recoverd_process);
while (sdp->sd_glockd_num--)
kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
- kthread_stop(sdp->sd_scand_process);
if (!(sb->s_flags & MS_RDONLY)) {
error = gfs2_make_fs_ro(sdp);
@@ -456,12 +455,15 @@ static void gfs2_delete_inode(struct inode *inode)
}
error = gfs2_dinode_dealloc(ip);
- /*
- * Must do this before unlock to avoid trying to write back
- * potentially dirty data now that inode no longer exists
- * on disk.
- */
+ if (error)
+ goto out_unlock;
+
+ error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+ if (error)
+ goto out_unlock;
+ /* Needs to be done before glock release & also in a transaction */
truncate_inode_pages(&inode->i_data, 0);
+ gfs2_trans_end(sdp);
out_unlock:
gfs2_glock_dq(&ip->i_iopen_gh);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 6e546ee8f3d..addb51e0f13 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -70,6 +70,7 @@ struct gfs2_quota_host {
u64 qu_limit;
u64 qu_warn;
s64 qu_value;
+ u32 qu_ll_next;
};
struct gfs2_quota_change_host {
@@ -580,6 +581,7 @@ static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf)
qu->qu_limit = be64_to_cpu(str->qu_limit);
qu->qu_warn = be64_to_cpu(str->qu_warn);
qu->qu_value = be64_to_cpu(str->qu_value);
+ qu->qu_ll_next = be32_to_cpu(str->qu_ll_next);
}
static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
@@ -589,6 +591,7 @@ static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
str->qu_limit = cpu_to_be64(qu->qu_limit);
str->qu_warn = cpu_to_be64(qu->qu_warn);
str->qu_value = cpu_to_be64(qu->qu_value);
+ str->qu_ll_next = cpu_to_be32(qu->qu_ll_next);
memset(&str->qu_reserved, 0, sizeof(str->qu_reserved));
}
@@ -614,6 +617,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
s64 value;
int err = -EIO;
+ if (gfs2_is_stuffed(ip)) {
+ struct gfs2_alloc *al = NULL;
+ al = gfs2_alloc_get(ip);
+ /* just request 1 blk */
+ al->al_requested = 1;
+ gfs2_inplace_reserve(ip);
+ gfs2_unstuff_dinode(ip, NULL);
+ gfs2_inplace_release(ip);
+ gfs2_alloc_put(ip);
+ }
page = grab_cache_page(mapping, index);
if (!page)
return -ENOMEM;
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 5ada38c99a2..beb6c7ac008 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -469,7 +469,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
};
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
- LM_FLAG_NOEXP, &ji_gh);
+ LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
if (error)
goto fail_gunlock_j;
} else {
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index ce48c4594ec..708c287e1d0 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -31,6 +31,7 @@
#include "inode.h"
#define BFITNOENT ((u32)~0)
+#define NO_BLOCK ((u64)~0)
/*
* These routines are used by the resource group routines (rgrp.c)
@@ -116,8 +117,7 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
* @buffer: the buffer that holds the bitmaps
* @buflen: the length (in bytes) of the buffer
* @goal: start search at this block's bit-pair (within @buffer)
- * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
- * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
+ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for.
*
* Scope of @goal and returned block number is only within this bitmap buffer,
* not entire rgrp or filesystem. @buffer will be offset from the actual
@@ -137,9 +137,13 @@ static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
byte = buffer + (goal / GFS2_NBBY);
bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
end = buffer + buflen;
- alloc = (old_state & 1) ? 0 : 0x55;
+ alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
while (byte < end) {
+ /* If we're looking for a free block we can eliminate all
+ bitmap settings with 0x55, which represents four data
+ blocks in a row. If we're looking for a data block, we can
+ eliminate 0x00 which corresponds to four free blocks. */
if ((*byte & 0x55) == alloc) {
blk += (8 - bit) >> 1;
@@ -859,23 +863,28 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
{
struct inode *inode;
- u32 goal = 0;
+ u32 goal = 0, block;
u64 no_addr;
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
for(;;) {
if (goal >= rgd->rd_data)
break;
- goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
- GFS2_BLKST_UNLINKED);
- if (goal == BFITNOENT)
+ down_write(&sdp->sd_log_flush_lock);
+ block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
+ GFS2_BLKST_UNLINKED);
+ up_write(&sdp->sd_log_flush_lock);
+ if (block == BFITNOENT)
break;
- no_addr = goal + rgd->rd_data0;
+ /* rgblk_search can return a block < goal, so we need to
+ keep it marching forward. */
+ no_addr = block + rgd->rd_data0;
goal++;
- if (no_addr < *last_unlinked)
+ if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
continue;
*last_unlinked = no_addr;
inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,
- no_addr, -1);
+ no_addr, -1, 1);
if (!IS_ERR(inode))
return inode;
}
@@ -1152,7 +1161,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
struct gfs2_alloc *al = &ip->i_alloc;
struct inode *inode;
int error = 0;
- u64 last_unlinked = 0;
+ u64 last_unlinked = NO_BLOCK;
if (gfs2_assert_warn(sdp, al->al_requested))
return -EINVAL;
@@ -1289,7 +1298,9 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
allocatable block anywhere else, we want to be able wrap around and
search in the first part of our first-searched bit block. */
for (x = 0; x <= length; x++) {
- if (bi->bi_clone)
+ /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
+ bitmaps, so we must search the originals for that. */
+ if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
bi->bi_len, goal, old_state);
else
@@ -1305,9 +1316,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
goal = 0;
}
- if (old_state != new_state) {
- gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT);
-
+ if (blk != BFITNOENT && old_state != new_state) {
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
bi->bi_len, blk, new_state);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 2473e2a86d1..dd3e737f528 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -58,7 +58,6 @@ void gfs2_tune_init(struct gfs2_tune *gt)
gt->gt_incore_log_blocks = 1024;
gt->gt_log_flush_secs = 60;
gt->gt_jindex_refresh_secs = 60;
- gt->gt_scand_secs = 15;
gt->gt_recoverd_secs = 60;
gt->gt_logd_secs = 1;
gt->gt_quotad_secs = 5;
@@ -169,7 +168,6 @@ static void end_bio_io_page(struct bio *bio, int error)
else
printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
unlock_page(page);
- return 0;
}
static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf)
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index c26c21b53c1..06e0b7768d9 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = {
};
static struct kset gfs2_kset = {
- .kobj = {.name = "gfs2"},
.ktype = &gfs2_ktype,
};
@@ -442,7 +441,6 @@ TUNE_ATTR(quota_simul_sync, 1);
TUNE_ATTR(quota_cache_secs, 1);
TUNE_ATTR(stall_secs, 1);
TUNE_ATTR(statfs_quantum, 1);
-TUNE_ATTR_DAEMON(scand_secs, scand_process);
TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
TUNE_ATTR_DAEMON(logd_secs, logd_process);
TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
@@ -464,7 +462,6 @@ static struct attribute *tune_attrs[] = {
&tune_attr_quota_cache_secs.attr,
&tune_attr_stall_secs.attr,
&tune_attr_statfs_quantum.attr,
- &tune_attr_scand_secs.attr,
&tune_attr_recoverd_secs.attr,
&tune_attr_logd_secs.attr,
&tune_attr_quotad_secs.attr,
@@ -553,6 +550,7 @@ int gfs2_sys_init(void)
{
gfs2_sys_margs = NULL;
spin_lock_init(&gfs2_sys_margs_lock);
+ kobject_set_name(&gfs2_kset.kobj, "gfs2");
kobj_set_kset_s(&gfs2_kset, fs_subsys);
return kset_register(&gfs2_kset);
}
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index f8dabf8446b..717983e2c2a 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -142,25 +142,25 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
lops_add(sdp, &bd->bd_le);
}
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
{
- struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
- GFP_NOFS | __GFP_NOFAIL);
- lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
- rv->rv_blkno = blkno;
- lops_add(sdp, &rv->rv_le);
+ BUG_ON(!list_empty(&bd->bd_le.le_list));
+ BUG_ON(!list_empty(&bd->bd_ail_st_list));
+ BUG_ON(!list_empty(&bd->bd_ail_gl_list));
+ lops_init_le(&bd->bd_le, &gfs2_revoke_lops);
+ lops_add(sdp, &bd->bd_le);
}
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
{
- struct gfs2_revoke *rv;
+ struct gfs2_bufdata *bd;
int found = 0;
gfs2_log_lock(sdp);
- list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
- if (rv->rv_blkno == blkno) {
- list_del(&rv->rv_le.le_list);
+ list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) {
+ if (bd->bd_blkno == blkno) {
+ list_del_init(&bd->bd_le.le_list);
gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
sdp->sd_log_num_revoke--;
found = 1;
@@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
if (found) {
struct gfs2_trans *tr = current->journal_info;
- kfree(rv);
+ kmem_cache_free(gfs2_bufdata_cachep, bd);
tr->tr_num_revoke_rm++;
}
}
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index 23d4cbe1de5..043d5f4b9c4 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp);
void gfs2_trans_add_gl(struct gfs2_glock *gl);
void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
diff --git a/fs/inode.c b/fs/inode.c
index 29f5068f819..f97de0aeb3b 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -142,6 +142,15 @@ static struct inode *alloc_inode(struct super_block *sb)
return NULL;
}
+ spin_lock_init(&inode->i_lock);
+ lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
+
+ mutex_init(&inode->i_mutex);
+ lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
+
+ init_rwsem(&inode->i_alloc_sem);
+ lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
+
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
@@ -190,8 +199,6 @@ void inode_init_once(struct inode *inode)
INIT_HLIST_NODE(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_dentry);
INIT_LIST_HEAD(&inode->i_devices);
- mutex_init(&inode->i_mutex);
- init_rwsem(&inode->i_alloc_sem);
INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
rwlock_init(&inode->i_data.tree_lock);
spin_lock_init(&inode->i_data.i_mmap_lock);
@@ -199,7 +206,6 @@ void inode_init_once(struct inode *inode)
spin_lock_init(&inode->i_data.private_lock);
INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
- spin_lock_init(&inode->i_lock);
i_size_ordered_init(inode);
#ifdef CONFIG_INOTIFY
INIT_LIST_HEAD(&inode->inotify_watches);
@@ -561,6 +567,18 @@ EXPORT_SYMBOL(new_inode);
void unlock_new_inode(struct inode *inode)
{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct file_system_type *type = inode->i_sb->s_type;
+ /*
+ * ensure nobody is actually holding i_mutex
+ */
+ mutex_destroy(&inode->i_mutex);
+ mutex_init(&inode->i_mutex);
+ if (inode->i_mode & S_IFDIR)
+ lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key);
+ else
+ lockdep_set_class(&inode->i_mutex, &type->i_mutex_key);
+#endif
/*
* This is special! We do not need the spinlock
* when clearing I_LOCK, because we're guaranteed
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 772b6531a2a..8df5bac0b7a 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -233,6 +233,8 @@ out:
return ret;
}
+static struct lock_class_key jbd_handle_key;
+
/* Allocate a new handle. This should probably be in a slab... */
static handle_t *new_handle(int nblocks)
{
@@ -243,6 +245,8 @@ static handle_t *new_handle(int nblocks)
handle->h_buffer_credits = nblocks;
handle->h_ref = 1;
+ lockdep_init_map(&handle->h_lockdep_map, "jbd_handle", &jbd_handle_key, 0);
+
return handle;
}
@@ -286,6 +290,9 @@ handle_t *journal_start(journal_t *journal, int nblocks)
current->journal_info = NULL;
handle = ERR_PTR(err);
}
+
+ lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_);
+
return handle;
}
@@ -1411,6 +1418,8 @@ int journal_stop(handle_t *handle)
spin_unlock(&journal->j_state_lock);
}
+ lock_release(&handle->h_lockdep_map, 1, _THIS_IP_);
+
jbd_free_handle(handle);
return err;
}
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index c32b241e3d9..60e5d49ca03 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -17,4 +17,5 @@ jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
+jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o
jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 65b3a1b5b88..8ec9323e830 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct
spin_unlock(&inode->i_lock);
}
-static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
+struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
struct posix_acl *acl;
@@ -247,8 +247,13 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
if (rc < 0)
return rc;
if (inode->i_mode != mode) {
- inode->i_mode = mode;
- jffs2_dirty_inode(inode);
+ struct iattr attr;
+
+ attr.ia_valid = ATTR_MODE;
+ attr.ia_mode = mode;
+ rc = jffs2_do_setattr(inode, &attr);
+ if (rc < 0)
+ return rc;
}
if (rc == 0)
acl = NULL;
@@ -307,22 +312,16 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
return generic_permission(inode, mask, jffs2_check_acl);
}
-int jffs2_init_acl(struct inode *inode, struct inode *dir)
+int jffs2_init_acl(struct inode *inode, struct posix_acl *acl)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct posix_acl *acl = NULL, *clone;
+ struct posix_acl *clone;
mode_t mode;
int rc = 0;
f->i_acl_access = JFFS2_ACL_NOT_CACHED;
f->i_acl_default = JFFS2_ACL_NOT_CACHED;
- if (!S_ISLNK(inode->i_mode)) {
- acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (!acl)
- inode->i_mode &= ~current->fs->umask;
- }
+
if (acl) {
if (S_ISDIR(inode->i_mode)) {
rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index c84378cee82..90a2dbf5905 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -28,9 +28,10 @@ struct jffs2_acl_header {
#define JFFS2_ACL_NOT_CACHED ((void *)-1)
+extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
extern int jffs2_permission(struct inode *, int, struct nameidata *);
extern int jffs2_acl_chmod(struct inode *);
-extern int jffs2_init_acl(struct inode *, struct inode *);
+extern int jffs2_init_acl(struct inode *, struct posix_acl *);
extern void jffs2_clear_acl(struct jffs2_inode_info *);
extern struct xattr_handler jffs2_acl_access_xattr_handler;
@@ -38,6 +39,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler;
#else
+#define jffs2_get_acl(inode, type) (NULL)
#define jffs2_permission NULL
#define jffs2_acl_chmod(inode) (0)
#define jffs2_init_acl(inode,dir) (0)
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 504643f2e98..d568ae84674 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -23,8 +23,8 @@ static int jffs2_garbage_collect_thread(void *);
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
{
spin_lock(&c->erase_completion_lock);
- if (c->gc_task && jffs2_thread_should_wake(c))
- send_sig(SIGHUP, c->gc_task, 1);
+ if (c->gc_task && jffs2_thread_should_wake(c))
+ send_sig(SIGHUP, c->gc_task, 1);
spin_unlock(&c->erase_completion_lock);
}
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 0ca2fff2617..722a6b68295 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
than actually making progress? */
c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
+ /* What number of 'very dirty' eraseblocks do we allow before we
+ trigger the GC thread even if we don't _need_ the space. When we
+ can't mark nodes obsolete on the medium, the old dirty nodes cause
+ performance problems because we have to inspect and discard them. */
+ c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger;
+ if (jffs2_can_mark_obsolete(c))
+ c->vdirty_blocks_gctrigger *= 10;
+
/* If there's less than this amount of dirty space, don't bother
trying to GC to make more space. It'll be a fruitless task */
c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
@@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
c->nospc_dirty_size);
+ dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
+ c->vdirty_blocks_gctrigger);
}
int jffs2_do_mount_fs(struct jffs2_sb_info *c)
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 485d065de41..86739ee53b3 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -5,7 +5,7 @@
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- * University of Szeged, Hungary
+ * University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -24,6 +24,34 @@ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
/* Statistics for blocks stored without compression */
static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
+
+/*
+ * Return 1 to use this compression
+ */
+static int jffs2_is_best_compression(struct jffs2_compressor *this,
+ struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
+{
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_SIZE:
+ if (bestsize > size)
+ return 1;
+ return 0;
+ case JFFS2_COMPR_MODE_FAVOURLZO:
+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
+ return 1;
+ if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
+ return 1;
+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
+ return 1;
+ if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
+ return 1;
+
+ return 0;
+ }
+ /* Shouldn't happen */
+ return 0;
+}
+
/* jffs2_compress:
* @data: Pointer to uncompressed data
* @cdata: Pointer to returned pointer to buffer for compressed data
@@ -43,121 +71,124 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co
* *datalen accordingly to show the amount of data which were compressed.
*/
uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- unsigned char *data_in, unsigned char **cpage_out,
- uint32_t *datalen, uint32_t *cdatalen)
+ unsigned char *data_in, unsigned char **cpage_out,
+ uint32_t *datalen, uint32_t *cdatalen)
{
int ret = JFFS2_COMPR_NONE;
- int compr_ret;
- struct jffs2_compressor *this, *best=NULL;
- unsigned char *output_buf = NULL, *tmp_buf;
- uint32_t orig_slen, orig_dlen;
- uint32_t best_slen=0, best_dlen=0;
+ int compr_ret;
+ struct jffs2_compressor *this, *best=NULL;
+ unsigned char *output_buf = NULL, *tmp_buf;
+ uint32_t orig_slen, orig_dlen;
+ uint32_t best_slen=0, best_dlen=0;
- switch (jffs2_compression_mode) {
- case JFFS2_COMPR_MODE_NONE:
- break;
- case JFFS2_COMPR_MODE_PRIORITY:
- output_buf = kmalloc(*cdatalen,GFP_KERNEL);
- if (!output_buf) {
- printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
- goto out;
- }
- orig_slen = *datalen;
- orig_dlen = *cdatalen;
- spin_lock(&jffs2_compressor_list_lock);
- list_for_each_entry(this, &jffs2_compressor_list, list) {
- /* Skip decompress-only backwards-compatibility and disabled modules */
- if ((!this->compress)||(this->disabled))
- continue;
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_NONE:
+ break;
+ case JFFS2_COMPR_MODE_PRIORITY:
+ output_buf = kmalloc(*cdatalen,GFP_KERNEL);
+ if (!output_buf) {
+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
+ goto out;
+ }
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
- this->usecount++;
- spin_unlock(&jffs2_compressor_list_lock);
- *datalen = orig_slen;
- *cdatalen = orig_dlen;
- compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
- spin_lock(&jffs2_compressor_list_lock);
- this->usecount--;
- if (!compr_ret) {
- ret = this->compr;
- this->stat_compr_blocks++;
- this->stat_compr_orig_size += *datalen;
- this->stat_compr_new_size += *cdatalen;
- break;
- }
- }
- spin_unlock(&jffs2_compressor_list_lock);
- if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
- break;
- case JFFS2_COMPR_MODE_SIZE:
- orig_slen = *datalen;
- orig_dlen = *cdatalen;
- spin_lock(&jffs2_compressor_list_lock);
- list_for_each_entry(this, &jffs2_compressor_list, list) {
- /* Skip decompress-only backwards-compatibility and disabled modules */
- if ((!this->compress)||(this->disabled))
- continue;
- /* Allocating memory for output buffer if necessary */
- if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
- spin_unlock(&jffs2_compressor_list_lock);
- kfree(this->compr_buf);
- spin_lock(&jffs2_compressor_list_lock);
- this->compr_buf_size=0;
- this->compr_buf=NULL;
- }
- if (!this->compr_buf) {
- spin_unlock(&jffs2_compressor_list_lock);
- tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
- spin_lock(&jffs2_compressor_list_lock);
- if (!tmp_buf) {
- printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
- continue;
- }
- else {
- this->compr_buf = tmp_buf;
- this->compr_buf_size = orig_dlen;
- }
- }
- this->usecount++;
- spin_unlock(&jffs2_compressor_list_lock);
- *datalen = orig_slen;
- *cdatalen = orig_dlen;
- compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
- spin_lock(&jffs2_compressor_list_lock);
- this->usecount--;
- if (!compr_ret) {
- if ((!best_dlen)||(best_dlen>*cdatalen)) {
- best_dlen = *cdatalen;
- best_slen = *datalen;
- best = this;
- }
- }
- }
- if (best_dlen) {
- *cdatalen = best_dlen;
- *datalen = best_slen;
- output_buf = best->compr_buf;
- best->compr_buf = NULL;
- best->compr_buf_size = 0;
- best->stat_compr_blocks++;
- best->stat_compr_orig_size += best_slen;
- best->stat_compr_new_size += best_dlen;
- ret = best->compr;
- }
- spin_unlock(&jffs2_compressor_list_lock);
- break;
- default:
- printk(KERN_ERR "JFFS2: unknow compression mode.\n");
- }
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->usecount--;
+ if (!compr_ret) {
+ ret = this->compr;
+ this->stat_compr_blocks++;
+ this->stat_compr_orig_size += *datalen;
+ this->stat_compr_new_size += *cdatalen;
+ break;
+ }
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ if (ret == JFFS2_COMPR_NONE)
+ kfree(output_buf);
+ break;
+ case JFFS2_COMPR_MODE_SIZE:
+ case JFFS2_COMPR_MODE_FAVOURLZO:
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
+ /* Allocating memory for output buffer if necessary */
+ if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ kfree(this->compr_buf);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->compr_buf_size=0;
+ this->compr_buf=NULL;
+ }
+ if (!this->compr_buf) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
+ spin_lock(&jffs2_compressor_list_lock);
+ if (!tmp_buf) {
+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
+ continue;
+ }
+ else {
+ this->compr_buf = tmp_buf;
+ this->compr_buf_size = orig_slen;
+ }
+ }
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->usecount--;
+ if (!compr_ret) {
+ if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
+ && (*cdatalen < *datalen)) {
+ best_dlen = *cdatalen;
+ best_slen = *datalen;
+ best = this;
+ }
+ }
+ }
+ if (best_dlen) {
+ *cdatalen = best_dlen;
+ *datalen = best_slen;
+ output_buf = best->compr_buf;
+ best->compr_buf = NULL;
+ best->compr_buf_size = 0;
+ best->stat_compr_blocks++;
+ best->stat_compr_orig_size += best_slen;
+ best->stat_compr_new_size += best_dlen;
+ ret = best->compr;
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ break;
+ default:
+ printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+ }
out:
- if (ret == JFFS2_COMPR_NONE) {
- *cpage_out = data_in;
- *datalen = *cdatalen;
- none_stat_compr_blocks++;
- none_stat_compr_size += *datalen;
- }
- else {
- *cpage_out = output_buf;
- }
+ if (ret == JFFS2_COMPR_NONE) {
+ *cpage_out = data_in;
+ *datalen = *cdatalen;
+ none_stat_compr_blocks++;
+ none_stat_compr_size += *datalen;
+ }
+ else {
+ *cpage_out = output_buf;
+ }
return ret;
}
@@ -165,8 +196,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint16_t comprtype, unsigned char *cdata_in,
unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
{
- struct jffs2_compressor *this;
- int ret;
+ struct jffs2_compressor *this;
+ int ret;
/* Older code had a bug where it would write non-zero 'usercompr'
fields. Deal with it. */
@@ -177,32 +208,32 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
case JFFS2_COMPR_NONE:
/* This should be special-cased elsewhere, but we might as well deal with it */
memcpy(data_out, cdata_in, datalen);
- none_stat_decompr_blocks++;
+ none_stat_decompr_blocks++;
break;
case JFFS2_COMPR_ZERO:
memset(data_out, 0, datalen);
break;
default:
- spin_lock(&jffs2_compressor_list_lock);
- list_for_each_entry(this, &jffs2_compressor_list, list) {
- if (comprtype == this->compr) {
- this->usecount++;
- spin_unlock(&jffs2_compressor_list_lock);
- ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
- spin_lock(&jffs2_compressor_list_lock);
- if (ret) {
- printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
- }
- else {
- this->stat_decompr_blocks++;
- }
- this->usecount--;
- spin_unlock(&jffs2_compressor_list_lock);
- return ret;
- }
- }
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (comprtype == this->compr) {
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ if (ret) {
+ printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
+ }
+ else {
+ this->stat_decompr_blocks++;
+ }
+ this->usecount--;
+ spin_unlock(&jffs2_compressor_list_lock);
+ return ret;
+ }
+ }
printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
- spin_unlock(&jffs2_compressor_list_lock);
+ spin_unlock(&jffs2_compressor_list_lock);
return -EIO;
}
return 0;
@@ -210,108 +241,119 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
int jffs2_register_compressor(struct jffs2_compressor *comp)
{
- struct jffs2_compressor *this;
+ struct jffs2_compressor *this;
- if (!comp->name) {
- printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
- return -1;
- }
- comp->compr_buf_size=0;
- comp->compr_buf=NULL;
- comp->usecount=0;
- comp->stat_compr_orig_size=0;
- comp->stat_compr_new_size=0;
- comp->stat_compr_blocks=0;
- comp->stat_decompr_blocks=0;
- D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+ if (!comp->name) {
+ printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+ return -1;
+ }
+ comp->compr_buf_size=0;
+ comp->compr_buf=NULL;
+ comp->usecount=0;
+ comp->stat_compr_orig_size=0;
+ comp->stat_compr_new_size=0;
+ comp->stat_compr_blocks=0;
+ comp->stat_decompr_blocks=0;
+ D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
- spin_lock(&jffs2_compressor_list_lock);
+ spin_lock(&jffs2_compressor_list_lock);
- list_for_each_entry(this, &jffs2_compressor_list, list) {
- if (this->priority < comp->priority) {
- list_add(&comp->list, this->list.prev);
- goto out;
- }
- }
- list_add_tail(&comp->list, &jffs2_compressor_list);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (this->priority < comp->priority) {
+ list_add(&comp->list, this->list.prev);
+ goto out;
+ }
+ }
+ list_add_tail(&comp->list, &jffs2_compressor_list);
out:
- D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
- printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
- })
+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+ })
- spin_unlock(&jffs2_compressor_list_lock);
+ spin_unlock(&jffs2_compressor_list_lock);
- return 0;
+ return 0;
}
int jffs2_unregister_compressor(struct jffs2_compressor *comp)
{
- D2(struct jffs2_compressor *this;)
+ D2(struct jffs2_compressor *this;)
- D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+ D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
- spin_lock(&jffs2_compressor_list_lock);
+ spin_lock(&jffs2_compressor_list_lock);
- if (comp->usecount) {
- spin_unlock(&jffs2_compressor_list_lock);
- printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
- return -1;
- }
- list_del(&comp->list);
+ if (comp->usecount) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
+ return -1;
+ }
+ list_del(&comp->list);
- D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
- printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
- })
- spin_unlock(&jffs2_compressor_list_lock);
- return 0;
+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+ })
+ spin_unlock(&jffs2_compressor_list_lock);
+ return 0;
}
void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
{
- if (orig != comprbuf)
- kfree(comprbuf);
+ if (orig != comprbuf)
+ kfree(comprbuf);
}
int __init jffs2_compressors_init(void)
{
/* Registering compressors */
#ifdef CONFIG_JFFS2_ZLIB
- jffs2_zlib_init();
+ jffs2_zlib_init();
#endif
#ifdef CONFIG_JFFS2_RTIME
- jffs2_rtime_init();
+ jffs2_rtime_init();
#endif
#ifdef CONFIG_JFFS2_RUBIN
- jffs2_rubinmips_init();
- jffs2_dynrubin_init();
+ jffs2_rubinmips_init();
+ jffs2_dynrubin_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_init();
#endif
/* Setting default compression mode */
#ifdef CONFIG_JFFS2_CMODE_NONE
- jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
- D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+ D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
#else
#ifdef CONFIG_JFFS2_CMODE_SIZE
- jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
- D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+ D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+#else
+#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
+ jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
+ D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
#else
- D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
+ D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
+#endif
#endif
#endif
- return 0;
+ return 0;
}
int jffs2_compressors_exit(void)
{
/* Unregistering compressors */
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_exit();
+#endif
#ifdef CONFIG_JFFS2_RUBIN
- jffs2_dynrubin_exit();
- jffs2_rubinmips_exit();
+ jffs2_dynrubin_exit();
+ jffs2_rubinmips_exit();
#endif
#ifdef CONFIG_JFFS2_RTIME
- jffs2_rtime_exit();
+ jffs2_rtime_exit();
#endif
#ifdef CONFIG_JFFS2_ZLIB
- jffs2_zlib_exit();
+ jffs2_zlib_exit();
#endif
- return 0;
+ return 0;
}
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
index 68cc7010dbd..7d1d72faa77 100644
--- a/fs/jffs2/compr.h
+++ b/fs/jffs2/compr.h
@@ -2,7 +2,7 @@
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- * University of Szeged, Hungary
+ * University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -27,34 +27,38 @@
#define JFFS2_RUBINMIPS_PRIORITY 10
#define JFFS2_DYNRUBIN_PRIORITY 20
#define JFFS2_LZARI_PRIORITY 30
-#define JFFS2_LZO_PRIORITY 40
#define JFFS2_RTIME_PRIORITY 50
#define JFFS2_ZLIB_PRIORITY 60
+#define JFFS2_LZO_PRIORITY 80
+
#define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
-#define JFFS2_DYNRUBIN_DISABLED /* for decompression */
+#define JFFS2_DYNRUBIN_DISABLED /* for decompression */
#define JFFS2_COMPR_MODE_NONE 0
#define JFFS2_COMPR_MODE_PRIORITY 1
#define JFFS2_COMPR_MODE_SIZE 2
+#define JFFS2_COMPR_MODE_FAVOURLZO 3
+
+#define FAVOUR_LZO_PERCENT 80
struct jffs2_compressor {
- struct list_head list;
- int priority; /* used by prirority comr. mode */
- char *name;
- char compr; /* JFFS2_COMPR_XXX */
- int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *srclen, uint32_t *destlen, void *model);
- int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
- uint32_t cdatalen, uint32_t datalen, void *model);
- int usecount;
- int disabled; /* if seted the compressor won't compress */
- unsigned char *compr_buf; /* used by size compr. mode */
- uint32_t compr_buf_size; /* used by size compr. mode */
- uint32_t stat_compr_orig_size;
- uint32_t stat_compr_new_size;
- uint32_t stat_compr_blocks;
- uint32_t stat_decompr_blocks;
+ struct list_head list;
+ int priority; /* used by prirority comr. mode */
+ char *name;
+ char compr; /* JFFS2_COMPR_XXX */
+ int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *srclen, uint32_t *destlen, void *model);
+ int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+ uint32_t cdatalen, uint32_t datalen, void *model);
+ int usecount;
+ int disabled; /* if set the compressor won't compress */
+ unsigned char *compr_buf; /* used by size compr. mode */
+ uint32_t compr_buf_size; /* used by size compr. mode */
+ uint32_t stat_compr_orig_size;
+ uint32_t stat_compr_new_size;
+ uint32_t stat_compr_blocks;
+ uint32_t stat_decompr_blocks;
};
int jffs2_register_compressor(struct jffs2_compressor *comp);
@@ -64,12 +68,12 @@ int jffs2_compressors_init(void);
int jffs2_compressors_exit(void);
uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- unsigned char *data_in, unsigned char **cpage_out,
- uint32_t *datalen, uint32_t *cdatalen);
+ unsigned char *data_in, unsigned char **cpage_out,
+ uint32_t *datalen, uint32_t *cdatalen);
int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- uint16_t comprtype, unsigned char *cdata_in,
- unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
+ uint16_t comprtype, unsigned char *cdata_in,
+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
@@ -90,5 +94,9 @@ void jffs2_rtime_exit(void);
int jffs2_zlib_init(void);
void jffs2_zlib_exit(void);
#endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
#endif /* __JFFS2_COMPR_H__ */
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c
new file mode 100644
index 00000000000..47b045797e4
--- /dev/null
+++ b/fs/jffs2/compr_lzo.c
@@ -0,0 +1,108 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright © 2007 Nokia Corporation. All rights reserved.
+ *
+ * Created by Richard Purdie <rpurdie@openedhand.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/lzo.h>
+#include "compr.h"
+
+static void *lzo_mem;
+static void *lzo_compress_buf;
+static DEFINE_MUTEX(deflate_mutex);
+
+static void free_workspace(void)
+{
+ vfree(lzo_mem);
+ vfree(lzo_compress_buf);
+}
+
+static int __init alloc_workspace(void)
+{
+ lzo_mem = vmalloc(LZO1X_MEM_COMPRESS);
+ lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE));
+
+ if (!lzo_mem || !lzo_compress_buf) {
+ printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n");
+ free_workspace();
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+ size_t compress_size;
+ int ret;
+
+ mutex_lock(&deflate_mutex);
+ ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
+ mutex_unlock(&deflate_mutex);
+
+ if (ret != LZO_E_OK)
+ return -1;
+
+ if (compress_size > *dstlen)
+ return -1;
+
+ memcpy(cpage_out, lzo_compress_buf, compress_size);
+ *dstlen = compress_size;
+
+ return 0;
+}
+
+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ size_t dl = destlen;
+ int ret;
+
+ ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl);
+
+ if (ret != LZO_E_OK || dl != destlen)
+ return -1;
+
+ return 0;
+}
+
+static struct jffs2_compressor jffs2_lzo_comp = {
+ .priority = JFFS2_LZO_PRIORITY,
+ .name = "lzo",
+ .compr = JFFS2_COMPR_LZO,
+ .compress = &jffs2_lzo_compress,
+ .decompress = &jffs2_lzo_decompress,
+ .disabled = 0,
+};
+
+int __init jffs2_lzo_init(void)
+{
+ int ret;
+
+ ret = alloc_workspace();
+ if (ret < 0)
+ return ret;
+
+ ret = jffs2_register_compressor(&jffs2_lzo_comp);
+ if (ret)
+ free_workspace();
+
+ return ret;
+}
+
+void jffs2_lzo_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_lzo_comp);
+ free_workspace();
+}
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
index 0d0bfd2e4e0..546d1538d07 100644
--- a/fs/jffs2/compr_rtime.c
+++ b/fs/jffs2/compr_rtime.c
@@ -104,7 +104,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
}
}
}
- return 0;
+ return 0;
}
static struct jffs2_compressor jffs2_rtime_comp = {
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c
index ea0431e047d..c73fa89b5f8 100644
--- a/fs/jffs2/compr_rubin.c
+++ b/fs/jffs2/compr_rubin.c
@@ -384,7 +384,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in,
void *model)
{
rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
- return 0;
+ return 0;
}
static int jffs2_dynrubin_decompress(unsigned char *data_in,
@@ -399,7 +399,7 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in,
bits[c] = data_in[c];
rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
- return 0;
+ return 0;
}
static struct jffs2_compressor jffs2_rubinmips_comp = {
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 2b87fccc155..cfd301a5edf 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -181,7 +181,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in,
}
zlib_inflateEnd(&inf_strm);
mutex_unlock(&inflate_mutex);
- return 0;
+ return 0;
}
static struct jffs2_compressor jffs2_zlib_comp = {
@@ -203,11 +203,11 @@ int __init jffs2_zlib_init(void)
ret = alloc_workspaces();
if (ret)
- return ret;
+ return ret;
ret = jffs2_register_compressor(&jffs2_zlib_comp);
if (ret)
- free_workspaces();
+ free_workspaces();
return ret;
}
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c1dfca310dd..8353eb9c179 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -32,7 +32,7 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int);
static int jffs2_rmdir (struct inode *,struct dentry *);
static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
static int jffs2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
+ struct inode *, struct dentry *);
const struct file_operations jffs2_dir_operations =
{
@@ -182,6 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
struct inode *inode;
+ struct posix_acl *acl;
int ret;
ri = jffs2_alloc_raw_inode();
@@ -192,7 +193,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
D1(printk(KERN_DEBUG "jffs2_create()\n"));
- inode = jffs2_new_inode(dir_i, mode, ri);
+ inode = jffs2_new_inode(dir_i, mode, ri, &acl);
if (IS_ERR(inode)) {
D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
@@ -212,12 +213,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
dentry->d_name.name, dentry->d_name.len);
if (ret)
- goto fail;
+ goto fail_acl;
ret = jffs2_init_security(inode, dir_i);
if (ret)
- goto fail;
- ret = jffs2_init_acl(inode, dir_i);
+ goto fail_acl;
+ ret = jffs2_init_acl(inode, acl);
if (ret)
goto fail;
@@ -230,6 +231,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
return 0;
+ fail_acl:
+ posix_acl_release(acl);
fail:
make_bad_inode(inode);
iput(inode);
@@ -306,6 +309,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
struct jffs2_full_dirent *fd;
int namelen;
uint32_t alloclen;
+ struct posix_acl *acl;
int ret, targetlen = strlen(target);
/* FIXME: If you care. We'd need to use frags for the target
@@ -332,7 +336,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
return ret;
}
- inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
+ inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl);
if (IS_ERR(inode)) {
jffs2_free_raw_inode(ri);
@@ -362,6 +366,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
up(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return PTR_ERR(fn);
}
@@ -372,6 +377,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
up(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return -ENOMEM;
}
@@ -389,9 +395,10 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
ret = jffs2_init_security(inode, dir_i);
if (ret) {
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return ret;
}
- ret = jffs2_init_acl(inode, dir_i);
+ ret = jffs2_init_acl(inode, acl);
if (ret) {
jffs2_clear_inode(inode);
return ret;
@@ -469,6 +476,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
struct jffs2_full_dirent *fd;
int namelen;
uint32_t alloclen;
+ struct posix_acl *acl;
int ret;
mode |= S_IFDIR;
@@ -491,7 +499,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
return ret;
}
- inode = jffs2_new_inode(dir_i, mode, ri);
+ inode = jffs2_new_inode(dir_i, mode, ri, &acl);
if (IS_ERR(inode)) {
jffs2_free_raw_inode(ri);
@@ -518,6 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
up(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return PTR_ERR(fn);
}
/* No data here. Only a metadata node, which will be
@@ -531,9 +540,10 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
ret = jffs2_init_security(inode, dir_i);
if (ret) {
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return ret;
}
- ret = jffs2_init_acl(inode, dir_i);
+ ret = jffs2_init_acl(inode, acl);
if (ret) {
jffs2_clear_inode(inode);
return ret;
@@ -629,6 +639,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
union jffs2_device_node dev;
int devlen = 0;
uint32_t alloclen;
+ struct posix_acl *acl;
int ret;
if (!new_valid_dev(rdev))
@@ -655,7 +666,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
return ret;
}
- inode = jffs2_new_inode(dir_i, mode, ri);
+ inode = jffs2_new_inode(dir_i, mode, ri, &acl);
if (IS_ERR(inode)) {
jffs2_free_raw_inode(ri);
@@ -684,6 +695,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
up(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return PTR_ERR(fn);
}
/* No data here. Only a metadata node, which will be
@@ -697,9 +709,10 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
ret = jffs2_init_security(inode, dir_i);
if (ret) {
jffs2_clear_inode(inode);
+ posix_acl_release(acl);
return ret;
}
- ret = jffs2_init_acl(inode, dir_i);
+ ret = jffs2_init_acl(inode, acl);
if (ret) {
jffs2_clear_inode(inode);
return ret;
@@ -770,7 +783,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
}
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
- struct inode *new_dir_i, struct dentry *new_dentry)
+ struct inode *new_dir_i, struct dentry *new_dentry)
{
int ret;
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 66e7c2f1e64..a1db9180633 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -38,8 +38,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
#ifdef __ECOS
ret = jffs2_flash_erase(c, jeb);
if (!ret) {
- jffs2_erase_succeeded(c, jeb);
- return;
+ jffs2_erase_succeeded(c, jeb);
+ return;
}
bad_offset = jeb->offset;
#else /* Linux */
@@ -50,12 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
if (!instr) {
printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
return;
}
@@ -82,12 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
if (ret == -ENOMEM || ret == -EAGAIN) {
/* Erase failed immediately. Refile it on the list */
D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
return;
}
@@ -114,6 +118,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
list_del(&jeb->list);
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
jffs2_mark_erased_block(c, jeb);
if (!--count) {
@@ -134,6 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
jffs2_free_jeb_node_refs(c, jeb);
list_add(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
jffs2_erase_block(c, jeb);
@@ -142,23 +148,25 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
}
/* Be nice */
- cond_resched();
+ yield();
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
}
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
done:
D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
-
- up(&c->erase_free_sem);
}
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move_tail(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
/* Ensure that kupdated calls us again to mark them clean */
jffs2_erase_pending_trigger(c);
}
@@ -172,22 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
failed too many times. */
if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
/* We'd like to give this block another try. */
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
return;
}
}
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
c->erasing_size -= c->sector_size;
c->bad_size += c->sector_size;
list_move(&jeb->list, &c->bad_list);
c->nr_erasing_blocks--;
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
wake_up(&c->erase_wait);
}
@@ -317,6 +329,33 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
size_t retlen;
int ret = -EIO;
+ if (c->mtd->point) {
+ unsigned long *wordebuf;
+
+ ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf);
+ if (ret) {
+ D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
+ goto do_flash_read;
+ }
+ if (retlen < c->sector_size) {
+ /* Don't muck about if it won't let us point to the whole erase sector */
+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
+ c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen);
+ goto do_flash_read;
+ }
+ wordebuf = ebuf-sizeof(*wordebuf);
+ retlen /= sizeof(*wordebuf);
+ do {
+ if (*++wordebuf != ~0)
+ break;
+ } while(--retlen);
+ c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
+ if (retlen)
+ printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
+ *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
+ return 0;
+ }
+ do_flash_read:
ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!ebuf) {
printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
@@ -362,7 +401,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
{
size_t retlen;
int ret;
- uint32_t bad_offset;
+ uint32_t uninitialized_var(bad_offset);
switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
case -EAGAIN: goto refile;
@@ -417,6 +456,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
}
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
c->erasing_size -= c->sector_size;
c->free_size += jeb->free_size;
@@ -429,23 +469,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
c->nr_erasing_blocks--;
c->nr_free_blocks++;
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
wake_up(&c->erase_wait);
return;
filebad:
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
/* Stick it on a list (any list) so erase_failed can take it
right off again. Silly, but shouldn't happen often. */
list_add(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
jffs2_erase_failed(c, jeb, bad_offset);
return;
refile:
/* Stick it back on the list from whence it came and come back later */
jffs2_erase_pending_trigger(c);
+ down(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_add(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock);
+ up(&c->erase_free_sem);
return;
}
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 8bc727b7169..ed85f9afdbc 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -24,7 +24,7 @@
static int jffs2_flash_setup(struct jffs2_sb_info *c);
-static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
+int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
{
struct jffs2_full_dnode *old_metadata, *new_metadata;
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -36,10 +36,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
unsigned int ivalid;
uint32_t alloclen;
int ret;
+
D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
- ret = inode_change_ok(inode, iattr);
- if (ret)
- return ret;
/* Special cases - we don't want more than one data node
for these types on the medium at any time. So setattr
@@ -183,9 +181,14 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
{
int rc;
+ rc = inode_change_ok(dentry->d_inode, iattr);
+ if (rc)
+ return rc;
+
rc = jffs2_do_setattr(dentry->d_inode, iattr);
if (!rc && (iattr->ia_valid & ATTR_MODE))
rc = jffs2_acl_chmod(dentry->d_inode);
+
return rc;
}
@@ -399,7 +402,8 @@ void jffs2_write_super (struct super_block *sb)
/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri,
+ struct posix_acl **acl)
{
struct inode *inode;
struct super_block *sb = dir_i->i_sb;
@@ -431,7 +435,23 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
} else {
ri->gid = cpu_to_je16(current->fsgid);
}
- ri->mode = cpu_to_jemode(mode);
+
+ /* POSIX ACLs have to be processed now, at least partly.
+ The umask is only applied if there's no default ACL */
+ if (!S_ISLNK(mode)) {
+ *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
+ if (IS_ERR(*acl)) {
+ make_bad_inode(inode);
+ iput(inode);
+ inode = (void *)*acl;
+ *acl = NULL;
+ return inode;
+ }
+ if (!(*acl))
+ mode &= ~current->fs->umask;
+ } else {
+ *acl = NULL;
+ }
ret = jffs2_do_new_inode (c, f, mode, ri);
if (ret) {
make_bad_inode(inode);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 2d99e06ab22..32ff0373aa0 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
struct jffs2_inode_cache *ic;
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw;
+ uint32_t gcblock_dirty;
int ret = 0, inum, nlink;
int xattr = 0;
@@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
}
raw = jeb->gc_node;
+ gcblock_dirty = jeb->dirty_size;
while(ref_obsolete(raw)) {
D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
@@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
} else {
ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
}
- goto release_sem;
+ goto test_gcnode;
}
#endif
@@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
if (ret != -EBADFD) {
spin_unlock(&c->inocache_lock);
- goto release_sem;
+ goto test_gcnode;
}
/* Fall through if it wanted us to, with inocache_lock held */
@@ -407,6 +409,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jffs2_gc_release_inode(c, f);
+ test_gcnode:
+ if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) {
+ /* Eep. This really should never happen. GC is broken */
+ printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node));
+ ret = -ENOSPC;
+ }
release_sem:
up(&c->alloc_sem);
@@ -556,7 +564,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
node = kmalloc(rawlen, GFP_KERNEL);
if (!node)
- return -ENOMEM;
+ return -ENOMEM;
ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
if (!ret && retlen != rawlen)
@@ -598,10 +606,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
goto bail;
}
+ if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) {
+ printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw));
+ goto bail;
+ }
+
if (node->d.nsize) {
crc = crc32(0, node->d.name, node->d.nsize);
if (je32_to_cpu(node->d.name_crc) != crc) {
- printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+ printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
goto bail;
}
@@ -624,7 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
if (ret || (retlen != rawlen)) {
printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
- rawlen, phys_ofs, ret, retlen);
+ rawlen, phys_ofs, ret, retlen);
if (retlen) {
jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL);
} else {
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index b13298a824e..3a2197f3c81 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -69,6 +69,8 @@ struct jffs2_sb_info {
uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */
uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */
uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */
+ /* Number of 'very dirty' blocks before we trigger immediate GC */
+ uint8_t vdirty_blocks_gctrigger;
uint32_t nospc_dirty_size;
@@ -106,6 +108,9 @@ struct jffs2_sb_info {
uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ unsigned char *wbuf_verify; /* read-back buffer for verification */
+#endif
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
unsigned char *wbuf; /* Write-behind buffer for NAND flash */
uint32_t wbuf_ofs;
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index bc5509fe577..ec1aae9e695 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -127,7 +127,7 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod
return ((struct jffs2_inode_cache *)raw);
}
- /* flash_offset & 3 always has to be zero, because nodes are
+ /* flash_offset & 3 always has to be zero, because nodes are
always aligned at 4 bytes. So we have a couple of extra bits
to play with, which indicate the node's status; see below: */
#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index dbc908ad622..a0313fa8748 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -154,7 +154,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize,
while(ret == -EAGAIN) {
ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
if (ret) {
- D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
+ D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
}
}
spin_unlock(&c->erase_completion_lock);
@@ -423,7 +423,12 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c,
even after refiling c->nextblock */
if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE))
&& (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) {
- printk(KERN_WARNING "argh. node added in wrong place\n");
+ printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3);
+ if (c->nextblock)
+ printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset);
+ else
+ printk(KERN_WARNING "No nextblock");
+ printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size));
return ERR_PTR(-EINVAL);
}
#endif
@@ -717,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
{
int ret = 0;
uint32_t dirty;
+ int nr_very_dirty = 0;
+ struct jffs2_eraseblock *jeb;
if (c->unchecked_size) {
D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
@@ -738,8 +745,18 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
(dirty > c->nospc_dirty_size))
ret = 1;
- D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
- c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+ list_for_each_entry(jeb, &c->very_dirty_list, list) {
+ nr_very_dirty++;
+ if (nr_very_dirty == c->vdirty_blocks_gctrigger) {
+ ret = 1;
+ /* In debug mode, actually go through and count them all */
+ D1(continue);
+ break;
+ }
+ }
+
+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n",
+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no"));
return ret;
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 80daea96bbc..f6743a915cf 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -173,12 +173,15 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
extern const struct inode_operations jffs2_symlink_inode_operations;
/* fs.c */
+struct posix_acl;
+
int jffs2_setattr (struct dentry *, struct iattr *);
+int jffs2_do_setattr (struct inode *, struct iattr *);
void jffs2_read_inode (struct inode *);
void jffs2_clear_inode (struct inode *);
void jffs2_dirty_inode(struct inode *inode);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
- struct jffs2_raw_inode *ri);
+ struct jffs2_raw_inode *ri, struct posix_acl **acl);
int jffs2_statfs (struct dentry *, struct kstatfs *);
void jffs2_write_super (struct super_block *);
int jffs2_remount_fs (struct super_block *, int *, char *);
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index b5baa356fed..2eae5d2dbeb 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -65,7 +65,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
if (!err && retlen < tn->csize) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
- c->mtd->unpoint(c->mtd, buffer, ofs, len);
+ c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
} else if (err)
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
else
@@ -211,7 +211,7 @@ static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *
* ordering.
*
* Returns 0 if the node was handled (including marking it obsolete)
- * < 0 an if error occurred
+ * < 0 an if error occurred
*/
static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
struct jffs2_readinode_info *rii,
@@ -862,8 +862,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re
JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n",
ref_offset(ref));
JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n",
- je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
- je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
+ je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
+ je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
jffs2_mark_node_obsolete(c, ref);
return 0;
}
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 6c75cd43334..272872d27fd 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -101,7 +101,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
- c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+ c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen);
flashbuf = NULL;
}
if (ret)
@@ -863,7 +863,7 @@ scan_more:
switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
case JFFS2_FEATURE_ROCOMPAT:
printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
- c->flags |= JFFS2_SB_FLAG_RO;
+ c->flags |= JFFS2_SB_FLAG_RO;
if (!(jffs2_is_readonly(c)))
return -EROFS;
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
@@ -1004,6 +1004,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
{
struct jffs2_full_dirent *fd;
struct jffs2_inode_cache *ic;
+ uint32_t checkedlen;
uint32_t crc;
int err;
@@ -1024,12 +1025,18 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
pseudo_random += je32_to_cpu(rd->version);
- fd = jffs2_alloc_full_dirent(rd->nsize+1);
+ /* Should never happen. Did. (OLPC trac #4184)*/
+ checkedlen = strnlen(rd->name, rd->nsize);
+ if (checkedlen < rd->nsize) {
+ printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+ ofs, checkedlen);
+ }
+ fd = jffs2_alloc_full_dirent(checkedlen+1);
if (!fd) {
return -ENOMEM;
}
- memcpy(&fd->name, rd->name, rd->nsize);
- fd->name[rd->nsize] = 0;
+ memcpy(&fd->name, rd->name, checkedlen);
+ fd->name[checkedlen] = 0;
crc = crc32(0, fd->name, rd->nsize);
if (crc != je32_to_cpu(rd->name_crc)) {
@@ -1055,7 +1062,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
fd->next = NULL;
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
- fd->nhash = full_name_hash(fd->name, rd->nsize);
+ fd->nhash = full_name_hash(fd->name, checkedlen);
fd->type = rd->type;
jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index bc9f6ba1082..02c39c64ecb 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -38,9 +38,9 @@ int jffs2_init_security(struct inode *inode, struct inode *dir)
}
rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
- kfree(name);
- kfree(value);
- return rc;
+ kfree(name);
+ kfree(value);
+ return rc;
}
/* ---- XATTR Handler for "security.*" ----------------- */
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index d828b296392..629af01e5ad 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -2,10 +2,10 @@
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- * Zoltan Sogor <weth@inf.u-szeged.hu>,
- * Patrik Kluba <pajko@halom.u-szeged.hu>,
- * University of Szeged, Hungary
- * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * Patrik Kluba <pajko@halom.u-szeged.hu>,
+ * University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -429,6 +429,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
case JFFS2_NODETYPE_DIRENT: {
struct jffs2_sum_dirent_flash *spd;
+ int checkedlen;
spd = sp;
dbg_summary("Dirent at 0x%08x-0x%08x\n",
@@ -436,12 +437,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
- fd = jffs2_alloc_full_dirent(spd->nsize+1);
+ /* This should never happen, but https://dev.laptop.org/ticket/4184 */
+ checkedlen = strnlen(spd->name, spd->nsize);
+ if (!checkedlen) {
+ printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n",
+ jeb->offset + je32_to_cpu(spd->offset));
+ return -EIO;
+ }
+ if (checkedlen < spd->nsize) {
+ printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+ jeb->offset + je32_to_cpu(spd->offset), checkedlen);
+ }
+
+
+ fd = jffs2_alloc_full_dirent(checkedlen+1);
if (!fd)
return -ENOMEM;
- memcpy(&fd->name, spd->name, spd->nsize);
- fd->name[spd->nsize] = 0;
+ memcpy(&fd->name, spd->name, checkedlen);
+ fd->name[checkedlen] = 0;
ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
if (!ic) {
@@ -455,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
fd->next = NULL;
fd->version = je32_to_cpu(spd->version);
fd->ino = je32_to_cpu(spd->ino);
- fd->nhash = full_name_hash(fd->name, spd->nsize);
+ fd->nhash = full_name_hash(fd->name, checkedlen);
fd->type = spd->type;
jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
index 0c6669e2139..8bf34f2fa5c 100644
--- a/fs/jffs2/summary.h
+++ b/fs/jffs2/summary.h
@@ -2,9 +2,9 @@
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- * Zoltan Sogor <weth@inf.u-szeged.hu>,
- * Patrik Kluba <pajko@halom.u-szeged.hu>,
- * University of Szeged, Hungary
+ * Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * Patrik Kluba <pajko@halom.u-szeged.hu>,
+ * University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 91d1d0f1c66..d1d4f27464b 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
return NULL;
}
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
+ uint32_t ofs)
+{
+ int ret;
+ size_t retlen;
+ char *eccstr;
+
+ ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
+ if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
+ printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
+ return ret;
+ } else if (retlen != c->wbuf_pagesize) {
+ printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
+ return -EIO;
+ }
+ if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
+ return 0;
+
+ if (ret == -EUCLEAN)
+ eccstr = "corrected";
+ else if (ret == -EBADMSG)
+ eccstr = "correction failed";
+ else
+ eccstr = "OK or unused";
+
+ printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
+ eccstr, c->wbuf_ofs);
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ c->wbuf, c->wbuf_pagesize, 0);
+
+ printk(KERN_WARNING "Read back:\n");
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ c->wbuf_verify, c->wbuf_pagesize, 0);
+
+ return -EIO;
+}
+#else
+#define jffs2_verify_write(c,b,o) (0)
+#endif
+
/* Recover from failure to write wbuf. Recover the nodes up to the
* wbuf, not the one which we were starting to try to write. */
@@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
rewrite_buf);
- if (ret || retlen != towrite) {
+ if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
/* Argh. We tried. Really we did. */
printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
kfree(buf);
@@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
- if (ret || retlen != c->wbuf_pagesize) {
- if (ret)
- printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
- else {
- printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
- retlen, c->wbuf_pagesize);
- ret = -EIO;
- }
-
+ if (ret) {
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
+ goto wfail;
+ } else if (retlen != c->wbuf_pagesize) {
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+ retlen, c->wbuf_pagesize);
+ ret = -EIO;
+ goto wfail;
+ } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
+ wfail:
jffs2_wbuf_recover(c);
return ret;
@@ -966,8 +1008,8 @@ exit:
#define NR_OOB_SCAN_PAGES 4
-/* For historical reasons we use only 12 bytes for OOB clean marker */
-#define OOB_CM_SIZE 12
+/* For historical reasons we use only 8 bytes for OOB clean marker */
+#define OOB_CM_SIZE 8
static const struct jffs2_unknown_node oob_cleanmarker =
{
@@ -1021,8 +1063,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
/*
* Check for a valid cleanmarker.
* Returns: 0 if a valid cleanmarker was found
- * 1 if no cleanmarker was found
- * negative error code if an error occurred
+ * 1 if no cleanmarker was found
+ * negative error code if an error occurred
*/
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb)
@@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
return -ENOMEM;
}
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf_verify) {
+ kfree(c->oobbuf);
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+#endif
return 0;
}
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
{
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ kfree(c->wbuf_verify);
+#endif
kfree(c->wbuf);
kfree(c->oobbuf);
}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 664c164aa67..2f5695446d0 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -215,6 +215,17 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
BUG();
});
+ if (strnlen(name, namelen) != namelen) {
+ /* This should never happen, but seems to have done on at least one
+ occasion: https://dev.laptop.org/ticket/4184 */
+ printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n");
+ printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
+ je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
+ je32_to_cpu(rd->name_crc));
+ WARN_ON(1);
+ return ERR_PTR(-EIO);
+ }
+
vecs[0].iov_base = rd;
vecs[0].iov_len = sizeof(*rd);
vecs[1].iov_base = (unsigned char *)name;
@@ -226,7 +237,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
- fd->nhash = full_name_hash(name, strlen(name));
+ fd->nhash = full_name_hash(name, namelen);
fd->type = rd->type;
memcpy(fd->name, name, namelen);
fd->name[namelen]=0;
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 3b0ff292593..6e3b5ddfb7a 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -75,7 +75,7 @@ extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c);
extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
- uint32_t xid, uint32_t version);
+ uint32_t xid, uint32_t version);
extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c
index 40942bc516b..8bbeab90ada 100644
--- a/fs/jffs2/xattr_user.c
+++ b/fs/jffs2/xattr_user.c
@@ -17,7 +17,7 @@
#include "nodelist.h"
static int jffs2_user_getxattr(struct inode *inode, const char *name,
- void *buffer, size_t size)
+ void *buffer, size_t size)
{
if (!strcmp(name, ""))
return -EINVAL;
@@ -25,7 +25,7 @@ static int jffs2_user_getxattr(struct inode *inode, const char *name,
}
static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
- size_t size, int flags)
+ size_t size, int flags)
{
if (!strcmp(name, ""))
return -EINVAL;
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index c14ba3cfa81..df0b8535de8 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -520,7 +520,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
* Changes an entry in the directory index table
*/
static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
- int slot, struct metapage ** mp, u64 *lblock)
+ int slot, struct metapage ** mp, s64 *lblock)
{
struct dir_table_slot *dirtab_slot;
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index cb8f30985ad..439901d205f 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -49,7 +49,7 @@ struct jfs_inode_info {
short btorder; /* access order */
short btindex; /* btpage entry index*/
struct inode *ipimap; /* inode map */
- long cflag; /* commit flags */
+ unsigned long cflag; /* commit flags */
u16 bxflag; /* xflag of pseudo buffer? */
unchar agno; /* ag number */
signed char active_ag; /* ag currently allocating from */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index ccfd0294405..15a3974cdee 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -2234,6 +2234,8 @@ static void lbmIODone(struct bio *bio, int error)
/* wakeup I/O initiator */
LCACHE_WAKEUP(&bp->l_ioevent);
+
+ return;
}
/*
@@ -2258,6 +2260,7 @@ static void lbmIODone(struct bio *bio, int error)
if (bp->l_flag & lbmDIRECT) {
LCACHE_WAKEUP(&bp->l_ioevent);
LCACHE_UNLOCK(flags);
+ return;
}
tail = log->wqueue;
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
index 1f85ef0ec04..9236bc49ae7 100644
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -376,7 +376,7 @@ struct jfs_log {
int size; /* 4: log size in log page (in page) */
int l2bsize; /* 4: log2 of bsize */
- long flag; /* 4: flag */
+ unsigned long flag; /* 4: flag */
struct lbuf *lbuf_free; /* 4: free lbufs */
wait_queue_head_t free_wait; /* 4: */
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 1332adc0b9f..941369c1ac8 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -291,8 +291,6 @@ static void metapage_read_end_io(struct bio *bio, int err)
dec_io(page, last_read_complete);
bio_put(bio);
-
- return 0;
}
static void remove_from_logsync(struct metapage *mp)
@@ -349,7 +347,6 @@ static void metapage_write_end_io(struct bio *bio, int err)
}
dec_io(page, last_write_complete);
bio_put(bio);
- return 0;
}
static int metapage_writepage(struct page *page, struct writeback_control *wbc)
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 3353ed8421a..908b23fadd0 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -10,6 +10,7 @@
#include <linux/utsname.h>
#include <linux/kernel.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsock.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
@@ -132,7 +133,7 @@ nsm_create(void)
.sin_port = 0,
};
struct rpc_create_args args = {
- .protocol = IPPROTO_UDP,
+ .protocol = XPRT_TRANSPORT_UDP,
.address = (struct sockaddr *)&sin,
.addrsize = sizeof(sin),
.servername = "localhost",
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 5316e307a49..633653bff94 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -62,8 +62,9 @@ static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
}
else
{
- printk(KERN_NOTICE
- "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
+ dprintk("lockd: bad cookie size %d (only cookies under "
+ "%d bytes are supported.)\n",
+ len, NLM_MAXCOOKIELEN);
return NULL;
}
return p;
@@ -84,8 +85,7 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f)
unsigned int len;
if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
- printk(KERN_NOTICE
- "lockd: bad fhandle size %d (should be %d)\n",
+ dprintk("lockd: bad fhandle size %d (should be %d)\n",
len, NFS2_FHSIZE);
return NULL;
}
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 846fc1d639d..43ff9397e6c 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -64,8 +64,9 @@ nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
}
else
{
- printk(KERN_NOTICE
- "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
+ dprintk("lockd: bad cookie size %d (only cookies under "
+ "%d bytes are supported.)\n",
+ len, NLM_MAXCOOKIELEN);
return NULL;
}
return p;
@@ -86,8 +87,7 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
memset(f->data, 0, sizeof(f->data));
f->size = ntohl(*p++);
if (f->size > NFS_MAXFHSIZE) {
- printk(KERN_NOTICE
- "lockd: bad fhandle size %d (should be <=%d)\n",
+ dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
f->size, NFS_MAXFHSIZE);
return NULL;
}
diff --git a/fs/locks.c b/fs/locks.c
index c795eaaf6c4..7f9a3ea4741 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker,
static void locks_wake_up_blocks(struct file_lock *blocker)
{
while (!list_empty(&blocker->fl_block)) {
- struct file_lock *waiter = list_entry(blocker->fl_block.next,
+ struct file_lock *waiter;
+
+ waiter = list_first_entry(&blocker->fl_block,
struct file_lock, fl_block);
__locks_delete_block(waiter);
if (waiter->fl_lmops && waiter->fl_lmops->fl_notify)
@@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
continue;
- if (posix_locks_conflict(cfl, fl))
+ if (posix_locks_conflict(fl, cfl))
break;
}
if (cfl)
@@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock);
static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
- struct list_head *tmp;
+ struct file_lock *fl;
next_task:
if (posix_same_owner(caller_fl, block_fl))
return 1;
- list_for_each(tmp, &blocked_list) {
- struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+ list_for_each_entry(fl, &blocked_list, fl_link) {
if (posix_same_owner(fl, block_fl)) {
fl = fl->fl_next;
block_fl = fl;
@@ -715,8 +716,7 @@ next_task:
}
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
- * at the head of the list, but that's secret knowledge known only to
- * flock_lock_file and posix_lock_file.
+ * after any leases, but before any posix locks.
*
* Note that if called with an FL_EXISTS argument, the caller may determine
* whether or not a lock was successfully freed by testing the return
@@ -733,6 +733,15 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
lock_kernel();
if (request->fl_flags & FL_ACCESS)
goto find_conflict;
+
+ if (request->fl_type != F_UNLCK) {
+ error = -ENOMEM;
+ new_fl = locks_alloc_lock();
+ if (new_fl == NULL)
+ goto out;
+ error = 0;
+ }
+
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
@@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
goto out;
}
- error = -ENOMEM;
- new_fl = locks_alloc_lock();
- if (new_fl == NULL)
- goto out;
/*
* If a higher-priority process was blocked on the old file lock,
* give it the opportunity to lock the file.
@@ -819,7 +824,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
lock_kernel();
if (request->fl_type != F_UNLCK) {
for_each_lock(inode, before) {
- struct file_lock *fl = *before;
+ fl = *before;
if (!IS_POSIX(fl))
continue;
if (!posix_locks_conflict(request, fl))
@@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
* If we've been sleeping someone might have
* changed the permissions behind our back.
*/
- if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ if (__mandatory_lock(inode))
continue;
}
@@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
+ struct file_lock *new_fl = NULL;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
@@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
|| (atomic_read(&inode->i_count) > 1)))
goto out;
+ error = -ENOMEM;
+ new_fl = locks_alloc_lock();
+ if (new_fl == NULL)
+ goto out;
+
/*
* At this point, we know that if there is an exclusive
* lease on this file, then we hold it on this filp
@@ -1405,18 +1416,15 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if (!leases_enable)
goto out;
- error = -ENOMEM;
- fl = locks_alloc_lock();
- if (fl == NULL)
- goto out;
-
- locks_copy_lock(fl, lease);
+ locks_copy_lock(new_fl, lease);
+ locks_insert_lock(before, new_fl);
- locks_insert_lock(before, fl);
+ *flp = new_fl;
+ return 0;
- *flp = fl;
- error = 0;
out:
+ if (new_fl != NULL)
+ locks_free_lock(new_fl);
return error;
}
EXPORT_SYMBOL(generic_setlease);
@@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
*/
- if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- mapping_writably_mapped(filp->f_mapping)) {
+ if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
error = -EAGAIN;
goto out;
}
@@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
*/
- if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- mapping_writably_mapped(filp->f_mapping)) {
+ if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
error = -EAGAIN;
goto out;
}
@@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
EXPORT_SYMBOL_GPL(vfs_cancel_lock);
-static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
+#ifdef CONFIG_PROC_FS
+#include <linux/seq_file.h>
+
+static void lock_get_status(struct seq_file *f, struct file_lock *fl,
+ int id, char *pfx)
{
struct inode *inode = NULL;
if (fl->fl_file != NULL)
inode = fl->fl_file->f_path.dentry->d_inode;
- out += sprintf(out, "%d:%s ", id, pfx);
+ seq_printf(f, "%d:%s ", id, pfx);
if (IS_POSIX(fl)) {
- out += sprintf(out, "%6s %s ",
+ seq_printf(f, "%6s %s ",
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
(inode == NULL) ? "*NOINODE*" :
- (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
- "MANDATORY" : "ADVISORY ");
+ mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
} else if (IS_FLOCK(fl)) {
if (fl->fl_type & LOCK_MAND) {
- out += sprintf(out, "FLOCK MSNFS ");
+ seq_printf(f, "FLOCK MSNFS ");
} else {
- out += sprintf(out, "FLOCK ADVISORY ");
+ seq_printf(f, "FLOCK ADVISORY ");
}
} else if (IS_LEASE(fl)) {
- out += sprintf(out, "LEASE ");
+ seq_printf(f, "LEASE ");
if (fl->fl_type & F_INPROGRESS)
- out += sprintf(out, "BREAKING ");
+ seq_printf(f, "BREAKING ");
else if (fl->fl_file)
- out += sprintf(out, "ACTIVE ");
+ seq_printf(f, "ACTIVE ");
else
- out += sprintf(out, "BREAKER ");
+ seq_printf(f, "BREAKER ");
} else {
- out += sprintf(out, "UNKNOWN UNKNOWN ");
+ seq_printf(f, "UNKNOWN UNKNOWN ");
}
if (fl->fl_type & LOCK_MAND) {
- out += sprintf(out, "%s ",
+ seq_printf(f, "%s ",
(fl->fl_type & LOCK_READ)
? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
} else {
- out += sprintf(out, "%s ",
+ seq_printf(f, "%s ",
(fl->fl_type & F_INPROGRESS)
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
}
if (inode) {
#ifdef WE_CAN_BREAK_LSLK_NOW
- out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
+ seq_printf(f, "%d %s:%ld ", fl->fl_pid,
inode->i_sb->s_id, inode->i_ino);
#else
/* userspace relies on this representation of dev_t ;-( */
- out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid,
+ seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid,
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino);
#endif
} else {
- out += sprintf(out, "%d <none>:0 ", fl->fl_pid);
+ seq_printf(f, "%d <none>:0 ", fl->fl_pid);
}
if (IS_POSIX(fl)) {
if (fl->fl_end == OFFSET_MAX)
- out += sprintf(out, "%Ld EOF\n", fl->fl_start);
+ seq_printf(f, "%Ld EOF\n", fl->fl_start);
else
- out += sprintf(out, "%Ld %Ld\n", fl->fl_start,
- fl->fl_end);
+ seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
} else {
- out += sprintf(out, "0 EOF\n");
+ seq_printf(f, "0 EOF\n");
}
}
-static void move_lock_status(char **p, off_t* pos, off_t offset)
+static int locks_show(struct seq_file *f, void *v)
{
- int len;
- len = strlen(*p);
- if(*pos >= offset) {
- /* the complete line is valid */
- *p += len;
- *pos += len;
- return;
- }
- if(*pos+len > offset) {
- /* use the second part of the line */
- int i = offset-*pos;
- memmove(*p,*p+i,len-i);
- *p += len-i;
- *pos += len;
- return;
- }
- /* discard the complete line */
- *pos += len;
+ struct file_lock *fl, *bfl;
+
+ fl = list_entry(v, struct file_lock, fl_link);
+
+ lock_get_status(f, fl, (long)f->private, "");
+
+ list_for_each_entry(bfl, &fl->fl_block, fl_block)
+ lock_get_status(f, bfl, (long)f->private, " ->");
+
+ f->private++;
+ return 0;
}
-/**
- * get_locks_status - reports lock usage in /proc/locks
- * @buffer: address in userspace to write into
- * @start: ?
- * @offset: how far we are through the buffer
- * @length: how much to read
- */
+static void *locks_start(struct seq_file *f, loff_t *pos)
+{
+ lock_kernel();
+ f->private = (void *)1;
+ return seq_list_start(&file_lock_list, *pos);
+}
-int get_locks_status(char *buffer, char **start, off_t offset, int length)
+static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
{
- struct list_head *tmp;
- char *q = buffer;
- off_t pos = 0;
- int i = 0;
+ return seq_list_next(v, &file_lock_list, pos);
+}
- lock_kernel();
- list_for_each(tmp, &file_lock_list) {
- struct list_head *btmp;
- struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
- lock_get_status(q, fl, ++i, "");
- move_lock_status(&q, &pos, offset);
-
- if(pos >= offset+length)
- goto done;
-
- list_for_each(btmp, &fl->fl_block) {
- struct file_lock *bfl = list_entry(btmp,
- struct file_lock, fl_block);
- lock_get_status(q, bfl, i, " ->");
- move_lock_status(&q, &pos, offset);
-
- if(pos >= offset+length)
- goto done;
- }
- }
-done:
+static void locks_stop(struct seq_file *f, void *v)
+{
unlock_kernel();
- *start = buffer;
- if(q-buffer < length)
- return (q-buffer);
- return length;
}
+struct seq_operations locks_seq_operations = {
+ .start = locks_start,
+ .next = locks_next,
+ .stop = locks_stop,
+ .show = locks_show,
+};
+#endif
+
/**
* lock_may_read - checks that the region is free of locks
* @inode: the inode that is being read
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index b55cb236cf7..df0f41e0988 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -16,4 +16,3 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
nfs4namespace.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
-nfs-objs := $(nfs-y)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index a204484072f..a532ee12740 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -23,6 +23,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
+#include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtrdma.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
@@ -340,7 +342,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_retries = 2;
switch (proto) {
- case IPPROTO_TCP:
+ case XPRT_TRANSPORT_TCP:
+ case XPRT_TRANSPORT_RDMA:
if (!to->to_initval)
to->to_initval = 60 * HZ;
if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
@@ -349,7 +352,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
to->to_exponential = 0;
break;
- case IPPROTO_UDP:
+ case XPRT_TRANSPORT_UDP:
default:
if (!to->to_initval)
to->to_initval = 11 * HZ / 10;
@@ -501,9 +504,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t
/*
* Initialise an NFS2 or NFS3 client
*/
-static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data)
+static int nfs_init_client(struct nfs_client *clp,
+ const struct nfs_parsed_mount_data *data)
{
- int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
int error;
if (clp->cl_cons_state == NFS_CS_READY) {
@@ -522,8 +525,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *
* Create a client RPC handle for doing FSSTAT with UNIX auth only
* - RFC 2623, sec 2.3.2
*/
- error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
- RPC_AUTH_UNIX, 0);
+ error = nfs_create_rpc_client(clp, data->nfs_server.protocol,
+ data->timeo, data->retrans, RPC_AUTH_UNIX, 0);
if (error < 0)
goto error;
nfs_mark_client_ready(clp, NFS_CS_READY);
@@ -538,7 +541,8 @@ error:
/*
* Create a version 2 or 3 client
*/
-static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data)
+static int nfs_init_server(struct nfs_server *server,
+ const struct nfs_parsed_mount_data *data)
{
struct nfs_client *clp;
int error, nfsvers = 2;
@@ -551,7 +555,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
#endif
/* Allocate or find a client reference we can use */
- clp = nfs_get_client(data->hostname, &data->addr, nfsvers);
+ clp = nfs_get_client(data->nfs_server.hostname,
+ &data->nfs_server.address, nfsvers);
if (IS_ERR(clp)) {
dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
return PTR_ERR(clp);
@@ -581,7 +586,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
if (error < 0)
goto error;
- error = nfs_init_server_rpcclient(server, data->pseudoflavor);
+ error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
if (error < 0)
goto error;
@@ -760,7 +765,7 @@ void nfs_free_server(struct nfs_server *server)
* Create a version 2 or 3 volume record
* - keyed on server and FSID
*/
-struct nfs_server *nfs_create_server(const struct nfs_mount_data *data,
+struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
struct nfs_fh *mntfh)
{
struct nfs_server *server;
@@ -906,7 +911,7 @@ error:
* Create a version 4 volume record
*/
static int nfs4_init_server(struct nfs_server *server,
- const struct nfs4_mount_data *data, rpc_authflavor_t authflavour)
+ const struct nfs_parsed_mount_data *data)
{
int error;
@@ -926,7 +931,7 @@ static int nfs4_init_server(struct nfs_server *server,
server->acdirmin = data->acdirmin * HZ;
server->acdirmax = data->acdirmax * HZ;
- error = nfs_init_server_rpcclient(server, authflavour);
+ error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
/* Done */
dprintk("<-- nfs4_init_server() = %d\n", error);
@@ -937,12 +942,7 @@ static int nfs4_init_server(struct nfs_server *server,
* Create a version 4 volume record
* - keyed on server and FSID
*/
-struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
- const char *hostname,
- const struct sockaddr_in *addr,
- const char *mntpath,
- const char *ip_addr,
- rpc_authflavor_t authflavour,
+struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
struct nfs_fh *mntfh)
{
struct nfs_fattr fattr;
@@ -956,13 +956,18 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
return ERR_PTR(-ENOMEM);
/* Get a client record */
- error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour,
- data->proto, data->timeo, data->retrans);
+ error = nfs4_set_client(server,
+ data->nfs_server.hostname,
+ &data->nfs_server.address,
+ data->client_address,
+ data->auth_flavors[0],
+ data->nfs_server.protocol,
+ data->timeo, data->retrans);
if (error < 0)
goto error;
/* set up the general RPC client */
- error = nfs4_init_server(server, data, authflavour);
+ error = nfs4_init_server(server, data);
if (error < 0)
goto error;
@@ -971,7 +976,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
/* Probe the root fh to retrieve its FSID */
- error = nfs4_path_walk(server, mntfh, mntpath);
+ error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path);
if (error < 0)
goto error;
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index c55a761c22b..af8b235d405 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -52,7 +52,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue;
- if ((struct nfs_open_context *)fl->fl_file->private_data != ctx)
+ if (nfs_file_open_context(fl->fl_file) != ctx)
continue;
status = nfs4_lock_delegation_recall(state, fl);
if (status >= 0)
@@ -109,6 +109,7 @@ again:
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
struct nfs_delegation *delegation = NFS_I(inode)->delegation;
+ struct rpc_cred *oldcred;
if (delegation == NULL)
return;
@@ -116,11 +117,12 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
sizeof(delegation->stateid.data));
delegation->type = res->delegation_type;
delegation->maxsize = res->maxsize;
- put_rpccred(cred);
+ oldcred = delegation->cred;
delegation->cred = get_rpccred(cred);
delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
NFS_I(inode)->delegation_state = delegation->type;
smp_wmb();
+ put_rpccred(oldcred);
}
/*
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e4a04d16b8b..8ec7fbd8240 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -200,9 +200,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
desc->timestamp = timestamp;
desc->timestamp_valid = 1;
SetPageUptodate(page);
- spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
- spin_unlock(&inode->i_lock);
/* Ensure consistent page alignment of the data.
* Note: assumes we have exclusive access to this mapping either
* through inode->i_mutex or some other mechanism.
@@ -214,9 +211,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
unlock_page(page);
return 0;
error:
- SetPageError(page);
unlock_page(page);
- nfs_zap_caches(inode);
desc->error = error;
return -EIO;
}
@@ -407,7 +402,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
struct file *file = desc->file;
struct nfs_entry *entry = desc->entry;
struct dentry *dentry = NULL;
- unsigned long fileid;
+ u64 fileid;
int loop_count = 0,
res;
@@ -418,7 +413,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
unsigned d_type = DT_UNKNOWN;
/* Note: entry->prev_cookie contains the cookie for
* retrieving the current dirent on the server */
- fileid = nfs_fileid_to_ino_t(entry->ino);
+ fileid = entry->ino;
/* Get a dentry if we have one */
if (dentry != NULL)
@@ -428,11 +423,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
/* Use readdirplus info */
if (dentry != NULL && dentry->d_inode != NULL) {
d_type = dt_type(dentry->d_inode);
- fileid = dentry->d_inode->i_ino;
+ fileid = NFS_FILEID(dentry->d_inode);
}
res = filldir(dirent, entry->name, entry->len,
- file->f_pos, fileid, d_type);
+ file->f_pos, nfs_compat_user_ino64(fileid),
+ d_type);
if (res < 0)
break;
file->f_pos++;
@@ -490,9 +486,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
page,
NFS_SERVER(inode)->dtsize,
desc->plus);
- spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
- spin_unlock(&inode->i_lock);
desc->page = page;
desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
if (desc->error >= 0) {
@@ -558,7 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
memset(desc, 0, sizeof(*desc));
desc->file = filp;
- desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie;
+ desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = NFS_USE_READDIRPLUS(inode);
@@ -623,7 +616,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
}
if (offset != filp->f_pos) {
filp->f_pos = offset;
- ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
+ nfs_file_open_context(filp)->dir_cookie = 0;
}
out:
mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
@@ -650,36 +643,18 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
*/
static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
{
- unsigned long verf;
-
if (IS_ROOT(dentry))
return 1;
- verf = dentry->d_time;
- if (nfs_caches_unstable(dir)
- || verf != NFS_I(dir)->cache_change_attribute)
+ if (!nfs_verify_change_attribute(dir, dentry->d_time))
+ return 0;
+ /* Revalidate nfsi->cache_change_attribute before we declare a match */
+ if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+ return 0;
+ if (!nfs_verify_change_attribute(dir, dentry->d_time))
return 0;
return 1;
}
-static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
-{
- dentry->d_time = verf;
-}
-
-static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
-{
- nfs_set_verifier(dentry, verf);
-}
-
-/*
- * Whenever an NFS operation succeeds, we know that the dentry
- * is valid, so we update the revalidation timestamp.
- */
-static inline void nfs_renew_times(struct dentry * dentry)
-{
- dentry->d_time = jiffies;
-}
-
/*
* Return the intent data that applies to this particular path component
*
@@ -695,6 +670,19 @@ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigne
}
/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
+static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+{
+ if (NFS_PROTO(dir)->version == 2)
+ return 0;
+ if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
+ return 0;
+ return (nd->intent.open.flags & O_EXCL) != 0;
+}
+
+/*
* Inode and filehandle revalidation for lookups.
*
* We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
@@ -717,6 +705,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
(S_ISREG(inode->i_mode) ||
S_ISDIR(inode->i_mode)))
goto out_force;
+ return 0;
}
return nfs_revalidate_inode(server, inode);
out_force:
@@ -759,7 +748,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- unsigned long verifier;
parent = dget_parent(dentry);
lock_kernel();
@@ -767,10 +755,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = dentry->d_inode;
- /* Revalidate parent directory attribute cache */
- if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
- goto out_zap_parent;
-
if (!inode) {
if (nfs_neg_need_reval(dir, dentry, nd))
goto out_bad;
@@ -785,7 +769,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
}
/* Force a full look up iff the parent directory has changed */
- if (nfs_check_verifier(dir, dentry)) {
+ if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode, nd))
goto out_zap_parent;
goto out_valid;
@@ -794,7 +778,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if (NFS_STALE(inode))
goto out_bad;
- verifier = nfs_save_change_attribute(dir);
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -803,8 +786,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
goto out_bad;
- nfs_renew_times(dentry);
- nfs_refresh_verifier(dentry, verifier);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
unlock_kernel();
dput(parent);
@@ -815,7 +797,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
out_zap_parent:
nfs_zap_caches(dir);
out_bad:
- NFS_CACHEINV(dir);
+ nfs_mark_for_revalidate(dir);
if (inode && S_ISDIR(inode->i_mode)) {
/* Purge readdir caches. */
nfs_zap_caches(inode);
@@ -872,8 +854,6 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
nfs_complete_unlink(dentry, inode);
unlock_kernel();
}
- /* When creating a negative dentry, we want to renew d_time */
- nfs_renew_times(dentry);
iput(inode);
}
@@ -883,30 +863,6 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
-/*
- * Use intent information to check whether or not we're going to do
- * an O_EXCL create using this path component.
- */
-static inline
-int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
-{
- if (NFS_PROTO(dir)->version == 2)
- return 0;
- if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
- return 0;
- return (nd->intent.open.flags & O_EXCL) != 0;
-}
-
-static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
-{
- struct nfs_server *server = NFS_SERVER(dir);
-
- if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
- /* Revalidate fsid using the parent directory */
- return __nfs_revalidate_inode(server, dir);
- return 0;
-}
-
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *res;
@@ -945,11 +901,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error);
goto out_unlock;
}
- error = nfs_reval_fsid(dir, &fattr);
- if (error < 0) {
- res = ERR_PTR(error);
- goto out_unlock;
- }
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
res = (struct dentry *)inode;
if (IS_ERR(res))
@@ -958,17 +909,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
no_entry:
res = d_materialise_unique(dentry, inode);
if (res != NULL) {
- struct dentry *parent;
if (IS_ERR(res))
goto out_unlock;
- /* Was a directory renamed! */
- parent = dget_parent(res);
- if (!IS_ROOT(parent))
- nfs_mark_for_revalidate(parent->d_inode);
- dput(parent);
dentry = res;
}
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unlock:
unlock_kernel();
@@ -1020,28 +964,16 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
}
dentry->d_op = NFS_PROTO(dir)->dentry_ops;
- /* Let vfs_create() deal with O_EXCL */
+ /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
+ * the dentry. */
if (nd->intent.open.flags & O_EXCL) {
- d_add(dentry, NULL);
+ d_instantiate(dentry, NULL);
goto out;
}
/* Open the file on the server */
lock_kernel();
- /* Revalidate parent directory attribute cache */
- error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
- if (error < 0) {
- res = ERR_PTR(error);
- unlock_kernel();
- goto out;
- }
-
- if (nd->intent.open.flags & O_CREAT) {
- nfs_begin_data_update(dir);
- res = nfs4_atomic_open(dir, dentry, nd);
- nfs_end_data_update(dir);
- } else
- res = nfs4_atomic_open(dir, dentry, nd);
+ res = nfs4_atomic_open(dir, dentry, nd);
unlock_kernel();
if (IS_ERR(res)) {
error = PTR_ERR(res);
@@ -1063,8 +995,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
}
} else if (res != NULL)
dentry = res;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out:
return res;
no_open:
@@ -1076,7 +1006,6 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct dentry *parent = NULL;
struct inode *inode = dentry->d_inode;
struct inode *dir;
- unsigned long verifier;
int openflags, ret = 0;
parent = dget_parent(dentry);
@@ -1086,8 +1015,12 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
- if (inode == NULL)
+ if (inode == NULL) {
+ if (!nfs_neg_need_reval(dir, dentry, nd))
+ ret = 1;
goto out;
+ }
+
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
goto no_open;
@@ -1104,10 +1037,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
* change attribute *before* we do the RPC call.
*/
lock_kernel();
- verifier = nfs_save_change_attribute(dir);
ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
- if (!ret)
- nfs_refresh_verifier(dentry, verifier);
unlock_kernel();
out:
dput(parent);
@@ -1133,6 +1063,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
.len = entry->len,
};
struct inode *inode;
+ unsigned long verf = nfs_save_change_attribute(dir);
switch (name.len) {
case 2:
@@ -1143,6 +1074,14 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
if (name.name[0] == '.')
return dget(parent);
}
+
+ spin_lock(&dir->i_lock);
+ if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {
+ spin_unlock(&dir->i_lock);
+ return NULL;
+ }
+ spin_unlock(&dir->i_lock);
+
name.hash = full_name_hash(name.name, name.len);
dentry = d_lookup(parent, &name);
if (dentry != NULL) {
@@ -1183,12 +1122,8 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
dentry = alias;
}
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- return dentry;
out_renew:
- nfs_renew_times(dentry);
- nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir));
+ nfs_set_verifier(dentry, verf);
return dentry;
}
@@ -1198,32 +1133,40 @@ out_renew:
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
+ struct dentry *parent = dget_parent(dentry);
+ struct inode *dir = parent->d_inode;
struct inode *inode;
int error = -EACCES;
+ d_drop(dentry);
+
/* We may have been initialized further down */
if (dentry->d_inode)
- return 0;
+ goto out;
if (fhandle->size == 0) {
- struct inode *dir = dentry->d_parent->d_inode;
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error)
- return error;
+ goto out_error;
}
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (!(fattr->valid & NFS_ATTR_FATTR)) {
struct nfs_server *server = NFS_SB(dentry->d_sb);
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
if (error < 0)
- return error;
+ goto out_error;
}
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
error = PTR_ERR(inode);
if (IS_ERR(inode))
- return error;
- d_instantiate(dentry, inode);
- if (d_unhashed(dentry))
- d_rehash(dentry);
+ goto out_error;
+ d_add(dentry, inode);
+out:
+ dput(parent);
return 0;
+out_error:
+ nfs_mark_for_revalidate(dir);
+ dput(parent);
+ return error;
}
/*
@@ -1249,13 +1192,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
open_flags = nd->intent.open.flags;
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
- nfs_end_data_update(dir);
if (error != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1283,13 +1222,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
attr.ia_valid = ATTR_MODE;
lock_kernel();
- nfs_begin_data_update(dir);
status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
- nfs_end_data_update(dir);
if (status != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1313,13 +1248,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
attr.ia_mode = mode | S_IFDIR;
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
- nfs_end_data_update(dir);
if (error != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1336,12 +1267,10 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL)
clear_nlink(dentry->d_inode);
- nfs_end_data_update(dir);
unlock_kernel();
return error;
@@ -1350,9 +1279,9 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter;
- const int i_inosize = sizeof(dir->i_ino)*2;
+ const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
const int countersize = sizeof(sillycounter)*2;
- const int slen = sizeof(".nfs") + i_inosize + countersize - 1;
+ const int slen = sizeof(".nfs")+fileidsize+countersize-1;
char silly[slen+1];
struct qstr qsilly;
struct dentry *sdentry;
@@ -1370,8 +1299,9 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto out;
- sprintf(silly, ".nfs%*.*lx",
- i_inosize, i_inosize, dentry->d_inode->i_ino);
+ sprintf(silly, ".nfs%*.*Lx",
+ fileidsize, fileidsize,
+ (unsigned long long)NFS_FILEID(dentry->d_inode));
/* Return delegation in anticipation of the rename */
nfs_inode_return_delegation(dentry->d_inode);
@@ -1398,19 +1328,14 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
qsilly.name = silly;
qsilly.len = strlen(silly);
- nfs_begin_data_update(dir);
if (dentry->d_inode) {
- nfs_begin_data_update(dentry->d_inode);
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
nfs_mark_for_revalidate(dentry->d_inode);
- nfs_end_data_update(dentry->d_inode);
} else
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
- nfs_end_data_update(dir);
if (!error) {
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry);
error = nfs_async_unlink(dir, dentry);
@@ -1443,19 +1368,15 @@ static int nfs_safe_remove(struct dentry *dentry)
goto out;
}
- nfs_begin_data_update(dir);
if (inode != NULL) {
nfs_inode_return_delegation(inode);
- nfs_begin_data_update(inode);
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
/* The VFS may want to delete this inode */
if (error == 0)
drop_nlink(inode);
nfs_mark_for_revalidate(inode);
- nfs_end_data_update(inode);
} else
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
- nfs_end_data_update(dir);
out:
return error;
}
@@ -1493,7 +1414,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dcache_lock);
error = nfs_safe_remove(dentry);
if (!error) {
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
} else if (need_rehash)
d_rehash(dentry);
@@ -1548,9 +1468,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
kunmap_atomic(kaddr, KM_USER0);
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
- nfs_end_data_update(dir);
if (error != 0) {
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
dir->i_sb->s_id, dir->i_ino,
@@ -1590,15 +1508,12 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
dentry->d_parent->d_name.name, dentry->d_name.name);
lock_kernel();
- nfs_begin_data_update(dir);
- nfs_begin_data_update(inode);
+ d_drop(dentry);
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
if (error == 0) {
atomic_inc(&inode->i_count);
- d_instantiate(dentry, inode);
+ d_add(dentry, inode);
}
- nfs_end_data_update(inode);
- nfs_end_data_update(dir);
unlock_kernel();
return error;
}
@@ -1701,22 +1616,16 @@ go_ahead:
d_delete(new_dentry);
}
- nfs_begin_data_update(old_dir);
- nfs_begin_data_update(new_dir);
- nfs_begin_data_update(old_inode);
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
new_dir, &new_dentry->d_name);
nfs_mark_for_revalidate(old_inode);
- nfs_end_data_update(old_inode);
- nfs_end_data_update(new_dir);
- nfs_end_data_update(old_dir);
out:
if (rehash)
d_rehash(rehash);
if (!error) {
d_move(old_dentry, new_dentry);
- nfs_renew_times(new_dentry);
- nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+ nfs_set_verifier(new_dentry,
+ nfs_save_change_attribute(new_dir));
}
/* new dentry created? */
@@ -1842,7 +1751,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
return NULL;
}
-int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_access_entry *cache;
@@ -1854,7 +1763,7 @@ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs
cache = nfs_access_search_rbtree(inode, cred);
if (cache == NULL)
goto out;
- if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
+ if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
goto out_stale;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
@@ -1909,7 +1818,7 @@ found:
nfs_access_free_entry(entry);
}
-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
{
struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
if (cache == NULL)
@@ -1957,6 +1866,24 @@ out:
return -EACCES;
}
+static int nfs_open_permission_mask(int openflags)
+{
+ int mask = 0;
+
+ if (openflags & FMODE_READ)
+ mask |= MAY_READ;
+ if (openflags & FMODE_WRITE)
+ mask |= MAY_WRITE;
+ if (openflags & FMODE_EXEC)
+ mask |= MAY_EXEC;
+ return mask;
+}
+
+int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
+{
+ return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
+}
+
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct rpc_cred *cred;
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index fcf4d384610..32fe97211ee 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -368,7 +368,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
return -ENOMEM;
dreq->inode = inode;
- dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
+ dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
@@ -510,7 +510,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
nfs_direct_write_reschedule(dreq);
break;
default:
- nfs_end_data_update(inode);
if (dreq->commit_data != NULL)
nfs_commit_free(dreq->commit_data);
nfs_direct_free_writedata(dreq);
@@ -533,7 +532,6 @@ static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq)
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
{
- nfs_end_data_update(inode);
nfs_direct_free_writedata(dreq);
nfs_zap_mapping(inode, inode->i_mapping);
nfs_direct_complete(dreq);
@@ -718,14 +716,12 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
sync = FLUSH_STABLE;
dreq->inode = inode;
- dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
+ dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);
- nfs_begin_data_update(inode);
-
rpc_clnt_sigmask(clnt, &oldset);
result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
if (!result)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 579cf8a7d4a..08c7c7387fc 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -33,6 +33,7 @@
#include <asm/system.h>
#include "delegation.h"
+#include "internal.h"
#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_FILE
@@ -55,6 +56,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);
+static struct vm_operations_struct nfs_file_vm_ops;
+
const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read = do_sync_read,
@@ -174,13 +177,38 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
}
/*
+ * Helper for nfs_file_flush() and nfs_fsync()
+ *
+ * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
+ * disk, but it retrieves and clears ctx->error after synching, despite
+ * the two being set at the same time in nfs_context_set_write_error().
+ * This is because the former is used to notify the _next_ call to
+ * nfs_file_write() that a write error occured, and hence cause it to
+ * fall back to doing a synchronous write.
+ */
+static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
+{
+ int have_error, status;
+ int ret = 0;
+
+ have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+ status = nfs_wb_all(inode);
+ have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+ if (have_error)
+ ret = xchg(&ctx->error, 0);
+ if (!ret)
+ ret = status;
+ return ret;
+}
+
+/*
* Flush all dirty pages, and check for write errors.
*
*/
static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = file->f_path.dentry->d_inode;
int status;
@@ -189,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id)
if ((file->f_mode & FMODE_WRITE) == 0)
return 0;
nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
- lock_kernel();
+
/* Ensure that data+attribute caches are up to date after close() */
- status = nfs_wb_all(inode);
- if (!status) {
- status = ctx->error;
- ctx->error = 0;
- if (!status)
- nfs_revalidate_inode(NFS_SERVER(inode), inode);
- }
- unlock_kernel();
+ status = nfs_do_fsync(ctx, inode);
+ if (!status)
+ nfs_revalidate_inode(NFS_SERVER(inode), inode);
return status;
}
@@ -257,8 +280,11 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
dentry->d_parent->d_name.name, dentry->d_name.name);
status = nfs_revalidate_mapping(inode, file->f_mapping);
- if (!status)
- status = generic_file_mmap(file, vma);
+ if (!status) {
+ vma->vm_ops = &nfs_file_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
+ file_accessed(file);
+ }
return status;
}
@@ -270,21 +296,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
static int
nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode;
- int status;
dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
- lock_kernel();
- status = nfs_wb_all(inode);
- if (!status) {
- status = ctx->error;
- ctx->error = 0;
- }
- unlock_kernel();
- return status;
+ return nfs_do_fsync(ctx, inode);
}
/*
@@ -333,7 +351,7 @@ static int nfs_launder_page(struct page *page)
const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
- .set_page_dirty = nfs_set_page_dirty,
+ .set_page_dirty = __set_page_dirty_nobuffers,
.writepage = nfs_writepage,
.writepages = nfs_writepages,
.prepare_write = nfs_prepare_write,
@@ -346,6 +364,43 @@ const struct address_space_operations nfs_file_aops = {
.launder_page = nfs_launder_page,
};
+static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ struct file *filp = vma->vm_file;
+ unsigned pagelen;
+ int ret = -EINVAL;
+
+ lock_page(page);
+ if (page->mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping)
+ goto out_unlock;
+ pagelen = nfs_page_length(page);
+ if (pagelen == 0)
+ goto out_unlock;
+ ret = nfs_prepare_write(filp, page, 0, pagelen);
+ if (!ret)
+ ret = nfs_commit_write(filp, page, 0, pagelen);
+out_unlock:
+ unlock_page(page);
+ return ret;
+}
+
+static struct vm_operations_struct nfs_file_vm_ops = {
+ .fault = filemap_fault,
+ .page_mkwrite = nfs_vm_page_mkwrite,
+};
+
+static int nfs_need_sync_write(struct file *filp, struct inode *inode)
+{
+ struct nfs_open_context *ctx;
+
+ if (IS_SYNC(inode) || (filp->f_flags & O_SYNC))
+ return 1;
+ ctx = nfs_file_open_context(filp);
+ if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
+ return 1;
+ return 0;
+}
+
static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
@@ -382,8 +437,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
result = generic_file_aio_write(iocb, iov, nr_segs, pos);
/* Return error values for O_SYNC and IS_SYNC() */
- if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) {
- int err = nfs_fsync(iocb->ki_filp, dentry, 1);
+ if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
+ int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
if (err < 0)
result = err;
}
@@ -522,8 +577,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
nfs_inc_stats(inode, NFSIOS_VFSLOCK);
/* No mandatory locks over NFS */
- if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- fl->fl_type != F_UNLCK)
+ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
return -ENOLCK;
if (IS_GETLK(cmd))
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 71a49c3acab..035c769b715 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -49,6 +49,11 @@
#define NFSDBG_FACILITY NFSDBG_VFS
+#define NFS_64_BIT_INODE_NUMBERS_ENABLED 1
+
+/* Default is to see 64-bit inode numbers */
+static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
+
static void nfs_invalidate_inode(struct inode *);
static int nfs_update_inode(struct inode *, struct nfs_fattr *);
@@ -62,6 +67,25 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
return nfs_fileid_to_ino_t(fattr->fileid);
}
+/**
+ * nfs_compat_user_ino64 - returns the user-visible inode number
+ * @fileid: 64-bit fileid
+ *
+ * This function returns a 32-bit inode number if the boot parameter
+ * nfs.enable_ino64 is zero.
+ */
+u64 nfs_compat_user_ino64(u64 fileid)
+{
+ int ino;
+
+ if (enable_ino64)
+ return fileid;
+ ino = fileid;
+ if (sizeof(ino) < sizeof(fileid))
+ ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
+ return ino;
+}
+
int nfs_write_inode(struct inode *inode, int sync)
{
int ret;
@@ -85,7 +109,6 @@ void nfs_clear_inode(struct inode *inode)
*/
BUG_ON(nfs_have_writebacks(inode));
BUG_ON(!list_empty(&NFS_I(inode)->open_files));
- BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
nfs_zap_acl_cache(inode);
nfs_access_zap_cache(inode);
}
@@ -118,8 +141,8 @@ static void nfs_zap_caches_locked(struct inode *inode)
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
- NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+ nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+ nfsi->attrtimeo_timestamp = jiffies;
memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
@@ -156,6 +179,13 @@ static void nfs_zap_acl_cache(struct inode *inode)
spin_unlock(&inode->i_lock);
}
+void nfs_invalidate_atime(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
+ spin_unlock(&inode->i_lock);
+}
+
/*
* Invalidate, but do not unhash, the inode.
* NB: must be called with inode->i_lock held!
@@ -338,7 +368,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
return 0;
lock_kernel();
- nfs_begin_data_update(inode);
/* Write all dirty data */
if (S_ISREG(inode->i_mode)) {
filemap_write_and_wait(inode->i_mapping);
@@ -352,7 +381,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error == 0)
nfs_refresh_inode(inode, &fattr);
- nfs_end_data_update(inode);
unlock_kernel();
return error;
}
@@ -431,7 +459,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
/* Flush out writes to the server in order to update c/mtime */
if (S_ISREG(inode->i_mode))
- nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT);
+ nfs_wb_nocommit(inode);
/*
* We may force a getattr if the user cares about atime.
@@ -450,8 +478,10 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
else
err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
- if (!err)
+ if (!err) {
generic_fillattr(inode, stat);
+ stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
+ }
return err;
}
@@ -536,7 +566,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
static void nfs_file_clear_open_context(struct file *filp)
{
struct inode *inode = filp->f_path.dentry->d_inode;
- struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(filp);
if (ctx) {
filp->private_data = NULL;
@@ -598,16 +628,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
status = nfs_wait_on_inode(inode);
if (status < 0)
goto out;
- if (NFS_STALE(inode)) {
- status = -ESTALE;
- /* Do we trust the cached ESTALE? */
- if (NFS_ATTRTIMEO(inode) != 0) {
- if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME)) {
- /* no */
- } else
- goto out;
- }
- }
+
+ status = -ESTALE;
+ if (NFS_STALE(inode))
+ goto out;
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
if (status != 0) {
@@ -654,7 +678,7 @@ int nfs_attribute_timeout(struct inode *inode)
if (nfs_have_delegation(inode, FMODE_READ))
return 0;
- return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
+ return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}
/**
@@ -683,11 +707,8 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa
}
spin_lock(&inode->i_lock);
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
- if (S_ISDIR(inode->i_mode)) {
+ if (S_ISDIR(inode->i_mode))
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
- /* This ensures we revalidate child dentries */
- nfsi->cache_change_attribute = jiffies;
- }
spin_unlock(&inode->i_lock);
nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
@@ -756,56 +777,27 @@ out:
return ret;
}
-/**
- * nfs_begin_data_update
- * @inode - pointer to inode
- * Declare that a set of operations will update file data on the server
- */
-void nfs_begin_data_update(struct inode *inode)
-{
- atomic_inc(&NFS_I(inode)->data_updates);
-}
-
-/**
- * nfs_end_data_update
- * @inode - pointer to inode
- * Declare end of the operations that will update file data
- * This will mark the inode as immediately needing revalidation
- * of its attribute cache.
- */
-void nfs_end_data_update(struct inode *inode)
-{
- struct nfs_inode *nfsi = NFS_I(inode);
-
- /* Directories: invalidate page cache */
- if (S_ISDIR(inode->i_mode)) {
- spin_lock(&inode->i_lock);
- nfsi->cache_validity |= NFS_INO_INVALID_DATA;
- spin_unlock(&inode->i_lock);
- }
- nfsi->cache_change_attribute = jiffies;
- atomic_dec(&nfsi->data_updates);
-}
-
static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
struct nfs_inode *nfsi = NFS_I(inode);
- unsigned long now = jiffies;
+ if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
+ nfsi->change_attr == fattr->pre_change_attr) {
+ nfsi->change_attr = fattr->change_attr;
+ if (S_ISDIR(inode->i_mode))
+ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+ }
/* If we have atomic WCC data, we may update some attributes */
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
- if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
+ if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
- nfsi->cache_change_attribute = now;
- }
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
- nfsi->cache_change_attribute = now;
+ if (S_ISDIR(inode->i_mode))
+ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
}
- if (inode->i_size == fattr->pre_size && nfsi->npages == 0) {
+ if (inode->i_size == fattr->pre_size && nfsi->npages == 0)
inode->i_size = fattr->size;
- nfsi->cache_change_attribute = now;
- }
}
}
@@ -822,7 +814,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
{
struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_size, new_isize;
- int data_unstable;
+ unsigned long invalid = 0;
/* Has the inode gone and changed behind our back? */
@@ -831,37 +823,41 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
return -EIO;
}
- /* Are we in the process of updating data on the server? */
- data_unstable = nfs_caches_unstable(inode);
-
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
nfsi->change_attr != fattr->change_attr)
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
/* Verify a few of the more important attributes */
if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size);
if (cur_size != new_isize && nfsi->npages == 0)
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
/* Have any file permissions changed? */
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|| inode->i_uid != fattr->uid
|| inode->i_gid != fattr->gid)
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+ invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
/* Has the link count changed? */
if (inode->i_nlink != fattr->nlink)
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
+ invalid |= NFS_INO_INVALID_ATTR;
if (!timespec_equal(&inode->i_atime, &fattr->atime))
- nfsi->cache_validity |= NFS_INO_INVALID_ATIME;
+ invalid |= NFS_INO_INVALID_ATIME;
+
+ if (invalid != 0)
+ nfsi->cache_validity |= invalid;
+ else
+ nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
+ | NFS_INO_INVALID_ATIME
+ | NFS_INO_REVAL_PAGECACHE);
nfsi->read_cache_jiffies = fattr->time_start;
return 0;
@@ -911,17 +907,41 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
struct nfs_inode *nfsi = NFS_I(inode);
- int status = 0;
spin_lock(&inode->i_lock);
- if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) {
- nfsi->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
- goto out;
- }
- status = nfs_update_inode(inode, fattr);
-out:
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+ if (S_ISDIR(inode->i_mode))
+ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock);
- return status;
+ return nfs_refresh_inode(inode, fattr);
+}
+
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+ (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
+ fattr->pre_change_attr = NFS_I(inode)->change_attr;
+ fattr->valid |= NFS_ATTR_WCC_V4;
+ }
+ if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
+ (fattr->valid & NFS_ATTR_WCC) == 0) {
+ memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+ memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+ fattr->pre_size = inode->i_size;
+ fattr->valid |= NFS_ATTR_WCC;
+ }
+ return nfs_post_op_update_inode(inode, fattr);
}
/*
@@ -941,9 +961,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
struct nfs_server *server;
struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_isize, new_isize;
- unsigned int invalid = 0;
+ unsigned long invalid = 0;
unsigned long now = jiffies;
- int data_stable;
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
@@ -968,57 +987,51 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
* Update the read time so we don't revalidate too often.
*/
nfsi->read_cache_jiffies = fattr->time_start;
- nfsi->last_updated = now;
- /* Fix a wraparound issue with nfsi->cache_change_attribute */
- if (time_before(now, nfsi->cache_change_attribute))
- nfsi->cache_change_attribute = now - 600*HZ;
-
- /* Are we racing with known updates of the metadata on the server? */
- data_stable = nfs_verify_change_attribute(inode, fattr->time_start);
- if (data_stable)
- nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATIME);
+ nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
+ | NFS_INO_REVAL_PAGECACHE);
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
+ /* More cache consistency checks */
+ if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
+ /* NFSv2/v3: Check if the mtime agrees */
+ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
+ dprintk("NFS: mtime change on server for file %s/%ld\n",
+ inode->i_sb->s_id, inode->i_ino);
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+ nfsi->cache_change_attribute = now;
+ }
+ /* If ctime has changed we should definitely clear access+acl caches */
+ if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
+ invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+ } else if (nfsi->change_attr != fattr->change_attr) {
+ dprintk("NFS: change_attr change on server for file %s/%ld\n",
+ inode->i_sb->s_id, inode->i_ino);
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+ nfsi->cache_change_attribute = now;
+ }
+
/* Check if our cached file size is stale */
new_isize = nfs_size_to_loff_t(fattr->size);
cur_isize = i_size_read(inode);
if (new_isize != cur_isize) {
- /* Do we perhaps have any outstanding writes? */
- if (nfsi->npages == 0) {
- /* No, but did we race with nfs_end_data_update()? */
- if (data_stable) {
- inode->i_size = new_isize;
- invalid |= NFS_INO_INVALID_DATA;
- }
- invalid |= NFS_INO_INVALID_ATTR;
- } else if (new_isize > cur_isize) {
+ /* Do we perhaps have any outstanding writes, or has
+ * the file grown beyond our last write? */
+ if (nfsi->npages == 0 || new_isize > cur_isize) {
inode->i_size = new_isize;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
}
- nfsi->cache_change_attribute = now;
dprintk("NFS: isize change on server for file %s/%ld\n",
inode->i_sb->s_id, inode->i_ino);
}
- /* Check if the mtime agrees */
- if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
- memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
- dprintk("NFS: mtime change on server for file %s/%ld\n",
- inode->i_sb->s_id, inode->i_ino);
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
- nfsi->cache_change_attribute = now;
- }
- /* If ctime has changed we should definitely clear access+acl caches */
- if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
- invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
- memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
- nfsi->cache_change_attribute = now;
- }
+ memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+ memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
+ nfsi->change_attr = fattr->change_attr;
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
inode->i_uid != fattr->uid ||
@@ -1039,31 +1052,29 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_blocks = fattr->du.nfs2.blocks;
}
- if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
- nfsi->change_attr != fattr->change_attr) {
- dprintk("NFS: change_attr change on server for file %s/%ld\n",
- inode->i_sb->s_id, inode->i_ino);
- nfsi->change_attr = fattr->change_attr;
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
- nfsi->cache_change_attribute = now;
- }
-
/* Update attrtimeo value if we're out of the unstable period */
if (invalid & NFS_INO_INVALID_ATTR) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
- } else if (time_after(now, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
- if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
- nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
- nfsi->attrtimeo_timestamp = now;
+ nfsi->last_updated = now;
+ } else {
+ if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
+ if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
+ nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+ nfsi->attrtimeo_timestamp = now;
+ }
+ /*
+ * Avoid jiffy wraparound issues with nfsi->last_updated
+ */
+ if (!time_in_range(nfsi->last_updated, nfsi->read_cache_jiffies, now))
+ nfsi->last_updated = nfsi->read_cache_jiffies;
}
+ invalid &= ~NFS_INO_INVALID_ATTR;
/* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
invalid &= ~NFS_INO_INVALID_DATA;
- if (data_stable)
- invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
if (!nfs_have_delegation(inode, FMODE_READ) ||
(nfsi->cache_validity & NFS_INO_REVAL_FORCED))
nfsi->cache_validity |= invalid;
@@ -1152,7 +1163,6 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
- atomic_set(&nfsi->data_updates, 0);
nfsi->ncommit = 0;
nfsi->npages = 0;
nfs4_init_once(nfsi);
@@ -1249,6 +1259,7 @@ static void __exit exit_nfs_fs(void)
/* Not quite true; I just maintain it */
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
MODULE_LICENSE("GPL");
+module_param(enable_ino64, bool, 0644);
module_init(init_nfs_fs)
module_exit(exit_nfs_fs)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 76cf55d5710..f3acf48412b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -5,8 +5,6 @@
#include <linux/mount.h>
struct nfs_string;
-struct nfs_mount_data;
-struct nfs4_mount_data;
/* Maximum number of readahead requests
* FIXME: this should really be a sysctl so that users may tune it to suit
@@ -27,20 +25,50 @@ struct nfs_clone_mount {
rpc_authflavor_t authflavor;
};
+/*
+ * In-kernel mount arguments
+ */
+struct nfs_parsed_mount_data {
+ int flags;
+ int rsize, wsize;
+ int timeo, retrans;
+ int acregmin, acregmax,
+ acdirmin, acdirmax;
+ int namlen;
+ unsigned int bsize;
+ unsigned int auth_flavor_len;
+ rpc_authflavor_t auth_flavors[1];
+ char *client_address;
+
+ struct {
+ struct sockaddr_in address;
+ char *hostname;
+ unsigned int program;
+ unsigned int version;
+ unsigned short port;
+ int protocol;
+ } mount_server;
+
+ struct {
+ struct sockaddr_in address;
+ char *hostname;
+ char *export_path;
+ unsigned int program;
+ int protocol;
+ } nfs_server;
+};
+
/* client.c */
extern struct rpc_program nfs_program;
extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
-extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
- struct nfs_fh *);
-extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
- const char *,
- const struct sockaddr_in *,
- const char *,
- const char *,
- rpc_authflavor_t,
- struct nfs_fh *);
+extern struct nfs_server *nfs_create_server(
+ const struct nfs_parsed_mount_data *,
+ struct nfs_fh *);
+extern struct nfs_server *nfs4_create_server(
+ const struct nfs_parsed_mount_data *,
+ struct nfs_fh *);
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
struct nfs_fh *);
extern void nfs_free_server(struct nfs_server *server);
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index c5fce756720..668ab96c7b5 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -251,6 +251,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, count);
+ req->rq_rcv_buf.flags |= XDRBUF_READ;
return 0;
}
@@ -271,7 +272,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
res->eof = 0;
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READ reply header overflowed:"
+ dprintk("NFS: READ reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
@@ -281,7 +282,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
- printk(KERN_WARNING "NFS: server cheating in read reply: "
+ dprintk("NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
count = recvd;
}
@@ -313,6 +314,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
/* Copy the page array */
xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
+ sndbuf->flags |= XDRBUF_WRITE;
return 0;
}
@@ -431,7 +433,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+ dprintk("NFS: READDIR reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
@@ -454,7 +456,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
len = ntohl(*p++);
p += XDR_QUADLEN(len) + 1; /* name plus cookie */
if (len > NFS2_MAXNAMLEN) {
- printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
+ dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
len);
goto err_unmap;
}
@@ -471,7 +473,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
entry[0] = entry[1] = 0;
/* truncate listing ? */
if (!nr) {
- printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+ dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1;
}
goto out;
@@ -583,12 +585,12 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
/* Convert length of symlink */
len = ntohl(*p++);
if (len >= rcvbuf->page_len || len <= 0) {
- dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+ dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG;
}
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
+ dprintk("NFS: READLINK reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
@@ -597,7 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
}
recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) {
- printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+ dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd);
return -EIO;
}
@@ -695,7 +697,7 @@ nfs_stat_to_errno(int stat)
if (nfs_errtbl[i].stat == stat)
return nfs_errtbl[i].errno;
}
- printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+ dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
return nfs_errtbl[i].errno;
}
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 7322da4d205..9b7362565c0 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -317,13 +317,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
}
dprintk("NFS call setacl\n");
- nfs_begin_data_update(inode);
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
status = rpc_call_sync(server->client_acl, &msg, 0);
spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
spin_unlock(&inode->i_lock);
- nfs_end_data_update(inode);
dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index c7ca5d70870..4cdc2361a66 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -166,6 +166,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
nfs_fattr_init(&dir_attr);
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_refresh_inode(dir, &dir_attr);
if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
msg.rpc_argp = fhandle;
@@ -173,8 +174,6 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
}
dprintk("NFS reply lookup: %d\n", status);
- if (status >= 0)
- status = nfs_refresh_inode(dir, &dir_attr);
return status;
}
@@ -607,6 +606,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
nfs_fattr_init(&dir_attr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+
+ nfs_invalidate_atime(dir);
+
nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply readdir: %d\n", status);
return status;
@@ -724,9 +726,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN;
- /* Call back common NFS readpage processing */
- if (task->tk_status >= 0)
- nfs_refresh_inode(data->inode, &data->fattr);
+
+ nfs_invalidate_atime(data->inode);
+ nfs_refresh_inode(data->inode, &data->fattr);
return 0;
}
@@ -747,7 +749,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN;
if (task->tk_status >= 0)
- nfs_post_op_update_inode(data->inode, data->res.fattr);
+ nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
return 0;
}
@@ -775,8 +777,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
{
if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN;
- if (task->tk_status >= 0)
- nfs_post_op_update_inode(data->inode, data->res.fattr);
+ nfs_refresh_inode(data->inode, data->res.fattr);
return 0;
}
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index d9e08f0cf2a..616d3267b7e 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -346,6 +346,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, count);
+ req->rq_rcv_buf.flags |= XDRBUF_READ;
return 0;
}
@@ -367,6 +368,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
/* Copy the page array */
xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
+ sndbuf->flags |= XDRBUF_WRITE;
return 0;
}
@@ -524,7 +526,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+ dprintk("NFS: READDIR reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
@@ -547,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
len = ntohl(*p++); /* string length */
p += XDR_QUADLEN(len) + 2; /* name + cookie */
if (len > NFS3_MAXNAMLEN) {
- printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
+ dprintk("NFS: giant filename in readdir (len %x)!\n",
len);
goto err_unmap;
}
@@ -567,7 +569,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
goto short_pkt;
len = ntohl(*p++);
if (len > NFS3_FHSIZE) {
- printk(KERN_WARNING "NFS: giant filehandle in "
+ dprintk("NFS: giant filehandle in "
"readdir (len %x)!\n", len);
goto err_unmap;
}
@@ -588,7 +590,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
entry[0] = entry[1] = 0;
/* truncate listing ? */
if (!nr) {
- printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+ dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1;
}
goto out;
@@ -826,22 +828,23 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
/* Convert length of symlink */
len = ntohl(*p++);
if (len >= rcvbuf->page_len || len <= 0) {
- dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+ dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG;
}
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
+ dprintk("NFS: READLINK reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
- dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+ dprintk("NFS: READLINK header is short. "
+ "iovec will be shifted.\n");
xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
}
recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) {
- printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+ dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd);
return -EIO;
}
@@ -876,13 +879,13 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
ocount = ntohl(*p++);
if (ocount != count) {
- printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
+ dprintk("NFS: READ count doesn't match RPC opaque count.\n");
return -errno_NFSERR_IO;
}
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) {
- printk(KERN_WARNING "NFS: READ reply header overflowed:"
+ dprintk("NFS: READ reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) {
@@ -892,7 +895,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
- printk(KERN_WARNING "NFS: server cheating in read reply: "
+ dprintk("NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
count = recvd;
res->eof = 0;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4b90e17555a..cb99fd90a9a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -62,10 +62,8 @@ struct nfs4_opendata;
static int _nfs4_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
-static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
-static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
@@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
*p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */
- p = xdr_encode_hyper(p, dentry->d_inode->i_ino);
+ p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
}
*p++ = xdr_one; /* next */
@@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
*p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */
- p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino);
+ p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
readdir->pgbase = (char *)p - (char *)start;
readdir->count -= readdir->pgbase;
@@ -211,8 +209,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
spin_lock(&dir->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
- if (cinfo->before == nfsi->change_attr && cinfo->atomic)
- nfsi->change_attr = cinfo->after;
+ if (!cinfo->atomic || cinfo->before != nfsi->change_attr)
+ nfsi->cache_change_attribute = jiffies;
+ nfsi->change_attr = cinfo->after;
spin_unlock(&dir->i_lock);
}
@@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
rcu_read_unlock();
lock_kernel();
- ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode);
+ ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
unlock_kernel();
if (ret != 0)
goto out;
@@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return 0;
}
-static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
-{
- struct nfs_access_entry cache;
- int mask = 0;
- int status;
-
- if (openflags & FMODE_READ)
- mask |= MAY_READ;
- if (openflags & FMODE_WRITE)
- mask |= MAY_WRITE;
- if (openflags & FMODE_EXEC)
- mask |= MAY_EXEC;
- status = nfs_access_get_cached(inode, cred, &cache);
- if (status == 0)
- goto out;
-
- /* Be clever: ask server to check for all possible rights */
- cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
- cache.cred = cred;
- cache.jiffies = jiffies;
- status = _nfs4_proc_access(inode, &cache);
- if (status != 0)
- return status;
- nfs_access_add_cache(inode, &cache);
-out:
- if ((cache.mask & mask) == mask)
- return 0;
- return -EACCES;
-}
-
static int nfs4_recover_expired_lease(struct nfs_server *server)
{
struct nfs_client *clp = server->nfs_client;
@@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
/* If the open_intent is for execute, we have an extra check to make */
if (nd->intent.open.flags & FMODE_EXEC) {
- ret = _nfs4_do_access(state->inode,
+ ret = nfs_may_open(state->inode,
state->owner->so_cred,
nd->intent.open.flags);
if (ret < 0)
@@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
filp = lookup_instantiate_filp(nd, path->dentry, NULL);
if (!IS_ERR(filp)) {
struct nfs_open_context *ctx;
- ctx = (struct nfs_open_context *)filp->private_data;
+ ctx = nfs_file_open_context(filp);
ctx->state = state;
return 0;
}
@@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
- if (PTR_ERR(state) == -ENOENT)
+ if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ }
return (struct dentry *)state;
}
res = d_add_unique(dentry, igrab(state->inode));
if (res != NULL)
path.dentry = res;
+ nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
nfs4_intent_set_file(nd, &path, state);
return res;
}
@@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
}
}
if (state->inode == dentry->d_inode) {
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
nfs4_intent_set_file(nd, &path, state);
return 1;
}
@@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_fattr fattr;
struct nfs4_accessargs args = {
.fh = NFS_FH(inode),
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_accessres res = {
+ .server = server,
+ .fattr = &fattr,
};
- struct nfs4_accessres res = { 0 };
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
.rpc_argp = &args,
@@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
if (mode & MAY_EXEC)
args.access |= NFS4_ACCESS_EXECUTE;
}
+ nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (!status) {
entry->mask = 0;
@@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
entry->mask |= MAY_WRITE;
if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
entry->mask |= MAY_EXEC;
+ nfs_refresh_inode(inode, &fattr);
}
return status;
}
@@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
}
state = nfs4_do_open(dir, &path, flags, sattr, cred);
put_rpccred(cred);
+ d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
goto out;
}
- d_instantiate(dentry, igrab(state->inode));
+ d_add(dentry, igrab(state->inode));
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) {
struct nfs_fattr fattr;
status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
@@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (status == 0)
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
+
+ nfs_invalidate_atime(dir);
+
dprintk("%s: returns %d\n", __FUNCTION__, status);
return status;
}
@@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
rpc_restart_call(task);
return -EAGAIN;
}
+
+ nfs_invalidate_atime(data->inode);
if (task->tk_status > 0)
renew_lease(server, data->timestamp);
return 0;
@@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
}
if (task->tk_status >= 0) {
renew_lease(NFS_SERVER(inode), data->timestamp);
- nfs_post_op_update_inode(inode, data->res.fattr);
+ nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
}
return 0;
}
@@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
rpc_restart_call(task);
return -EAGAIN;
}
- if (task->tk_status >= 0)
- nfs_post_op_update_inode(inode, data->res.fattr);
+ nfs_refresh_inode(inode, data->res.fattr);
return 0;
}
@@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
if (status == 0) {
status = data->rpc_status;
if (status == 0)
- nfs_post_op_update_inode(inode, &data->fattr);
+ nfs_refresh_inode(inode, &data->fattr);
}
rpc_put_task(task);
return status;
@@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
status = -ENOMEM;
if (seqid == NULL)
goto out;
- task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
+ task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
status = PTR_ERR(task);
if (IS_ERR(task))
goto out;
@@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
int ret;
dprintk("%s: begin!\n", __FUNCTION__);
- data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data,
+ data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
fl->fl_u.nfs4_fl.owner);
if (data == NULL)
return -ENOMEM;
@@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
int status;
/* verify open state */
- ctx = (struct nfs_open_context *)filp->private_data;
+ ctx = nfs_file_open_context(filp);
state = ctx->state;
if (request->fl_start < 0 || request->fl_end < 0)
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 3e4adf8c831..bfb36261cec 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -774,7 +774,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue;
- if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
+ if (nfs_file_open_context(fl->fl_file)->state != state)
continue;
status = ops->recover_lock(state, fl);
if (status >= 0)
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index badd73b7ca1..51dd3804866 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -376,10 +376,12 @@ static int nfs4_stat_to_errno(int);
decode_locku_maxsz)
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_access_maxsz)
+ encode_access_maxsz + \
+ encode_getattr_maxsz)
#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_access_maxsz)
+ decode_access_maxsz + \
+ decode_getattr_maxsz)
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
@@ -562,7 +564,6 @@ struct compound_hdr {
#define RESERVE_SPACE(nbytes) do { \
p = xdr_reserve_space(xdr, nbytes); \
- if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
BUG_ON(!p); \
} while (0)
@@ -628,8 +629,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
if (owner_namelen < 0) {
- printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
- iap->ia_uid);
+ dprintk("nfs: couldn't resolve uid %d to string\n",
+ iap->ia_uid);
/* XXX */
strcpy(owner_name, "nobody");
owner_namelen = sizeof("nobody") - 1;
@@ -640,8 +641,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
if (iap->ia_valid & ATTR_GID) {
owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
if (owner_grouplen < 0) {
- printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
- iap->ia_gid);
+ dprintk("nfs: couldn't resolve gid %d to string\n",
+ iap->ia_gid);
strcpy(owner_group, "nobody");
owner_grouplen = sizeof("nobody") - 1;
/* goto out; */
@@ -711,7 +712,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
* Now we backfill the bitmap and the attribute buffer length.
*/
if (len != ((char *)p - (char *)q) + 4) {
- printk ("encode_attr: Attr length calculation error! %u != %Zu\n",
+ printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
len, ((char *)p - (char *)q) + 4);
BUG();
}
@@ -1376,14 +1377,20 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 3,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->fh)) == 0)
- status = encode_access(&xdr, args->access);
+ status = encode_putfh(&xdr, args->fh);
+ if (status != 0)
+ goto out;
+ status = encode_access(&xdr, args->access);
+ if (status != 0)
+ goto out;
+ status = encode_getfattr(&xdr, args->bitmask);
+out:
return status;
}
@@ -1857,6 +1864,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, args->count);
+ req->rq_rcv_buf.flags |= XDRBUF_READ;
out:
return status;
}
@@ -1933,6 +1941,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
status = encode_write(&xdr, args);
if (status)
goto out;
+ req->rq_snd_buf.flags |= XDRBUF_WRITE;
status = encode_getfattr(&xdr, args->bitmask);
out:
return status;
@@ -2180,9 +2189,9 @@ out:
#define READ_BUF(nbytes) do { \
p = xdr_inline_decode(xdr, nbytes); \
if (unlikely(!p)) { \
- printk(KERN_INFO "%s: prematurely hit end of receive" \
+ dprintk("nfs: %s: prematurely hit end of receive" \
" buffer\n", __FUNCTION__); \
- printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
+ dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
__FUNCTION__, xdr->p, nbytes, xdr->end); \
return -EIO; \
} \
@@ -2223,9 +2232,8 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
READ_BUF(8);
READ32(opnum);
if (opnum != expected) {
- printk(KERN_NOTICE
- "nfs4_decode_op_hdr: Server returned operation"
- " %d but we issued a request for %d\n",
+ dprintk("nfs: Server returned operation"
+ " %d but we issued a request for %d\n",
opnum, expected);
return -EIO;
}
@@ -2758,7 +2766,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
dprintk("%s: nfs_map_name_to_uid failed!\n",
__FUNCTION__);
} else
- printk(KERN_WARNING "%s: name too long (%u)!\n",
+ dprintk("%s: name too long (%u)!\n",
__FUNCTION__, len);
bitmap[1] &= ~FATTR4_WORD1_OWNER;
}
@@ -2783,7 +2791,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
dprintk("%s: nfs_map_group_to_gid failed!\n",
__FUNCTION__);
} else
- printk(KERN_WARNING "%s: name too long (%u)!\n",
+ dprintk("%s: name too long (%u)!\n",
__FUNCTION__, len);
bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
}
@@ -2950,7 +2958,8 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl
unsigned int nwords = xdr->p - savep;
if (unlikely(attrwords != nwords)) {
- printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
+ dprintk("%s: server returned incorrect attribute length: "
+ "%u %c %u\n",
__FUNCTION__,
attrwords << 2,
(attrwords < nwords) ? '<' : '>',
@@ -3451,7 +3460,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
- printk(KERN_WARNING "NFS: server cheating in read reply: "
+ dprintk("NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd);
count = recvd;
eof = 0;
@@ -3500,7 +3509,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
p += 2; /* cookie */
len = ntohl(*p++); /* filename length */
if (len > NFS4_MAXNAMLEN) {
- printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
+ dprintk("NFS: giant filename in readdir (len 0x%x)\n",
+ len);
goto err_unmap;
}
xlen = XDR_QUADLEN(len);
@@ -3528,7 +3538,7 @@ short_pkt:
entry[0] = entry[1] = 0;
/* truncate listing ? */
if (!nr) {
- printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+ dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1;
}
goto out;
@@ -3554,13 +3564,13 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
READ_BUF(4);
READ32(len);
if (len >= rcvbuf->page_len || len <= 0) {
- dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+ dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG;
}
hdrlen = (char *) xdr->p - (char *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) {
- printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+ dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd);
return -EIO;
}
@@ -3643,7 +3653,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (attrlen > recvd) {
- printk(KERN_WARNING "NFS: server cheating in getattr"
+ dprintk("NFS: server cheating in getattr"
" acl reply: attrlen %u > recvd %u\n",
attrlen, recvd);
return -EINVAL;
@@ -3688,8 +3698,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
READ_BUF(8);
READ32(opnum);
if (opnum != OP_SETCLIENTID) {
- printk(KERN_NOTICE
- "nfs4_decode_setclientid: Server returned operation"
+ dprintk("nfs: decode_setclientid: Server returned operation"
" %d\n", opnum);
return -EIO;
}
@@ -3783,8 +3792,13 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
- if ((status = decode_putfh(&xdr)) == 0)
- status = decode_access(&xdr, res);
+ status = decode_putfh(&xdr);
+ if (status != 0)
+ goto out;
+ status = decode_access(&xdr, res);
+ if (status != 0)
+ goto out;
+ decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 3490322d114..e87b44ee9ac 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -76,6 +76,7 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsock.h>
#include <linux/nfs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
@@ -491,7 +492,7 @@ static int __init root_nfs_get_handle(void)
struct sockaddr_in sin;
int status;
int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
- IPPROTO_TCP : IPPROTO_UDP;
+ XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP;
int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
NFS_MNT3_VERSION : NFS_MNT_VERSION;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 845cdde1d8b..97669ed0550 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -476,6 +476,8 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
dprintk("NFS call readdir %d\n", (unsigned int)cookie);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_invalidate_atime(dir);
+
dprintk("NFS reply readdir: %d\n", status);
return status;
}
@@ -550,6 +552,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
+ nfs_invalidate_atime(data->inode);
if (task->tk_status >= 0) {
nfs_refresh_inode(data->inode, data->res.fattr);
/* Emulate the eof flag, which isn't normally needed in NFSv2
@@ -576,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
if (task->tk_status >= 0)
- nfs_post_op_update_inode(data->inode, data->res.fattr);
+ nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
return 0;
}
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 19e05633f4e..4587a86adaa 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -341,9 +341,6 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode));
nfs_mark_for_revalidate(data->inode);
}
- spin_lock(&data->inode->i_lock);
- NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME;
- spin_unlock(&data->inode->i_lock);
return 0;
}
@@ -497,8 +494,7 @@ int nfs_readpage(struct file *file, struct page *page)
if (ctx == NULL)
goto out_unlock;
} else
- ctx = get_nfs_open_context((struct nfs_open_context *)
- file->private_data);
+ ctx = get_nfs_open_context(nfs_file_open_context(file));
error = nfs_readpage_async(ctx, inode, page);
@@ -576,8 +572,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
if (desc.ctx == NULL)
return -EBADF;
} else
- desc.ctx = get_nfs_open_context((struct nfs_open_context *)
- filp->private_data);
+ desc.ctx = get_nfs_open_context(nfs_file_open_context(filp));
if (rsize < PAGE_CACHE_SIZE)
nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
else
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b878528b64c..fa517ae9207 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -33,6 +33,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
+#include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtrdma.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
@@ -58,36 +60,6 @@
#define NFSDBG_FACILITY NFSDBG_VFS
-
-struct nfs_parsed_mount_data {
- int flags;
- int rsize, wsize;
- int timeo, retrans;
- int acregmin, acregmax,
- acdirmin, acdirmax;
- int namlen;
- unsigned int bsize;
- unsigned int auth_flavor_len;
- rpc_authflavor_t auth_flavors[1];
- char *client_address;
-
- struct {
- struct sockaddr_in address;
- unsigned int program;
- unsigned int version;
- unsigned short port;
- int protocol;
- } mount_server;
-
- struct {
- struct sockaddr_in address;
- char *hostname;
- char *export_path;
- unsigned int program;
- int protocol;
- } nfs_server;
-};
-
enum {
/* Mount options that take no arguments */
Opt_soft, Opt_hard,
@@ -97,7 +69,7 @@ enum {
Opt_ac, Opt_noac,
Opt_lock, Opt_nolock,
Opt_v2, Opt_v3,
- Opt_udp, Opt_tcp,
+ Opt_udp, Opt_tcp, Opt_rdma,
Opt_acl, Opt_noacl,
Opt_rdirplus, Opt_nordirplus,
Opt_sharecache, Opt_nosharecache,
@@ -116,7 +88,7 @@ enum {
/* Mount options that take string arguments */
Opt_sec, Opt_proto, Opt_mountproto,
- Opt_addr, Opt_mounthost, Opt_clientaddr,
+ Opt_addr, Opt_mountaddr, Opt_clientaddr,
/* Mount options that are ignored */
Opt_userspace, Opt_deprecated,
@@ -143,6 +115,7 @@ static match_table_t nfs_mount_option_tokens = {
{ Opt_v3, "v3" },
{ Opt_udp, "udp" },
{ Opt_tcp, "tcp" },
+ { Opt_rdma, "rdma" },
{ Opt_acl, "acl" },
{ Opt_noacl, "noacl" },
{ Opt_rdirplus, "rdirplus" },
@@ -175,13 +148,14 @@ static match_table_t nfs_mount_option_tokens = {
{ Opt_mountproto, "mountproto=%s" },
{ Opt_addr, "addr=%s" },
{ Opt_clientaddr, "clientaddr=%s" },
- { Opt_mounthost, "mounthost=%s" },
+ { Opt_userspace, "mounthost=%s" },
+ { Opt_mountaddr, "mountaddr=%s" },
{ Opt_err, NULL }
};
enum {
- Opt_xprt_udp, Opt_xprt_tcp,
+ Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma,
Opt_xprt_err
};
@@ -189,6 +163,7 @@ enum {
static match_table_t nfs_xprt_protocol_tokens = {
{ Opt_xprt_udp, "udp" },
{ Opt_xprt_tcp, "tcp" },
+ { Opt_xprt_rdma, "rdma" },
{ Opt_xprt_err, NULL }
};
@@ -449,7 +424,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
const char *nostr;
} nfs_info[] = {
{ NFS_MOUNT_SOFT, ",soft", ",hard" },
- { NFS_MOUNT_INTR, ",intr", "" },
+ { NFS_MOUNT_INTR, ",intr", ",nointr" },
{ NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", "" },
@@ -460,8 +435,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
};
const struct proc_nfs_info *nfs_infop;
struct nfs_client *clp = nfss->nfs_client;
- char buf[12];
- const char *proto;
seq_printf(m, ",vers=%d", clp->rpc_ops->version);
seq_printf(m, ",rsize=%d", nfss->rsize);
@@ -480,18 +453,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
else
seq_puts(m, nfs_infop->nostr);
}
- switch (nfss->client->cl_xprt->prot) {
- case IPPROTO_TCP:
- proto = "tcp";
- break;
- case IPPROTO_UDP:
- proto = "udp";
- break;
- default:
- snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
- proto = buf;
- }
- seq_printf(m, ",proto=%s", proto);
+ seq_printf(m, ",proto=%s",
+ rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
seq_printf(m, ",retrans=%u", clp->retrans_count);
seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
@@ -506,8 +469,8 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
nfs_show_mount_options(m, nfss, 0);
- seq_puts(m, ",addr=");
- seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
+ seq_printf(m, ",addr="NIPQUAD_FMT,
+ NIPQUAD(nfss->nfs_client->cl_addr.sin_addr));
return 0;
}
@@ -698,13 +661,19 @@ static int nfs_parse_mount_options(char *raw,
break;
case Opt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = IPPROTO_UDP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
mnt->timeo = 7;
mnt->retrans = 5;
break;
case Opt_tcp:
mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = IPPROTO_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ mnt->timeo = 600;
+ mnt->retrans = 2;
+ break;
+ case Opt_rdma:
+ mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
mnt->timeo = 600;
mnt->retrans = 2;
break;
@@ -913,13 +882,20 @@ static int nfs_parse_mount_options(char *raw,
switch (token) {
case Opt_xprt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = IPPROTO_UDP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
mnt->timeo = 7;
mnt->retrans = 5;
break;
case Opt_xprt_tcp:
mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = IPPROTO_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ mnt->timeo = 600;
+ mnt->retrans = 2;
+ break;
+ case Opt_xprt_rdma:
+ /* vector side protocols to TCP */
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
mnt->timeo = 600;
mnt->retrans = 2;
break;
@@ -937,11 +913,12 @@ static int nfs_parse_mount_options(char *raw,
switch (token) {
case Opt_xprt_udp:
- mnt->mount_server.protocol = IPPROTO_UDP;
+ mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_xprt_tcp:
- mnt->mount_server.protocol = IPPROTO_TCP;
+ mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
break;
+ case Opt_xprt_rdma: /* not used for side protocols */
default:
goto out_unrec_xprt;
}
@@ -961,7 +938,7 @@ static int nfs_parse_mount_options(char *raw,
goto out_nomem;
mnt->client_address = string;
break;
- case Opt_mounthost:
+ case Opt_mountaddr:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
@@ -1027,16 +1004,10 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
sin = args->mount_server.address;
else
sin = args->nfs_server.address;
- if (args->mount_server.port == 0) {
- status = rpcb_getport_sync(&sin,
- args->mount_server.program,
- args->mount_server.version,
- args->mount_server.protocol);
- if (status < 0)
- goto out_err;
- sin.sin_port = htons(status);
- } else
- sin.sin_port = htons(args->mount_server.port);
+ /*
+ * autobind will be used if mount_server.port == 0
+ */
+ sin.sin_port = htons(args->mount_server.port);
/*
* Now ask the mount server to map our export path
@@ -1049,14 +1020,11 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
args->mount_server.version,
args->mount_server.protocol,
root_fh);
- if (status < 0)
- goto out_err;
-
- return status;
+ if (status == 0)
+ return 0;
-out_err:
- dfprintk(MOUNT, "NFS: unable to contact server on host "
- NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr));
+ dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT
+ ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status);
return status;
}
@@ -1079,15 +1047,31 @@ out_err:
* XXX: as far as I can tell, changing the NFS program number is not
* supported in the NFS client.
*/
-static int nfs_validate_mount_data(struct nfs_mount_data **options,
+static int nfs_validate_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
struct nfs_fh *mntfh,
const char *dev_name)
{
- struct nfs_mount_data *data = *options;
+ struct nfs_mount_data *data = (struct nfs_mount_data *)options;
if (data == NULL)
goto out_no_data;
+ memset(args, 0, sizeof(*args));
+ args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
+ args->rsize = NFS_MAX_FILE_IO_SIZE;
+ args->wsize = NFS_MAX_FILE_IO_SIZE;
+ args->timeo = 600;
+ args->retrans = 2;
+ args->acregmin = 3;
+ args->acregmax = 60;
+ args->acdirmin = 30;
+ args->acdirmax = 60;
+ args->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ args->mount_server.program = NFS_MNT_PROGRAM;
+ args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ args->nfs_server.program = NFS_PROGRAM;
+
switch (data->version) {
case 1:
data->namlen = 0;
@@ -1116,92 +1100,73 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options,
if (mntfh->size < sizeof(mntfh->data))
memset(mntfh->data + mntfh->size, 0,
sizeof(mntfh->data) - mntfh->size);
+
+ if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
+ goto out_no_address;
+
+ /*
+ * Translate to nfs_parsed_mount_data, which nfs_fill_super
+ * can deal with.
+ */
+ args->flags = data->flags;
+ args->rsize = data->rsize;
+ args->wsize = data->wsize;
+ args->flags = data->flags;
+ args->timeo = data->timeo;
+ args->retrans = data->retrans;
+ args->acregmin = data->acregmin;
+ args->acregmax = data->acregmax;
+ args->acdirmin = data->acdirmin;
+ args->acdirmax = data->acdirmax;
+ args->nfs_server.address = data->addr;
+ if (!(data->flags & NFS_MOUNT_TCP))
+ args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+ args->namlen = data->namlen;
+ args->bsize = data->bsize;
+ args->auth_flavors[0] = data->pseudoflavor;
break;
default: {
unsigned int len;
char *c;
int status;
- struct nfs_parsed_mount_data args = {
- .flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP),
- .rsize = NFS_MAX_FILE_IO_SIZE,
- .wsize = NFS_MAX_FILE_IO_SIZE,
- .timeo = 600,
- .retrans = 2,
- .acregmin = 3,
- .acregmax = 60,
- .acdirmin = 30,
- .acdirmax = 60,
- .mount_server.protocol = IPPROTO_UDP,
- .mount_server.program = NFS_MNT_PROGRAM,
- .nfs_server.protocol = IPPROTO_TCP,
- .nfs_server.program = NFS_PROGRAM,
- };
-
- if (nfs_parse_mount_options((char *) *options, &args) == 0)
- return -EINVAL;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
+ if (nfs_parse_mount_options((char *)options, args) == 0)
+ return -EINVAL;
- /*
- * NB: after this point, caller will free "data"
- * if we return an error
- */
- *options = data;
+ if (!nfs_verify_server_address((struct sockaddr *)
+ &args->nfs_server.address))
+ goto out_no_address;
c = strchr(dev_name, ':');
if (c == NULL)
return -EINVAL;
len = c - dev_name;
- if (len > sizeof(data->hostname))
- return -ENAMETOOLONG;
- strncpy(data->hostname, dev_name, len);
- args.nfs_server.hostname = data->hostname;
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
c++;
if (strlen(c) > NFS_MAXPATHLEN)
return -ENAMETOOLONG;
- args.nfs_server.export_path = c;
+ args->nfs_server.export_path = c;
- status = nfs_try_mount(&args, mntfh);
+ status = nfs_try_mount(args, mntfh);
if (status)
return status;
- /*
- * Translate to nfs_mount_data, which nfs_fill_super
- * can deal with.
- */
- data->version = 6;
- data->flags = args.flags;
- data->rsize = args.rsize;
- data->wsize = args.wsize;
- data->timeo = args.timeo;
- data->retrans = args.retrans;
- data->acregmin = args.acregmin;
- data->acregmax = args.acregmax;
- data->acdirmin = args.acdirmin;
- data->acdirmax = args.acdirmax;
- data->addr = args.nfs_server.address;
- data->namlen = args.namlen;
- data->bsize = args.bsize;
- data->pseudoflavor = args.auth_flavors[0];
-
break;
}
}
- if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
- data->pseudoflavor = RPC_AUTH_UNIX;
+ if (!(args->flags & NFS_MOUNT_SECFLAVOUR))
+ args->auth_flavors[0] = RPC_AUTH_UNIX;
#ifndef CONFIG_NFS_V3
- if (data->flags & NFS_MOUNT_VER3)
+ if (args->flags & NFS_MOUNT_VER3)
goto out_v3_not_compiled;
#endif /* !CONFIG_NFS_V3 */
- if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
- goto out_no_address;
-
return 0;
out_no_data:
@@ -1258,7 +1223,8 @@ static inline void nfs_initialise_sb(struct super_block *sb)
/*
* Finish setting up an NFS2/3 superblock
*/
-static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
+static void nfs_fill_super(struct super_block *sb,
+ struct nfs_parsed_mount_data *data)
{
struct nfs_server *server = NFS_SB(sb);
@@ -1379,7 +1345,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
struct nfs_server *server = NULL;
struct super_block *s;
struct nfs_fh mntfh;
- struct nfs_mount_data *data = raw_data;
+ struct nfs_parsed_mount_data data;
struct dentry *mntroot;
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
struct nfs_sb_mountdata sb_mntdata = {
@@ -1388,12 +1354,12 @@ static int nfs_get_sb(struct file_system_type *fs_type,
int error;
/* Validate the mount data */
- error = nfs_validate_mount_data(&data, &mntfh, dev_name);
+ error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
if (error < 0)
goto out;
/* Get a volume representation */
- server = nfs_create_server(data, &mntfh);
+ server = nfs_create_server(&data, &mntfh);
if (IS_ERR(server)) {
error = PTR_ERR(server);
goto out;
@@ -1417,7 +1383,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
if (!s->s_root) {
/* initial superblock/root creation */
- nfs_fill_super(s, data);
+ nfs_fill_super(s, &data);
}
mntroot = nfs_get_root(s, &mntfh);
@@ -1432,8 +1398,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
error = 0;
out:
- if (data != raw_data)
- kfree(data);
+ kfree(data.nfs_server.hostname);
return error;
out_err_nosb:
@@ -1559,38 +1524,49 @@ static void nfs4_fill_super(struct super_block *sb)
/*
* Validate NFSv4 mount options
*/
-static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
- const char *dev_name,
- struct sockaddr_in *addr,
- rpc_authflavor_t *authflavour,
- char **hostname,
- char **mntpath,
- char **ip_addr)
+static int nfs4_validate_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
+ const char *dev_name)
{
- struct nfs4_mount_data *data = *options;
+ struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
char *c;
if (data == NULL)
goto out_no_data;
+ memset(args, 0, sizeof(*args));
+ args->rsize = NFS_MAX_FILE_IO_SIZE;
+ args->wsize = NFS_MAX_FILE_IO_SIZE;
+ args->timeo = 600;
+ args->retrans = 2;
+ args->acregmin = 3;
+ args->acregmax = 60;
+ args->acdirmin = 30;
+ args->acdirmax = 60;
+ args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+
switch (data->version) {
case 1:
- if (data->host_addrlen != sizeof(*addr))
+ if (data->host_addrlen != sizeof(args->nfs_server.address))
goto out_no_address;
- if (copy_from_user(addr, data->host_addr, sizeof(*addr)))
+ if (copy_from_user(&args->nfs_server.address,
+ data->host_addr,
+ sizeof(args->nfs_server.address)))
return -EFAULT;
- if (addr->sin_port == 0)
- addr->sin_port = htons(NFS_PORT);
- if (!nfs_verify_server_address((struct sockaddr *) addr))
+ if (args->nfs_server.address.sin_port == 0)
+ args->nfs_server.address.sin_port = htons(NFS_PORT);
+ if (!nfs_verify_server_address((struct sockaddr *)
+ &args->nfs_server.address))
goto out_no_address;
switch (data->auth_flavourlen) {
case 0:
- *authflavour = RPC_AUTH_UNIX;
+ args->auth_flavors[0] = RPC_AUTH_UNIX;
break;
case 1:
- if (copy_from_user(authflavour, data->auth_flavours,
- sizeof(*authflavour)))
+ if (copy_from_user(&args->auth_flavors[0],
+ data->auth_flavours,
+ sizeof(args->auth_flavors[0])))
return -EFAULT;
break;
default:
@@ -1600,75 +1576,57 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
if (IS_ERR(c))
return PTR_ERR(c);
- *hostname = c;
+ args->nfs_server.hostname = c;
c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
if (IS_ERR(c))
return PTR_ERR(c);
- *mntpath = c;
- dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath);
+ args->nfs_server.export_path = c;
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
c = strndup_user(data->client_addr.data, 16);
if (IS_ERR(c))
return PTR_ERR(c);
- *ip_addr = c;
+ args->client_address = c;
+
+ /*
+ * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+ * can deal with.
+ */
+
+ args->flags = data->flags & NFS4_MOUNT_FLAGMASK;
+ args->rsize = data->rsize;
+ args->wsize = data->wsize;
+ args->timeo = data->timeo;
+ args->retrans = data->retrans;
+ args->acregmin = data->acregmin;
+ args->acregmax = data->acregmax;
+ args->acdirmin = data->acdirmin;
+ args->acdirmax = data->acdirmax;
+ args->nfs_server.protocol = data->proto;
break;
default: {
unsigned int len;
- struct nfs_parsed_mount_data args = {
- .rsize = NFS_MAX_FILE_IO_SIZE,
- .wsize = NFS_MAX_FILE_IO_SIZE,
- .timeo = 600,
- .retrans = 2,
- .acregmin = 3,
- .acregmax = 60,
- .acdirmin = 30,
- .acdirmax = 60,
- .nfs_server.protocol = IPPROTO_TCP,
- };
-
- if (nfs_parse_mount_options((char *) *options, &args) == 0)
+
+ if (nfs_parse_mount_options((char *)options, args) == 0)
return -EINVAL;
if (!nfs_verify_server_address((struct sockaddr *)
- &args.nfs_server.address))
+ &args->nfs_server.address))
return -EINVAL;
- *addr = args.nfs_server.address;
- switch (args.auth_flavor_len) {
+ switch (args->auth_flavor_len) {
case 0:
- *authflavour = RPC_AUTH_UNIX;
+ args->auth_flavors[0] = RPC_AUTH_UNIX;
break;
case 1:
- *authflavour = (rpc_authflavor_t) args.auth_flavors[0];
break;
default:
goto out_inval_auth;
}
/*
- * Translate to nfs4_mount_data, which nfs4_fill_super
- * can deal with.
- */
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
- *options = data;
-
- data->version = 1;
- data->flags = args.flags & NFS4_MOUNT_FLAGMASK;
- data->rsize = args.rsize;
- data->wsize = args.wsize;
- data->timeo = args.timeo;
- data->retrans = args.retrans;
- data->acregmin = args.acregmin;
- data->acregmax = args.acregmax;
- data->acdirmin = args.acdirmin;
- data->acdirmax = args.acdirmax;
- data->proto = args.nfs_server.protocol;
-
- /*
* Split "dev_name" into "hostname:mntpath".
*/
c = strchr(dev_name, ':');
@@ -1678,27 +1636,25 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
len = c - dev_name;
if (len > NFS4_MAXNAMLEN)
return -ENAMETOOLONG;
- *hostname = kzalloc(len, GFP_KERNEL);
- if (*hostname == NULL)
+ args->nfs_server.hostname = kzalloc(len, GFP_KERNEL);
+ if (args->nfs_server.hostname == NULL)
return -ENOMEM;
- strncpy(*hostname, dev_name, len - 1);
+ strncpy(args->nfs_server.hostname, dev_name, len - 1);
c++; /* step over the ':' */
len = strlen(c);
if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
- *mntpath = kzalloc(len + 1, GFP_KERNEL);
- if (*mntpath == NULL)
+ args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL);
+ if (args->nfs_server.export_path == NULL)
return -ENOMEM;
- strncpy(*mntpath, c, len);
+ strncpy(args->nfs_server.export_path, c, len);
- dprintk("MNTPATH: %s\n", *mntpath);
+ dprintk("MNTPATH: %s\n", args->nfs_server.export_path);
- if (args.client_address == NULL)
+ if (args->client_address == NULL)
goto out_no_client_address;
- *ip_addr = args.client_address;
-
break;
}
}
@@ -1729,14 +1685,11 @@ out_no_client_address:
static int nfs4_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
{
- struct nfs4_mount_data *data = raw_data;
+ struct nfs_parsed_mount_data data;
struct super_block *s;
struct nfs_server *server;
- struct sockaddr_in addr;
- rpc_authflavor_t authflavour;
struct nfs_fh mntfh;
struct dentry *mntroot;
- char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
struct nfs_sb_mountdata sb_mntdata = {
.mntflags = flags,
@@ -1744,14 +1697,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
int error;
/* Validate the mount data */
- error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour,
- &hostname, &mntpath, &ip_addr);
+ error = nfs4_validate_mount_data(raw_data, &data, dev_name);
if (error < 0)
goto out;
/* Get a volume representation */
- server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
- authflavour, &mntfh);
+ server = nfs4_create_server(&data, &mntfh);
if (IS_ERR(server)) {
error = PTR_ERR(server);
goto out;
@@ -1790,9 +1741,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
error = 0;
out:
- kfree(ip_addr);
- kfree(mntpath);
- kfree(hostname);
+ kfree(data.client_address);
+ kfree(data.nfs_server.export_path);
+ kfree(data.nfs_server.hostname);
return error;
out_free:
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 045ab805c17..1aed850d18f 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -66,7 +66,6 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
.rpc_cred = data->cred,
};
- nfs_begin_data_update(dir);
NFS_PROTO(dir)->unlink_setup(&msg, dir);
rpc_call_setup(task, &msg, 0);
}
@@ -84,8 +83,6 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
if (!NFS_PROTO(dir)->unlink_done(task, dir))
rpc_restart_call(task);
- else
- nfs_end_data_update(dir);
}
/**
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 0d7a77cc394..e2bb66c3440 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -110,6 +110,13 @@ void nfs_writedata_release(void *wdata)
nfs_writedata_free(wdata);
}
+static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
+{
+ ctx->error = error;
+ smp_wmb();
+ set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+}
+
static struct nfs_page *nfs_page_find_request_locked(struct page *page)
{
struct nfs_page *req = NULL;
@@ -243,10 +250,7 @@ static void nfs_end_page_writeback(struct page *page)
/*
* Find an associated nfs write request, and prepare to flush it out
- * Returns 1 if there was no write request, or if the request was
- * already tagged by nfs_set_page_dirty.Returns 0 if the request
- * was not tagged.
- * May also return an error if the user signalled nfs_wait_on_request().
+ * May return an error if the user signalled nfs_wait_on_request().
*/
static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
struct page *page)
@@ -261,7 +265,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
req = nfs_page_find_request_locked(page);
if (req == NULL) {
spin_unlock(&inode->i_lock);
- return 1;
+ return 0;
}
if (nfs_lock_request_dontget(req))
break;
@@ -282,7 +286,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
spin_unlock(&inode->i_lock);
nfs_unlock_request(req);
nfs_pageio_complete(pgio);
- return 1;
+ return 0;
}
if (nfs_set_page_writeback(page) != 0) {
spin_unlock(&inode->i_lock);
@@ -290,70 +294,56 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
}
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
NFS_PAGE_TAG_LOCKED);
- ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
spin_unlock(&inode->i_lock);
nfs_pageio_add_request(pgio, req);
- return ret;
+ return 0;
}
-/*
- * Write an mmapped page to the server.
- */
-static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
{
- struct nfs_pageio_descriptor mypgio, *pgio;
- struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host;
- unsigned offset;
- int err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
- if (wbc->for_writepages)
- pgio = wbc->fs_private;
- else {
- nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
- pgio = &mypgio;
- }
-
nfs_pageio_cond_complete(pgio, page->index);
+ return nfs_page_async_flush(pgio, page);
+}
- err = nfs_page_async_flush(pgio, page);
- if (err <= 0)
- goto out;
- err = 0;
- offset = nfs_page_length(page);
- if (!offset)
- goto out;
-
- nfs_pageio_cond_complete(pgio, page->index);
+/*
+ * Write an mmapped page to the server.
+ */
+static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+{
+ struct nfs_pageio_descriptor pgio;
+ int err;
- ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
- if (ctx == NULL) {
- err = -EBADF;
- goto out;
- }
- err = nfs_writepage_setup(ctx, page, 0, offset);
- put_nfs_open_context(ctx);
- if (err != 0)
- goto out;
- err = nfs_page_async_flush(pgio, page);
- if (err > 0)
- err = 0;
-out:
- if (!wbc->for_writepages)
- nfs_pageio_complete(pgio);
- return err;
+ nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc));
+ err = nfs_do_writepage(page, wbc, &pgio);
+ nfs_pageio_complete(&pgio);
+ if (err < 0)
+ return err;
+ if (pgio.pg_error < 0)
+ return pgio.pg_error;
+ return 0;
}
int nfs_writepage(struct page *page, struct writeback_control *wbc)
{
- int err;
+ int ret;
+
+ ret = nfs_writepage_locked(page, wbc);
+ unlock_page(page);
+ return ret;
+}
+
+static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
+{
+ int ret;
- err = nfs_writepage_locked(page, wbc);
+ ret = nfs_do_writepage(page, wbc, data);
unlock_page(page);
- return err;
+ return ret;
}
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
@@ -365,12 +355,11 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
- wbc->fs_private = &pgio;
- err = generic_writepages(mapping, wbc);
+ err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
nfs_pageio_complete(&pgio);
- if (err)
+ if (err < 0)
return err;
- if (pgio.pg_error)
+ if (pgio.pg_error < 0)
return pgio.pg_error;
return 0;
}
@@ -389,14 +378,11 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
return error;
if (!nfsi->npages) {
igrab(inode);
- nfs_begin_data_update(inode);
if (nfs_have_delegation(inode, FMODE_WRITE))
nfsi->change_attr++;
}
SetPagePrivate(req->wb_page);
set_page_private(req->wb_page, (unsigned long)req);
- if (PageDirty(req->wb_page))
- set_bit(PG_NEED_FLUSH, &req->wb_flags);
nfsi->npages++;
kref_get(&req->wb_kref);
return 0;
@@ -416,12 +402,9 @@ static void nfs_inode_remove_request(struct nfs_page *req)
set_page_private(req->wb_page, 0);
ClearPagePrivate(req->wb_page);
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
- if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags))
- __set_page_dirty_nobuffers(req->wb_page);
nfsi->npages--;
if (!nfsi->npages) {
spin_unlock(&inode->i_lock);
- nfs_end_data_update(inode);
iput(inode);
} else
spin_unlock(&inode->i_lock);
@@ -682,7 +665,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
int nfs_flush_incompatible(struct file *file, struct page *page)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct nfs_page *req;
int do_flush, status;
/*
@@ -716,7 +699,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
int nfs_updatepage(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = page->mapping->host;
int status = 0;
@@ -967,7 +950,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
if (task->tk_status < 0) {
nfs_set_pageerror(page);
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
dprintk(", error = %d\n", task->tk_status);
goto out;
}
@@ -1030,7 +1013,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
if (task->tk_status < 0) {
nfs_set_pageerror(page);
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
dprintk(", error = %d\n", task->tk_status);
goto remove_request;
}
@@ -1244,7 +1227,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
req->wb_bytes,
(long long)req_offset(req));
if (task->tk_status < 0) {
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status);
goto next;
@@ -1347,53 +1330,52 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
return ret;
}
-/*
- * flush the inode to disk.
- */
-int nfs_wb_all(struct inode *inode)
+static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
{
- struct address_space *mapping = inode->i_mapping;
- struct writeback_control wbc = {
- .bdi = mapping->backing_dev_info,
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = LONG_MAX,
- .for_writepages = 1,
- .range_cyclic = 1,
- };
int ret;
- ret = nfs_writepages(mapping, &wbc);
+ ret = nfs_writepages(mapping, wbc);
if (ret < 0)
goto out;
- ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
- if (ret >= 0)
- return 0;
+ ret = nfs_sync_mapping_wait(mapping, wbc, how);
+ if (ret < 0)
+ goto out;
+ return 0;
out:
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
return ret;
}
-int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how)
+/* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */
+static int nfs_write_mapping(struct address_space *mapping, int how)
{
struct writeback_control wbc = {
.bdi = mapping->backing_dev_info,
- .sync_mode = WB_SYNC_ALL,
+ .sync_mode = WB_SYNC_NONE,
.nr_to_write = LONG_MAX,
- .range_start = range_start,
- .range_end = range_end,
.for_writepages = 1,
+ .range_cyclic = 1,
};
int ret;
- ret = nfs_writepages(mapping, &wbc);
+ ret = __nfs_write_mapping(mapping, &wbc, how);
if (ret < 0)
- goto out;
- ret = nfs_sync_mapping_wait(mapping, &wbc, how);
- if (ret >= 0)
- return 0;
-out:
- __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
- return ret;
+ return ret;
+ wbc.sync_mode = WB_SYNC_ALL;
+ return __nfs_write_mapping(mapping, &wbc, how);
+}
+
+/*
+ * flush the inode to disk.
+ */
+int nfs_wb_all(struct inode *inode)
+{
+ return nfs_write_mapping(inode->i_mapping, 0);
+}
+
+int nfs_wb_nocommit(struct inode *inode)
+{
+ return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT);
}
int nfs_wb_page_cancel(struct inode *inode, struct page *page)
@@ -1477,35 +1459,6 @@ int nfs_wb_page(struct inode *inode, struct page* page)
return nfs_wb_page_priority(inode, page, FLUSH_STABLE);
}
-int nfs_set_page_dirty(struct page *page)
-{
- struct address_space *mapping = page->mapping;
- struct inode *inode;
- struct nfs_page *req;
- int ret;
-
- if (!mapping)
- goto out_raced;
- inode = mapping->host;
- if (!inode)
- goto out_raced;
- spin_lock(&inode->i_lock);
- req = nfs_page_find_request_locked(page);
- if (req != NULL) {
- /* Mark any existing write requests for flushing */
- ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags);
- spin_unlock(&inode->i_lock);
- nfs_release_request(req);
- return ret;
- }
- ret = __set_page_dirty_nobuffers(page);
- spin_unlock(&inode->i_lock);
- return ret;
-out_raced:
- return !TestSetPageDirty(page);
-}
-
-
int __init nfs_init_writepagecache(void)
{
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 10f6e7dcf63..2d116d2298f 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -174,9 +174,6 @@ static __be32 *
encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
- struct dentry *dentry = fhp->fh_dentry;
- struct timespec time;
-
*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
*p++ = htonl((u32) stat->mode);
*p++ = htonl((u32) stat->nlink);
@@ -191,10 +188,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
*p++ = htonl((u32) MAJOR(stat->rdev));
*p++ = htonl((u32) MINOR(stat->rdev));
p = encode_fsid(p, fhp);
- p = xdr_encode_hyper(p, (u64) stat->ino);
+ p = xdr_encode_hyper(p, stat->ino);
p = encode_time3(p, &stat->atime);
- lease_get_mtime(dentry->d_inode, &time);
- p = encode_time3(p, &time);
+ p = encode_time3(p, &stat->mtime);
p = encode_time3(p, &stat->ctime);
return p;
@@ -203,31 +199,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
static __be32 *
encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_dentry->d_inode;
-
/* Attributes to follow */
*p++ = xdr_one;
-
- *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
- *p++ = htonl((u32) fhp->fh_post_mode);
- *p++ = htonl((u32) fhp->fh_post_nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
- if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
- p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
- } else {
- p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
- }
- p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
- *p++ = fhp->fh_post_rdev[0];
- *p++ = fhp->fh_post_rdev[1];
- p = encode_fsid(p, fhp);
- p = xdr_encode_hyper(p, (u64) inode->i_ino);
- p = encode_time3(p, &fhp->fh_post_atime);
- p = encode_time3(p, &fhp->fh_post_mtime);
- p = encode_time3(p, &fhp->fh_post_ctime);
-
- return p;
+ return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
}
/*
@@ -246,6 +220,7 @@ encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
if (!err) {
*p++ = xdr_one; /* attributes follow */
+ lease_get_mtime(dentry->d_inode, &stat.mtime);
return encode_fattr3(rqstp, p, fhp, &stat);
}
}
@@ -284,6 +259,23 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
return encode_post_op_attr(rqstp, p, fhp);
}
+/*
+ * Fill in the post_op attr for the wcc data
+ */
+void fill_post_wcc(struct svc_fh *fhp)
+{
+ int err;
+
+ if (fhp->fh_post_saved)
+ printk("nfsd: inode locked twice during operation.\n");
+
+ err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry,
+ &fhp->fh_post_attr);
+ if (err)
+ fhp->fh_post_saved = 0;
+ else
+ fhp->fh_post_saved = 1;
+}
/*
* XDR decode functions
@@ -643,8 +635,11 @@ int
nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_attrstat *resp)
{
- if (resp->status == 0)
+ if (resp->status == 0) {
+ lease_get_mtime(resp->fh.fh_dentry->d_inode,
+ &resp->stat.mtime);
p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
+ }
return xdr_ressize_check(rqstp, p);
}
@@ -802,7 +797,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
static __be32 *
encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
- int namlen, ino_t ino)
+ int namlen, u64 ino)
{
*p++ = xdr_one; /* mark entry present */
p = xdr_encode_hyper(p, ino); /* file id */
@@ -873,7 +868,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
static int
encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type, int plus)
+ loff_t offset, u64 ino, unsigned int d_type, int plus)
{
struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
common);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 31d6633c7fe..9d536a8cb37 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -39,6 +39,7 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/clnt.h>
@@ -343,26 +344,28 @@ static struct rpc_version * nfs_cb_version[] = {
&nfs_cb_version4,
};
-/*
- * Use the SETCLIENTID credential
- */
-static struct rpc_cred *
-nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
+/* Reference counting, callback cleanup, etc., all look racy as heck.
+ * And why is cb_set an atomic? */
+
+static int do_probe_callback(void *data)
{
- struct auth_cred acred;
- struct rpc_clnt *clnt = clp->cl_callback.cb_client;
- struct rpc_cred *ret;
-
- get_group_info(clp->cl_cred.cr_group_info);
- acred.uid = clp->cl_cred.cr_uid;
- acred.gid = clp->cl_cred.cr_gid;
- acred.group_info = clp->cl_cred.cr_group_info;
-
- dprintk("NFSD: looking up %s cred\n",
- clnt->cl_auth->au_ops->au_name);
- ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags);
- put_group_info(clp->cl_cred.cr_group_info);
- return ret;
+ struct nfs4_client *clp = data;
+ struct nfs4_callback *cb = &clp->cl_callback;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+ .rpc_argp = clp,
+ };
+ int status;
+
+ status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
+
+ if (status) {
+ rpc_shutdown_client(cb->cb_client);
+ cb->cb_client = NULL;
+ } else
+ atomic_set(&cb->cb_set, 1);
+ put_nfs4_client(clp);
+ return 0;
}
/*
@@ -390,11 +393,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
.flags = (RPC_CLNT_CREATE_NOPING),
};
- struct rpc_message msg = {
- .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
- .rpc_argp = clp,
- };
- int status;
+ struct task_struct *t;
if (atomic_read(&cb->cb_set))
return;
@@ -426,16 +425,11 @@ nfsd4_probe_callback(struct nfs4_client *clp)
/* the task holds a reference to the nfs4_client struct */
atomic_inc(&clp->cl_count);
- msg.rpc_cred = nfsd4_lookupcred(clp,0);
- if (IS_ERR(msg.rpc_cred))
- goto out_release_clp;
- status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
- put_rpccred(msg.rpc_cred);
+ t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
- if (status != 0) {
- dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
+ if (IS_ERR(t))
goto out_release_clp;
- }
+
return;
out_release_clp:
@@ -447,30 +441,6 @@ out_err:
(int)clp->cl_name.len, clp->cl_name.data);
}
-static void
-nfs4_cb_null(struct rpc_task *task, void *dummy)
-{
- struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
- struct nfs4_callback *cb = &clp->cl_callback;
- __be32 addr = htonl(cb->cb_addr);
-
- dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
-
- if (task->tk_status < 0) {
- dprintk("NFSD: callback establishment to client %.*s failed\n",
- (int)clp->cl_name.len, clp->cl_name.data);
- goto out;
- }
- atomic_set(&cb->cb_set, 1);
- dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr));
-out:
- put_nfs4_client(clp);
-}
-
-static const struct rpc_call_ops nfs4_cb_null_ops = {
- .rpc_call_done = nfs4_cb_null,
-};
-
/*
* called with dp->dl_count inc'ed.
* nfs4_lock_state() may or may not have been called.
@@ -491,10 +461,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
return;
- msg.rpc_cred = nfsd4_lookupcred(clp, 0);
- if (IS_ERR(msg.rpc_cred))
- goto out;
-
cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
cbr->cbr_dp = dp;
@@ -515,13 +481,12 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
}
out_put_cred:
- put_rpccred(msg.rpc_cred);
-out:
if (status == -EIO)
atomic_set(&clp->cl_callback.cb_set, 0);
/* Success or failure, now we're either waiting for lease expiration
* or deleg_return. */
dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+ put_nfs4_client(clp);
nfs4_put_delegation(dp);
return;
}
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 2ccffde81b8..4c0c683ce07 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -207,6 +207,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
{
struct ent ent, *res;
char *buf1, *bp;
+ int len;
int error = -EINVAL;
if (buf[buflen - 1] != '\n')
@@ -248,10 +249,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
goto out;
/* Name */
- error = qword_get(&buf, buf1, PAGE_SIZE);
- if (error == -EINVAL)
+ error = -EINVAL;
+ len = qword_get(&buf, buf1, PAGE_SIZE);
+ if (len < 0)
goto out;
- if (error == -ENOENT)
+ if (len == 0)
set_bit(CACHE_NEGATIVE, &ent.h.flags);
else {
if (error >= IDMAP_NAMESZ) {
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 29b7e63cb32..18ead1790bb 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -238,12 +238,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
break;
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
open->op_stateowner->so_confirmed = 1;
- printk("NFSD: unsupported OPEN claim type %d\n",
+ dprintk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_notsupp;
goto out;
default:
- printk("NFSD: Invalid OPEN claim type %d\n",
+ dprintk("NFSD: Invalid OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_inval;
goto out;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3f559700788..31673cd251c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name)
return clp;
}
+static void
+shutdown_callback_client(struct nfs4_client *clp)
+{
+ struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+
+ /* shutdown rpc client, ending any outstanding recall rpcs */
+ if (clnt) {
+ clp->cl_callback.cb_client = NULL;
+ rpc_shutdown_client(clnt);
+ }
+}
+
static inline void
free_client(struct nfs4_client *clp)
{
+ shutdown_callback_client(clp);
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
kfree(clp->cl_name.data);
@@ -375,18 +388,6 @@ put_nfs4_client(struct nfs4_client *clp)
}
static void
-shutdown_callback_client(struct nfs4_client *clp)
-{
- struct rpc_clnt *clnt = clp->cl_callback.cb_client;
-
- /* shutdown rpc client, ending any outstanding recall rpcs */
- if (clnt) {
- clp->cl_callback.cb_client = NULL;
- rpc_shutdown_client(clnt);
- }
-}
-
-static void
expire_client(struct nfs4_client *clp)
{
struct nfs4_stateowner *sop;
@@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp)
dprintk("NFSD: expire_client cl_count %d\n",
atomic_read(&clp->cl_count));
- shutdown_callback_client(clp);
-
INIT_LIST_HEAD(&reaplist);
spin_lock(&recall_lock);
while (!list_empty(&clp->cl_delegations)) {
@@ -462,26 +461,28 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
}
static inline int
-same_name(const char *n1, const char *n2) {
+same_name(const char *n1, const char *n2)
+{
return 0 == memcmp(n1, n2, HEXDIR_LEN);
}
static int
-cmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) {
- return(!memcmp(v1->data,v2->data,sizeof(v1->data)));
+same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
+{
+ return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
}
static int
-cmp_clid(clientid_t * cl1, clientid_t * cl2) {
- return((cl1->cl_boot == cl2->cl_boot) &&
- (cl1->cl_id == cl2->cl_id));
+same_clid(clientid_t *cl1, clientid_t *cl2)
+{
+ return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
}
/* XXX what about NGROUP */
static int
-cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){
- return(cr1->cr_uid == cr2->cr_uid);
-
+same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
+{
+ return cr1->cr_uid == cr2->cr_uid;
}
static void
@@ -507,7 +508,7 @@ check_name(struct xdr_netobj name) {
if (name.len == 0)
return 0;
if (name.len > NFS4_OPAQUE_LIMIT) {
- printk("NFSD: check_name: name too long(%d)!\n", name.len);
+ dprintk("NFSD: check_name: name too long(%d)!\n", name.len);
return 0;
}
return 1;
@@ -546,7 +547,7 @@ find_confirmed_client(clientid_t *clid)
unsigned int idhashval = clientid_hashval(clid->cl_id);
list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
- if (cmp_clid(&clp->cl_clientid, clid))
+ if (same_clid(&clp->cl_clientid, clid))
return clp;
}
return NULL;
@@ -559,7 +560,7 @@ find_unconfirmed_client(clientid_t *clid)
unsigned int idhashval = clientid_hashval(clid->cl_id);
list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
- if (cmp_clid(&clp->cl_clientid, clid))
+ if (same_clid(&clp->cl_clientid, clid))
return clp;
}
return NULL;
@@ -753,7 +754,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* or different ip_address
*/
status = nfserr_clid_inuse;
- if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred)
+ if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
|| conf->cl_addr != sin->sin_addr.s_addr) {
dprintk("NFSD: setclientid: string in use by client"
"at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));
@@ -772,14 +773,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
new = create_client(clname, dname);
if (new == NULL)
goto out;
- copy_verf(new, &clverifier);
- new->cl_addr = sin->sin_addr.s_addr;
- copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
- gen_confirm(new);
- gen_callback(new, setclid);
- add_to_unconfirmed(new, strhashval);
- } else if (cmp_verf(&conf->cl_verifier, &clverifier)) {
+ } else if (same_verf(&conf->cl_verifier, &clverifier)) {
/*
* CASE 1:
* cl_name match, confirmed, principal match
@@ -804,13 +799,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
new = create_client(clname, dname);
if (new == NULL)
goto out;
- copy_verf(new,&conf->cl_verifier);
- new->cl_addr = sin->sin_addr.s_addr;
- copy_cred(&new->cl_cred,&rqstp->rq_cred);
copy_clid(new, conf);
- gen_confirm(new);
- gen_callback(new, setclid);
- add_to_unconfirmed(new,strhashval);
} else if (!unconf) {
/*
* CASE 2:
@@ -823,14 +812,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
new = create_client(clname, dname);
if (new == NULL)
goto out;
- copy_verf(new,&clverifier);
- new->cl_addr = sin->sin_addr.s_addr;
- copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
- gen_confirm(new);
- gen_callback(new, setclid);
- add_to_unconfirmed(new, strhashval);
- } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
+ } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
/*
* CASE3:
* confirmed found (name, principal match)
@@ -850,19 +833,19 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
new = create_client(clname, dname);
if (new == NULL)
goto out;
- copy_verf(new,&clverifier);
- new->cl_addr = sin->sin_addr.s_addr;
- copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
- gen_confirm(new);
- gen_callback(new, setclid);
- add_to_unconfirmed(new, strhashval);
} else {
/* No cases hit !!! */
status = nfserr_inval;
goto out;
}
+ copy_verf(new, &clverifier);
+ new->cl_addr = sin->sin_addr.s_addr;
+ copy_cred(&new->cl_cred, &rqstp->rq_cred);
+ gen_confirm(new);
+ gen_callback(new, setclid);
+ add_to_unconfirmed(new, strhashval);
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
@@ -910,16 +893,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
goto out;
if ((conf && unconf) &&
- (cmp_verf(&unconf->cl_confirm, &confirm)) &&
- (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
+ (same_verf(&unconf->cl_confirm, &confirm)) &&
+ (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
(same_name(conf->cl_recdir,unconf->cl_recdir)) &&
- (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+ (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
/* CASE 1:
* unconf record that matches input clientid and input confirm.
* conf record that matches input clientid.
* conf and unconf records match names, verifiers
*/
- if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred))
+ if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
/* XXX: We just turn off callbacks until we can handle
@@ -933,7 +916,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
}
} else if ((conf && !unconf) ||
((conf && unconf) &&
- (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
+ (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
!same_name(conf->cl_recdir, unconf->cl_recdir)))) {
/* CASE 2:
* conf record that matches input clientid.
@@ -941,18 +924,18 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
* unconf->cl_name or unconf->cl_verifier don't match the
* conf record.
*/
- if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
+ if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
status = nfserr_clid_inuse;
else
status = nfs_ok;
} else if (!conf && unconf
- && cmp_verf(&unconf->cl_confirm, &confirm)) {
+ && same_verf(&unconf->cl_confirm, &confirm)) {
/* CASE 3:
* conf record not found.
* unconf record found.
* unconf->cl_confirm matches input confirm
*/
- if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
+ if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
status = nfserr_clid_inuse;
} else {
unsigned int hash =
@@ -967,8 +950,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
conf = unconf;
status = nfs_ok;
}
- } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
- && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm,
+ } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
+ && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
&confirm)))) {
/* CASE 4:
* conf record not found, or if conf, conf->cl_confirm does not
@@ -1019,7 +1002,7 @@ nfsd4_free_slab(struct kmem_cache **slab)
*slab = NULL;
}
-static void
+void
nfsd4_free_slabs(void)
{
nfsd4_free_slab(&stateowner_slab);
@@ -1207,10 +1190,12 @@ move_to_close_lru(struct nfs4_stateowner *sop)
}
static int
-cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
- return ((sop->so_owner.len == owner->len) &&
- !memcmp(sop->so_owner.data, owner->data, owner->len) &&
- (sop->so_client->cl_clientid.cl_id == clid->cl_id));
+same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
+ clientid_t *clid)
+{
+ return (sop->so_owner.len == owner->len) &&
+ 0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
+ (sop->so_client->cl_clientid.cl_id == clid->cl_id);
}
static struct nfs4_stateowner *
@@ -1219,7 +1204,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
struct nfs4_stateowner *so = NULL;
list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
- if (cmp_owner_str(so, &open->op_owner, &open->op_clientid))
+ if (same_owner_str(so, &open->op_owner, &open->op_clientid))
return so;
}
return NULL;
@@ -1360,6 +1345,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
* lock) we know the server hasn't removed the lease yet, we know
* it's safe to take a reference: */
atomic_inc(&dp->dl_count);
+ atomic_inc(&dp->dl_client->cl_count);
spin_lock(&recall_lock);
list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
@@ -1368,8 +1354,12 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
/* only place dl_time is set. protected by lock_kernel*/
dp->dl_time = get_seconds();
- /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */
- fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ;
+ /*
+ * We don't want the locks code to timeout the lease for us;
+ * we'll remove it ourself if the delegation isn't returned
+ * in time.
+ */
+ fl->fl_break_time = 0;
t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");
if (IS_ERR(t)) {
@@ -1378,6 +1368,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
printk(KERN_INFO "NFSD: Callback thread failed for "
"for client (clientid %08x/%08x)\n",
clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+ put_nfs4_client(dp->dl_client);
nfs4_put_delegation(dp);
}
}
@@ -1738,7 +1729,7 @@ out:
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
&& flag == NFS4_OPEN_DELEGATE_NONE
&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
- printk("NFSD: WARNING: refusing delegation reclaim\n");
+ dprintk("NFSD: WARNING: refusing delegation reclaim\n");
open->op_delegate_type = flag;
}
@@ -2044,7 +2035,7 @@ static inline int
io_during_grace_disallowed(struct inode *inode, int flags)
{
return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
- && MANDATORY_LOCK(inode);
+ && mandatory_lock(inode);
}
/*
@@ -2147,7 +2138,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
*sopp = NULL;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
- printk("NFSD: preprocess_seqid_op: magic stateid!\n");
+ dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
return nfserr_bad_stateid;
}
@@ -2181,25 +2172,24 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
lkflg = setlkflg(lock->lk_type);
if (lock->lk_is_new) {
- if (!sop->so_is_open_owner)
- return nfserr_bad_stateid;
- if (!cmp_clid(&clp->cl_clientid, lockclid))
+ if (!sop->so_is_open_owner)
+ return nfserr_bad_stateid;
+ if (!same_clid(&clp->cl_clientid, lockclid))
return nfserr_bad_stateid;
- /* stp is the open stateid */
- status = nfs4_check_openmode(stp, lkflg);
- if (status)
- return status;
- } else {
- /* stp is the lock stateid */
- status = nfs4_check_openmode(stp->st_openstp, lkflg);
- if (status)
- return status;
+ /* stp is the open stateid */
+ status = nfs4_check_openmode(stp, lkflg);
+ if (status)
+ return status;
+ } else {
+ /* stp is the lock stateid */
+ status = nfs4_check_openmode(stp->st_openstp, lkflg);
+ if (status)
+ return status;
}
-
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
- printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
+ dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
return nfserr_bad_stateid;
}
@@ -2215,22 +2205,22 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
goto check_replay;
if (sop->so_confirmed && flags & CONFIRM) {
- printk("NFSD: preprocess_seqid_op: expected"
+ dprintk("NFSD: preprocess_seqid_op: expected"
" unconfirmed stateowner!\n");
return nfserr_bad_stateid;
}
if (!sop->so_confirmed && !(flags & CONFIRM)) {
- printk("NFSD: preprocess_seqid_op: stateowner not"
+ dprintk("NFSD: preprocess_seqid_op: stateowner not"
" confirmed yet!\n");
return nfserr_bad_stateid;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
- printk("NFSD: preprocess_seqid_op: future stateid?!\n");
+ dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
return nfserr_bad_stateid;
}
if (stateid->si_generation < stp->st_stateid.si_generation) {
- printk("NFSD: preprocess_seqid_op: old stateid!\n");
+ dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
return nfserr_old_stateid;
}
renew_client(sop->so_client);
@@ -2242,7 +2232,7 @@ check_replay:
/* indicate replay to calling function */
return nfserr_replay_me;
}
- printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+ dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
sop->so_seqid, seqid);
*sopp = NULL;
return nfserr_bad_seqid;
@@ -2561,7 +2551,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
struct nfs4_stateowner *op;
list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
- if (cmp_owner_str(op, owner, clid))
+ if (same_owner_str(op, owner, clid))
return op;
}
return NULL;
@@ -2855,7 +2845,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
file_lock.fl_type = F_WRLCK;
break;
default:
- printk("NFSD: nfs4_lockt: bad lock type!\n");
+ dprintk("NFSD: nfs4_lockt: bad lock type!\n");
status = nfserr_inval;
goto out;
}
@@ -3025,7 +3015,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
INIT_LIST_HEAD(&matches);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
- if (!cmp_owner_str(sop, owner, clid))
+ if (!same_owner_str(sop, owner, clid))
continue;
list_for_each_entry(stp, &sop->so_stateids,
st_perstateowner) {
@@ -3149,11 +3139,14 @@ nfs4_check_open_reclaim(clientid_t *clid)
/* initialization to perform at module load time: */
-void
+int
nfs4_state_init(void)
{
- int i;
+ int i, status;
+ status = nfsd4_init_slabs();
+ if (status)
+ return status;
for (i = 0; i < CLIENT_HASH_SIZE; i++) {
INIT_LIST_HEAD(&conf_id_hashtbl[i]);
INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -3182,6 +3175,7 @@ nfs4_state_init(void)
for (i = 0; i < CLIENT_HASH_SIZE; i++)
INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
reclaim_str_hashtbl_size = 0;
+ return 0;
}
static void
@@ -3242,20 +3236,15 @@ __nfs4_state_start(void)
set_max_delegations();
}
-int
+void
nfs4_state_start(void)
{
- int status;
-
if (nfs4_init)
- return 0;
- status = nfsd4_init_slabs();
- if (status)
- return status;
+ return;
nfsd4_load_reboot_recovery_data();
__nfs4_state_start();
nfs4_init = 1;
- return 0;
+ return;
}
int
@@ -3313,7 +3302,6 @@ nfs4_state_shutdown(void)
nfs4_lock_state();
nfs4_release_reclaim();
__nfs4_state_shutdown();
- nfsd4_free_slabs();
nfs4_unlock_state();
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 8ef0964179b..57333944af7 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -102,7 +102,8 @@ check_filename(char *str, int len, __be32 err)
out: \
return status; \
xdr_error: \
- printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+ dprintk("NFSD: xdr error (%s:%d)\n", \
+ __FILE__, __LINE__); \
status = nfserr_bad_xdr; \
goto out
@@ -124,7 +125,8 @@ xdr_error: \
if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
savemem(argp, p, nbytes) : \
(char *)p)) { \
- printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+ dprintk("NFSD: xdr error (%s:%d)\n", \
+ __FILE__, __LINE__); \
goto xdr_error; \
} \
p += XDR_QUADLEN(nbytes); \
@@ -140,7 +142,8 @@ xdr_error: \
p = argp->p; \
argp->p += XDR_QUADLEN(nbytes); \
} else if (!(p = read_buf(argp, nbytes))) { \
- printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+ dprintk("NFSD: xdr error (%s:%d)\n", \
+ __FILE__, __LINE__); \
goto xdr_error; \
} \
} while (0)
@@ -948,7 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
*/
avail = (char*)argp->end - (char*)argp->p;
if (avail + argp->pagelen < write->wr_buflen) {
- printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
+ dprintk("NFSD: xdr error (%s:%d)\n",
+ __FILE__, __LINE__);
goto xdr_error;
}
argp->rqstp->rq_vec[0].iov_base = p;
@@ -1019,7 +1023,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
if (!argp->ops) {
argp->ops = argp->iops;
- printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n");
+ dprintk("nfsd: couldn't allocate room for COMPOUND\n");
goto xdr_error;
}
}
@@ -1326,7 +1330,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
path = exp->ex_path;
if (strncmp(path, rootpath, strlen(rootpath))) {
- printk("nfsd: fs_locations failed;"
+ dprintk("nfsd: fs_locations failed;"
"%s is not contained in %s\n", path, rootpath);
*stat = nfserr_notsupp;
return NULL;
@@ -1475,7 +1479,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
err = vfs_getattr(exp->ex_mnt, dentry, &stat);
if (err)
goto out_nfserr;
- if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
+ if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
+ FATTR4_WORD0_MAXNAME)) ||
(bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
FATTR4_WORD1_SPACE_TOTAL))) {
err = vfs_statfs(dentry, &statfs);
@@ -1679,7 +1684,7 @@ out_acl:
if (bmval0 & FATTR4_WORD0_FILEID) {
if ((buflen -= 8) < 0)
goto out_resource;
- WRITE64((u64) stat.ino);
+ WRITE64(stat.ino);
}
if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
if ((buflen -= 8) < 0)
@@ -1721,7 +1726,7 @@ out_acl:
if (bmval0 & FATTR4_WORD0_MAXNAME) {
if ((buflen -= 4) < 0)
goto out_resource;
- WRITE32(~(u32) 0);
+ WRITE32(statfs.f_namelen);
}
if (bmval0 & FATTR4_WORD0_MAXREAD) {
if ((buflen -= 8) < 0)
@@ -1821,16 +1826,15 @@ out_acl:
WRITE32(stat.mtime.tv_nsec);
}
if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
- struct dentry *mnt_pnt, *mnt_root;
-
if ((buflen -= 8) < 0)
goto out_resource;
- mnt_root = exp->ex_mnt->mnt_root;
- if (mnt_root->d_inode == dentry->d_inode) {
- mnt_pnt = exp->ex_mnt->mnt_mountpoint;
- WRITE64((u64) mnt_pnt->d_inode->i_ino);
- } else
- WRITE64((u64) stat.ino);
+ if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
+ err = vfs_getattr(exp->ex_mnt->mnt_parent,
+ exp->ex_mnt->mnt_mountpoint, &stat);
+ if (err)
+ goto out_nfserr;
+ }
+ WRITE64(stat.ino);
}
*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
*countp = p - buffer;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index baac89d917c..77dc9893b7b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -298,7 +298,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
* qword quoting is used, so filehandle will be \x....
*/
char *dname, *path;
- int maxsize;
+ int uninitialized_var(maxsize);
char *mesg = buf;
int len;
struct auth_domain *dom;
@@ -679,11 +679,13 @@ static int __init init_nfsd(void)
int retval;
printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
+ retval = nfs4_state_init(); /* nfs4 locking state */
+ if (retval)
+ return retval;
nfsd_stat_init(); /* Statistics */
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
- nfs4_state_init(); /* NFSv4 locking state */
nfsd_idmap_init(); /* Name to ID mapping */
if (proc_mkdir("fs/nfs", NULL)) {
struct proc_dir_entry *entry;
@@ -712,6 +714,7 @@ static void __exit exit_nfsd(void)
nfsd_stat_shutdown();
nfsd_lockd_shutdown();
nfsd_idmap_shutdown();
+ nfsd4_free_slabs();
unregister_filesystem(&nfsd_fs_type);
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index a8c89ae4c74..1190aeaa92b 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -349,9 +349,7 @@ nfsd_svc(unsigned short port, int nrservs)
error = nfsd_racache_init(2*nrservs);
if (error<0)
goto out;
- error = nfs4_state_start();
- if (error<0)
- goto out;
+ nfs4_state_start();
nfsd_reset_versions();
@@ -546,10 +544,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
- if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2)
- nfserr = nfserr_dropit;
if (nfserr == nfserr_dropit) {
- dprintk("nfsd: Dropping request due to malloc failure!\n");
+ dprintk("nfsd: Dropping request; may be revisited later\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
return 0;
}
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index cb3e7fadb77..986f9b32083 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -523,6 +523,10 @@ nfssvc_encode_entry(void *ccdv, const char *name,
cd->common.err = nfserr_toosmall;
return -EINVAL;
}
+ if (ino > ~((u32) 0)) {
+ cd->common.err = nfserr_fbig;
+ return -EINVAL;
+ }
*p++ = xdr_one; /* mark entry present */
*p++ = htonl((u32) ino); /* file id */
p = xdr_encode_array(p, name, namlen);/* name length & name */
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 7867151ebb8..2a8d665b134 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -61,12 +61,6 @@
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
-/* We must ignore files (but only files) which might have mandatory
- * locks on them because there is no way to know if the accesser has
- * the lock.
- */
-#define IS_ISMNDLK(i) (S_ISREG((i)->i_mode) && MANDATORY_LOCK(i))
-
/*
* This is a cache of readahead params that help us choose the proper
* readahead strategy. Initially, we set all readahead parameters to 0
@@ -295,7 +289,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
if (!iap->ia_valid)
goto out;
- /* NFSv2 does not differentiate between "set-[ac]time-to-now"
+ /*
+ * NFSv2 does not differentiate between "set-[ac]time-to-now"
* which only requires access, and "set-[ac]time-to-X" which
* requires ownership.
* So if it looks like it might be "set both to the same time which
@@ -308,25 +303,33 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
*/
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
#define MAX_TOUCH_TIME_ERROR (30*60)
- if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
- && iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec
- ) {
- /* Looks probable. Now just make sure time is in the right ballpark.
- * Solaris, at least, doesn't seem to care what the time request is.
- * We require it be within 30 minutes of now.
- */
- time_t delta = iap->ia_atime.tv_sec - get_seconds();
- if (delta<0) delta = -delta;
- if (delta < MAX_TOUCH_TIME_ERROR &&
- inode_change_ok(inode, iap) != 0) {
- /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
- * this will cause notify_change to set these times to "now"
+ if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
+ iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
+ /*
+ * Looks probable.
+ *
+ * Now just make sure time is in the right ballpark.
+ * Solaris, at least, doesn't seem to care what the time
+ * request is. We require it be within 30 minutes of now.
*/
- iap->ia_valid &= ~BOTH_TIME_SET;
- }
+ time_t delta = iap->ia_atime.tv_sec - get_seconds();
+ if (delta < 0)
+ delta = -delta;
+ if (delta < MAX_TOUCH_TIME_ERROR &&
+ inode_change_ok(inode, iap) != 0) {
+ /*
+ * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
+ * This will cause notify_change to set these times
+ * to "now"
+ */
+ iap->ia_valid &= ~BOTH_TIME_SET;
+ }
}
- /* The size case is special. It changes the file as well as the attributes. */
+ /*
+ * The size case is special.
+ * It changes the file as well as the attributes.
+ */
if (iap->ia_valid & ATTR_SIZE) {
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
@@ -680,7 +683,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = nfserr_perm;
if (IS_APPEND(inode) && (access & MAY_WRITE))
goto out;
- if (IS_ISMNDLK(inode))
+ /*
+ * We must ignore files (but only files) which might have mandatory
+ * locks on them because there is no way to know if the accesser has
+ * the lock.
+ */
+ if (S_ISREG((inode)->i_mode) && mandatory_lock(inode))
goto out;
if (!inode->i_fop)
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index af4ef808fa9..345798ebd36 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -17,6 +17,18 @@ ToDo/Notes:
happen is unclear however so it is worth waiting until someone hits
the problem.
+2.1.29 - Fix a deadlock at mount time.
+
+ - During mount the VFS holds s_umount lock on the superblock. So when
+ we try to empty the journal $LogFile contents by calling
+ ntfs_attr_set() when the machine does not have much memory and the
+ journal is large ntfs_attr_set() results in the VM trying to balance
+ dirty pages which in turn tries to that the s_umount lock and thus we
+ get a deadlock. The solution is to not use ntfs_attr_set() and
+ instead do the zeroing by hand at the block level rather than page
+ cache level.
+ - Fix sparse warnings.
+
2.1.28 - Fix a deadlock.
- Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode(). Thanks to Sergey
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index 82550838556..58b6be99254 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
unistr.o upcase.o
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.29\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 6e5c2534f4b..cfdc7900d27 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -2,7 +2,7 @@
* aops.c - NTFS kernel address space operations and page cache handling.
* Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -396,7 +396,7 @@ static int ntfs_readpage(struct file *file, struct page *page)
loff_t i_size;
struct inode *vi;
ntfs_inode *ni, *base_ni;
- u8 *kaddr;
+ u8 *addr;
ntfs_attr_search_ctx *ctx;
MFT_RECORD *mrec;
unsigned long flags;
@@ -491,15 +491,15 @@ retry_readpage:
/* Race with shrinking truncate. */
attr_len = i_size;
}
- kaddr = kmap_atomic(page, KM_USER0);
+ addr = kmap_atomic(page, KM_USER0);
/* Copy the data to the page. */
- memcpy(kaddr, (u8*)ctx->attr +
+ memcpy(addr, (u8*)ctx->attr +
le16_to_cpu(ctx->attr->data.resident.value_offset),
attr_len);
/* Zero the remainder of the page. */
- memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+ memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ kunmap_atomic(addr, KM_USER0);
put_unm_err_out:
ntfs_attr_put_search_ctx(ctx);
unm_err_out:
@@ -1344,7 +1344,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
loff_t i_size;
struct inode *vi = page->mapping->host;
ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
- char *kaddr;
+ char *addr;
ntfs_attr_search_ctx *ctx = NULL;
MFT_RECORD *m = NULL;
u32 attr_len;
@@ -1484,14 +1484,14 @@ retry_writepage:
/* Shrinking cannot fail. */
BUG_ON(err);
}
- kaddr = kmap_atomic(page, KM_USER0);
+ addr = kmap_atomic(page, KM_USER0);
/* Copy the data from the page to the mft record. */
memcpy((u8*)ctx->attr +
le16_to_cpu(ctx->attr->data.resident.value_offset),
- kaddr, attr_len);
+ addr, attr_len);
/* Zero out of bounds area in the page cache page. */
- memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
- kunmap_atomic(kaddr, KM_USER0);
+ memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+ kunmap_atomic(addr, KM_USER0);
flush_dcache_page(page);
flush_dcache_mft_record_page(ctx->ntfs_ino);
/* We are done with the page. */
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 1c08fefe487..92dabdcf2b8 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -1,7 +1,7 @@
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -2500,7 +2500,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
struct page *page;
u8 *kaddr;
pgoff_t idx, end;
- unsigned int start_ofs, end_ofs, size;
+ unsigned start_ofs, end_ofs, size;
ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
(long long)ofs, (long long)cnt, val);
@@ -2548,6 +2548,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
kunmap_atomic(kaddr, KM_USER0);
set_page_dirty(page);
page_cache_release(page);
+ balance_dirty_pages_ratelimited(mapping);
+ cond_resched();
if (idx == end)
goto done;
idx++;
@@ -2604,6 +2606,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
kunmap_atomic(kaddr, KM_USER0);
set_page_dirty(page);
page_cache_release(page);
+ balance_dirty_pages_ratelimited(mapping);
+ cond_resched();
}
done:
ntfs_debug("Done.");
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index ffcc504a166..c814204d4ea 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -1,7 +1,7 @@
/*
* file.c - NTFS kernel file operations. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@@ -26,7 +26,6 @@
#include <linux/swap.h>
#include <linux/uio.h>
#include <linux/writeback.h>
-#include <linux/sched.h>
#include <asm/page.h>
#include <asm/uaccess.h>
@@ -362,7 +361,7 @@ static inline void ntfs_fault_in_pages_readable(const char __user *uaddr,
volatile char c;
/* Set @end to the first byte outside the last page we care about. */
- end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes);
+ end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes);
while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end))
;
@@ -532,7 +531,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
blocksize_bits = vol->sb->s_blocksize_bits;
u = 0;
do {
- struct page *page = pages[u];
+ page = pages[u];
+ BUG_ON(!page);
/*
* create_empty_buffers() will create uptodate/dirty buffers if
* the page is uptodate/dirty.
@@ -1291,7 +1291,7 @@ static inline size_t ntfs_copy_from_user(struct page **pages,
size_t bytes)
{
struct page **last_page = pages + nr_pages;
- char *kaddr;
+ char *addr;
size_t total = 0;
unsigned len;
int left;
@@ -1300,13 +1300,13 @@ static inline size_t ntfs_copy_from_user(struct page **pages,
len = PAGE_CACHE_SIZE - ofs;
if (len > bytes)
len = bytes;
- kaddr = kmap_atomic(*pages, KM_USER0);
- left = __copy_from_user_inatomic(kaddr + ofs, buf, len);
- kunmap_atomic(kaddr, KM_USER0);
+ addr = kmap_atomic(*pages, KM_USER0);
+ left = __copy_from_user_inatomic(addr + ofs, buf, len);
+ kunmap_atomic(addr, KM_USER0);
if (unlikely(left)) {
/* Do it the slow way. */
- kaddr = kmap(*pages);
- left = __copy_from_user(kaddr + ofs, buf, len);
+ addr = kmap(*pages);
+ left = __copy_from_user(addr + ofs, buf, len);
kunmap(*pages);
if (unlikely(left))
goto err_out;
@@ -1408,26 +1408,26 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages,
size_t *iov_ofs, size_t bytes)
{
struct page **last_page = pages + nr_pages;
- char *kaddr;
+ char *addr;
size_t copied, len, total = 0;
do {
len = PAGE_CACHE_SIZE - ofs;
if (len > bytes)
len = bytes;
- kaddr = kmap_atomic(*pages, KM_USER0);
- copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+ addr = kmap_atomic(*pages, KM_USER0);
+ copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
*iov, *iov_ofs, len);
- kunmap_atomic(kaddr, KM_USER0);
+ kunmap_atomic(addr, KM_USER0);
if (unlikely(copied != len)) {
/* Do it the slow way. */
- kaddr = kmap(*pages);
- copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+ addr = kmap(*pages);
+ copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
*iov, *iov_ofs, len);
/*
* Zero the rest of the target like __copy_from_user().
*/
- memset(kaddr + ofs + copied, 0, len - copied);
+ memset(addr + ofs + copied, 0, len - copied);
kunmap(*pages);
if (unlikely(copied != len))
goto err_out;
@@ -1735,8 +1735,6 @@ static int ntfs_commit_pages_after_write(struct page **pages,
read_unlock_irqrestore(&ni->size_lock, flags);
BUG_ON(initialized_size != i_size);
if (end > initialized_size) {
- unsigned long flags;
-
write_lock_irqsave(&ni->size_lock, flags);
ni->initialized_size = end;
i_size_write(vi, end);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index b532a730cec..e9da092e277 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -34,7 +34,6 @@
#include "dir.h"
#include "debug.h"
#include "inode.h"
-#include "attrib.h"
#include "lcnalloc.h"
#include "malloc.h"
#include "mft.h"
@@ -2500,8 +2499,6 @@ retry_truncate:
/* Resize the attribute record to best fit the new attribute size. */
if (new_size < vol->mft_record_size &&
!ntfs_resident_attr_value_resize(m, a, new_size)) {
- unsigned long flags;
-
/* The resize succeeded! */
flush_dcache_mft_record_page(ctx->ntfs_ino);
mark_mft_record_dirty(ctx->ntfs_ino);
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index acfed325f4e..d7932e95b1f 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -1,7 +1,7 @@
/*
* logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
*
- * Copyright (c) 2002-2005 Anton Altaparmakov
+ * Copyright (c) 2002-2007 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@@ -724,24 +724,139 @@ bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
*/
bool ntfs_empty_logfile(struct inode *log_vi)
{
- ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+ VCN vcn, end_vcn;
+ ntfs_inode *log_ni = NTFS_I(log_vi);
+ ntfs_volume *vol = log_ni->vol;
+ struct super_block *sb = vol->sb;
+ runlist_element *rl;
+ unsigned long flags;
+ unsigned block_size, block_size_bits;
+ int err;
+ bool should_wait = true;
ntfs_debug("Entering.");
- if (!NVolLogFileEmpty(vol)) {
- int err;
-
- err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi),
- 0xff);
- if (unlikely(err)) {
- ntfs_error(vol->sb, "Failed to fill $LogFile with "
- "0xff bytes (error code %i).", err);
- return false;
- }
- /* Set the flag so we do not have to do it again on remount. */
- NVolSetLogFileEmpty(vol);
+ if (NVolLogFileEmpty(vol)) {
+ ntfs_debug("Done.");
+ return true;
}
+ /*
+ * We cannot use ntfs_attr_set() because we may be still in the middle
+ * of a mount operation. Thus we do the emptying by hand by first
+ * zapping the page cache pages for the $LogFile/$DATA attribute and
+ * then emptying each of the buffers in each of the clusters specified
+ * by the runlist by hand.
+ */
+ block_size = sb->s_blocksize;
+ block_size_bits = sb->s_blocksize_bits;
+ vcn = 0;
+ read_lock_irqsave(&log_ni->size_lock, flags);
+ end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
+ vol->cluster_size_bits;
+ read_unlock_irqrestore(&log_ni->size_lock, flags);
+ truncate_inode_pages(log_vi->i_mapping, 0);
+ down_write(&log_ni->runlist.lock);
+ rl = log_ni->runlist.rl;
+ if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
+map_vcn:
+ err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
+ if (err) {
+ ntfs_error(sb, "Failed to map runlist fragment (error "
+ "%d).", -err);
+ goto err;
+ }
+ rl = log_ni->runlist.rl;
+ BUG_ON(!rl || vcn < rl->vcn || !rl->length);
+ }
+ /* Seek to the runlist element containing @vcn. */
+ while (rl->length && vcn >= rl[1].vcn)
+ rl++;
+ do {
+ LCN lcn;
+ sector_t block, end_block;
+ s64 len;
+
+ /*
+ * If this run is not mapped map it now and start again as the
+ * runlist will have been updated.
+ */
+ lcn = rl->lcn;
+ if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
+ vcn = rl->vcn;
+ goto map_vcn;
+ }
+ /* If this run is not valid abort with an error. */
+ if (unlikely(!rl->length || lcn < LCN_HOLE))
+ goto rl_err;
+ /* Skip holes. */
+ if (lcn == LCN_HOLE)
+ continue;
+ block = lcn << vol->cluster_size_bits >> block_size_bits;
+ len = rl->length;
+ if (rl[1].vcn > end_vcn)
+ len = end_vcn - rl->vcn;
+ end_block = (lcn + len) << vol->cluster_size_bits >>
+ block_size_bits;
+ /* Iterate over the blocks in the run and empty them. */
+ do {
+ struct buffer_head *bh;
+
+ /* Obtain the buffer, possibly not uptodate. */
+ bh = sb_getblk(sb, block);
+ BUG_ON(!bh);
+ /* Setup buffer i/o submission. */
+ lock_buffer(bh);
+ bh->b_end_io = end_buffer_write_sync;
+ get_bh(bh);
+ /* Set the entire contents of the buffer to 0xff. */
+ memset(bh->b_data, -1, block_size);
+ if (!buffer_uptodate(bh))
+ set_buffer_uptodate(bh);
+ if (buffer_dirty(bh))
+ clear_buffer_dirty(bh);
+ /*
+ * Submit the buffer and wait for i/o to complete but
+ * only for the first buffer so we do not miss really
+ * serious i/o errors. Once the first buffer has
+ * completed ignore errors afterwards as we can assume
+ * that if one buffer worked all of them will work.
+ */
+ submit_bh(WRITE, bh);
+ if (should_wait) {
+ should_wait = false;
+ wait_on_buffer(bh);
+ if (unlikely(!buffer_uptodate(bh)))
+ goto io_err;
+ }
+ brelse(bh);
+ } while (++block < end_block);
+ } while ((++rl)->vcn < end_vcn);
+ up_write(&log_ni->runlist.lock);
+ /*
+ * Zap the pages again just in case any got instantiated whilst we were
+ * emptying the blocks by hand. FIXME: We may not have completed
+ * writing to all the buffer heads yet so this may happen too early.
+ * We really should use a kernel thread to do the emptying
+ * asynchronously and then we can also set the volume dirty and output
+ * an error message if emptying should fail.
+ */
+ truncate_inode_pages(log_vi->i_mapping, 0);
+ /* Set the flag so we do not have to do it again on remount. */
+ NVolSetLogFileEmpty(vol);
ntfs_debug("Done.");
return true;
+io_err:
+ ntfs_error(sb, "Failed to write buffer. Unmount and run chkdsk.");
+ goto dirty_err;
+rl_err:
+ ntfs_error(sb, "Runlist is corrupt. Unmount and run chkdsk.");
+dirty_err:
+ NVolSetErrors(vol);
+ err = -EIO;
+err:
+ up_write(&log_ni->runlist.lock);
+ ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
+ -err);
+ return false;
}
#endif /* NTFS_RW */
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
index 9afd72c7ad0..56a9a6d25a2 100644
--- a/fs/ntfs/runlist.c
+++ b/fs/ntfs/runlist.c
@@ -1,7 +1,7 @@
/**
* runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002-2005 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -1714,7 +1714,7 @@ extend_hole:
sizeof(*rl));
/* Adjust the beginning of the tail if necessary. */
if (end > rl->vcn) {
- s64 delta = end - rl->vcn;
+ delta = end - rl->vcn;
rl->vcn = end;
rl->length -= delta;
/* Only adjust the lcn if it is real. */
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 778a850b463..4ba7f0bdc24 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -354,7 +354,6 @@ struct ocfs2_insert_type {
enum ocfs2_append_type ins_appending;
enum ocfs2_contig_type ins_contig;
int ins_contig_index;
- int ins_free_records;
int ins_tree_depth;
};
@@ -362,7 +361,6 @@ struct ocfs2_merge_ctxt {
enum ocfs2_contig_type c_contig_type;
int c_has_empty_extent;
int c_split_covers_rec;
- int c_used_tail_recs;
};
/*
@@ -2808,36 +2806,28 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
struct ocfs2_merge_ctxt *ctxt)
{
- int ret = 0, delete_tail_recs = 0;
+ int ret = 0;
struct ocfs2_extent_list *el = path_leaf_el(left_path);
struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
- if (ctxt->c_split_covers_rec) {
- delete_tail_recs++;
-
- if (ctxt->c_contig_type == CONTIG_LEFTRIGHT ||
- ctxt->c_has_empty_extent)
- delete_tail_recs++;
-
- if (ctxt->c_has_empty_extent) {
- /*
- * The merge code will need to create an empty
- * extent to take the place of the newly
- * emptied slot. Remove any pre-existing empty
- * extents - having more than one in a leaf is
- * illegal.
- */
- ret = ocfs2_rotate_tree_left(inode, handle, left_path,
- dealloc);
- if (ret) {
- mlog_errno(ret);
- goto out;
- }
- split_index--;
- rec = &el->l_recs[split_index];
+ if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
+ /*
+ * The merge code will need to create an empty
+ * extent to take the place of the newly
+ * emptied slot. Remove any pre-existing empty
+ * extents - having more than one in a leaf is
+ * illegal.
+ */
+ ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+ dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
}
+ split_index--;
+ rec = &el->l_recs[split_index];
}
if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) {
@@ -3593,6 +3583,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
struct buffer_head *di_bh,
struct buffer_head **last_eb_bh,
struct ocfs2_extent_rec *insert_rec,
+ int *free_records,
struct ocfs2_insert_type *insert)
{
int ret;
@@ -3633,7 +3624,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
* XXX: This test is simplistic, we can search for empty
* extent records too.
*/
- insert->ins_free_records = le16_to_cpu(el->l_count) -
+ *free_records = le16_to_cpu(el->l_count) -
le16_to_cpu(el->l_next_free_rec);
if (!insert->ins_tree_depth) {
@@ -3730,10 +3721,13 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
struct ocfs2_alloc_context *meta_ac)
{
int status;
+ int uninitialized_var(free_records);
struct buffer_head *last_eb_bh = NULL;
struct ocfs2_insert_type insert = {0, };
struct ocfs2_extent_rec rec;
+ BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
mlog(0, "add %u clusters at position %u to inode %llu\n",
new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -3752,7 +3746,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
rec.e_flags = flags;
status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
- &insert);
+ &free_records, &insert);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -3762,9 +3756,9 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
"Insert.contig_index: %d, Insert.free_records: %d, "
"Insert.tree_depth: %d\n",
insert.ins_appending, insert.ins_contig, insert.ins_contig_index,
- insert.ins_free_records, insert.ins_tree_depth);
+ free_records, insert.ins_tree_depth);
- if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) {
+ if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
status = ocfs2_grow_tree(inode, handle, fe_bh,
&insert.ins_tree_depth, &last_eb_bh,
meta_ac);
@@ -3847,26 +3841,17 @@ leftright:
if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
le16_to_cpu(rightmost_el->l_count)) {
- int old_depth = depth;
-
ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
meta_ac);
if (ret) {
mlog_errno(ret);
goto out;
}
-
- if (old_depth != depth) {
- eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
- rightmost_el = &eb->h_list;
- }
}
memset(&insert, 0, sizeof(struct ocfs2_insert_type));
insert.ins_appending = APPEND_NONE;
insert.ins_contig = CONTIG_NONE;
- insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
- - le16_to_cpu(rightmost_el->l_next_free_rec);
insert.ins_tree_depth = depth;
insert_range = le32_to_cpu(split_rec.e_cpos) +
@@ -4015,11 +4000,6 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
} else
rightmost_el = path_root_el(path);
- ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec);
- if (ctxt.c_used_tail_recs > 0 &&
- ocfs2_is_empty_extent(&rightmost_el->l_recs[0]))
- ctxt.c_used_tail_recs--;
-
if (rec->e_cpos == split_rec->e_cpos &&
rec->e_leaf_clusters == split_rec->e_leaf_clusters)
ctxt.c_split_covers_rec = 1;
@@ -4028,10 +4008,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]);
- mlog(0, "index: %d, contig: %u, used_tail_recs: %u, "
- "has_empty: %u, split_covers: %u\n", split_index,
- ctxt.c_contig_type, ctxt.c_used_tail_recs,
- ctxt.c_has_empty_extent, ctxt.c_split_covers_rec);
+ mlog(0, "index: %d, contig: %u, has_empty: %u, split_covers: %u\n",
+ split_index, ctxt.c_contig_type, ctxt.c_has_empty_extent,
+ ctxt.c_split_covers_rec);
if (ctxt.c_contig_type == CONTIG_NONE) {
if (ctxt.c_split_covers_rec)
@@ -4180,27 +4159,18 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
le16_to_cpu(rightmost_el->l_count)) {
- int old_depth = depth;
-
ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
meta_ac);
if (ret) {
mlog_errno(ret);
goto out;
}
-
- if (old_depth != depth) {
- eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
- rightmost_el = &eb->h_list;
- }
}
memset(&insert, 0, sizeof(struct ocfs2_insert_type));
insert.ins_appending = APPEND_NONE;
insert.ins_contig = CONTIG_NONE;
insert.ins_split = SPLIT_RIGHT;
- insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
- - le16_to_cpu(rightmost_el->l_next_free_rec);
insert.ins_tree_depth = depth;
ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
@@ -5665,12 +5635,50 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
return ocfs2_journal_dirty_data(handle, bh);
}
+static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
+ unsigned int from, unsigned int to,
+ struct page *page, int zero, u64 *phys)
+{
+ int ret, partial = 0;
+
+ ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0);
+ if (ret)
+ mlog_errno(ret);
+
+ if (zero)
+ zero_user_page(page, from, to - from, KM_USER0);
+
+ /*
+ * Need to set the buffers we zero'd into uptodate
+ * here if they aren't - ocfs2_map_page_blocks()
+ * might've skipped some
+ */
+ if (ocfs2_should_order_data(inode)) {
+ ret = walk_page_buffers(handle,
+ page_buffers(page),
+ from, to, &partial,
+ ocfs2_ordered_zero_func);
+ if (ret < 0)
+ mlog_errno(ret);
+ } else {
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, &partial,
+ ocfs2_writeback_zero_func);
+ if (ret < 0)
+ mlog_errno(ret);
+ }
+
+ if (!partial)
+ SetPageUptodate(page);
+
+ flush_dcache_page(page);
+}
+
static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
loff_t end, struct page **pages,
int numpages, u64 phys, handle_t *handle)
{
- int i, ret, partial = 0;
- void *kaddr;
+ int i;
struct page *page;
unsigned int from, to = PAGE_CACHE_SIZE;
struct super_block *sb = inode->i_sb;
@@ -5691,87 +5699,31 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
BUG_ON(from > PAGE_CACHE_SIZE);
BUG_ON(to > PAGE_CACHE_SIZE);
- ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0);
- if (ret)
- mlog_errno(ret);
-
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + from, 0, to - from);
- kunmap_atomic(kaddr, KM_USER0);
-
- /*
- * Need to set the buffers we zero'd into uptodate
- * here if they aren't - ocfs2_map_page_blocks()
- * might've skipped some
- */
- if (ocfs2_should_order_data(inode)) {
- ret = walk_page_buffers(handle,
- page_buffers(page),
- from, to, &partial,
- ocfs2_ordered_zero_func);
- if (ret < 0)
- mlog_errno(ret);
- } else {
- ret = walk_page_buffers(handle, page_buffers(page),
- from, to, &partial,
- ocfs2_writeback_zero_func);
- if (ret < 0)
- mlog_errno(ret);
- }
-
- if (!partial)
- SetPageUptodate(page);
-
- flush_dcache_page(page);
+ ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1,
+ &phys);
start = (page->index + 1) << PAGE_CACHE_SHIFT;
}
out:
- if (pages) {
- for (i = 0; i < numpages; i++) {
- page = pages[i];
- unlock_page(page);
- mark_page_accessed(page);
- page_cache_release(page);
- }
- }
+ if (pages)
+ ocfs2_unlock_and_free_pages(pages, numpages);
}
static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
- struct page **pages, int *num, u64 *phys)
+ struct page **pages, int *num)
{
- int i, numpages = 0, ret = 0;
- unsigned int ext_flags;
+ int numpages, ret = 0;
struct super_block *sb = inode->i_sb;
struct address_space *mapping = inode->i_mapping;
unsigned long index;
loff_t last_page_bytes;
- BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
BUG_ON(start > end);
- if (start == end)
- goto out;
-
BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
(end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
- ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits,
- phys, NULL, &ext_flags);
- if (ret) {
- mlog_errno(ret);
- goto out;
- }
-
- /* Tail is a hole. */
- if (*phys == 0)
- goto out;
-
- /* Tail is marked as unwritten, we can count on write to zero
- * in that case. */
- if (ext_flags & OCFS2_EXT_UNWRITTEN)
- goto out;
-
+ numpages = 0;
last_page_bytes = PAGE_ALIGN(end);
index = start >> PAGE_CACHE_SHIFT;
do {
@@ -5788,14 +5740,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
out:
if (ret != 0) {
- if (pages) {
- for (i = 0; i < numpages; i++) {
- if (pages[i]) {
- unlock_page(pages[i]);
- page_cache_release(pages[i]);
- }
- }
- }
+ if (pages)
+ ocfs2_unlock_and_free_pages(pages, numpages);
numpages = 0;
}
@@ -5816,18 +5762,20 @@ out:
int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
u64 range_start, u64 range_end)
{
- int ret, numpages;
+ int ret = 0, numpages;
struct page **pages = NULL;
u64 phys;
+ unsigned int ext_flags;
+ struct super_block *sb = inode->i_sb;
/*
* File systems which don't support sparse files zero on every
* extend.
*/
- if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+ if (!ocfs2_sparse_alloc(OCFS2_SB(sb)))
return 0;
- pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb),
+ pages = kcalloc(ocfs2_pages_per_cluster(sb),
sizeof(struct page *), GFP_NOFS);
if (pages == NULL) {
ret = -ENOMEM;
@@ -5835,16 +5783,31 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
goto out;
}
- ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
- &numpages, &phys);
+ if (range_start == range_end)
+ goto out;
+
+ ret = ocfs2_extent_map_get_blocks(inode,
+ range_start >> sb->s_blocksize_bits,
+ &phys, NULL, &ext_flags);
if (ret) {
mlog_errno(ret);
goto out;
}
- if (numpages == 0)
+ /*
+ * Tail is a hole, or is marked unwritten. In either case, we
+ * can count on read and write to return/push zero's.
+ */
+ if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN)
goto out;
+ ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
+ &numpages);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
ocfs2_zero_cluster_pages(inode, range_start, range_end, pages,
numpages, phys, handle);
@@ -5865,6 +5828,178 @@ out:
return ret;
}
+static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+{
+ unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+
+ memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+}
+
+void ocfs2_dinode_new_extent_list(struct inode *inode,
+ struct ocfs2_dinode *di)
+{
+ ocfs2_zero_dinode_id2(inode, di);
+ di->id2.i_list.l_tree_depth = 0;
+ di->id2.i_list.l_next_free_rec = 0;
+ di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+}
+
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+ spin_lock(&oi->ip_lock);
+ oi->ip_dyn_features |= OCFS2_INLINE_DATA_FL;
+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+ spin_unlock(&oi->ip_lock);
+
+ /*
+ * We clear the entire i_data structure here so that all
+ * fields can be properly initialized.
+ */
+ ocfs2_zero_dinode_id2(inode, di);
+
+ idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+}
+
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+ struct buffer_head *di_bh)
+{
+ int ret, i, has_data, num_pages = 0;
+ handle_t *handle;
+ u64 uninitialized_var(block);
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_alloc_context *data_ac = NULL;
+ struct page **pages = NULL;
+ loff_t end = osb->s_clustersize;
+
+ has_data = i_size_read(inode) ? 1 : 0;
+
+ if (has_data) {
+ pages = kcalloc(ocfs2_pages_per_cluster(osb->sb),
+ sizeof(struct page *), GFP_NOFS);
+ if (pages == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_unlock;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ if (has_data) {
+ u32 bit_off, num;
+ unsigned int page_end;
+ u64 phys;
+
+ ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+ &num);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * Save two copies, one for insert, and one that can
+ * be changed by ocfs2_map_and_dirty_page() below.
+ */
+ block = phys = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+ /*
+ * Non sparse file systems zero on extend, so no need
+ * to do that now.
+ */
+ if (!ocfs2_sparse_alloc(osb) &&
+ PAGE_CACHE_SIZE < osb->s_clustersize)
+ end = PAGE_CACHE_SIZE;
+
+ ret = ocfs2_grab_eof_pages(inode, 0, end, pages, &num_pages);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * This should populate the 1st page for us and mark
+ * it up to date.
+ */
+ ret = ocfs2_read_inline_data(inode, pages[0], di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ page_end = PAGE_CACHE_SIZE;
+ if (PAGE_CACHE_SIZE > osb->s_clustersize)
+ page_end = osb->s_clustersize;
+
+ for (i = 0; i < num_pages; i++)
+ ocfs2_map_and_dirty_page(inode, handle, 0, page_end,
+ pages[i], i > 0, &phys);
+ }
+
+ spin_lock(&oi->ip_lock);
+ oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+ spin_unlock(&oi->ip_lock);
+
+ ocfs2_dinode_new_extent_list(inode, di);
+
+ ocfs2_journal_dirty(handle, di_bh);
+
+ if (has_data) {
+ /*
+ * An error at this point should be extremely rare. If
+ * this proves to be false, we could always re-build
+ * the in-inode data from our pages.
+ */
+ ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+ 0, block, 1, 0, NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ inode->i_blocks = ocfs2_inode_sector_count(inode);
+ }
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+
+out_unlock:
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+
+out:
+ if (pages) {
+ ocfs2_unlock_and_free_pages(pages, num_pages);
+ kfree(pages);
+ }
+
+ return ret;
+}
+
/*
* It is expected, that by the time you call this function,
* inode->i_size and fe->i_size have been adjusted.
@@ -6090,6 +6225,81 @@ bail:
return status;
}
+/*
+ * 'start' is inclusive, 'end' is not.
+ */
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+ unsigned int start, unsigned int end, int trunc)
+{
+ int ret;
+ unsigned int numbytes;
+ handle_t *handle;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+ if (end > i_size_read(inode))
+ end = i_size_read(inode);
+
+ BUG_ON(start >= end);
+
+ if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) ||
+ !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) ||
+ !ocfs2_supports_inline_data(osb)) {
+ ocfs2_error(inode->i_sb,
+ "Inline data flags for inode %llu don't agree! "
+ "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ le16_to_cpu(di->i_dyn_features),
+ OCFS2_I(inode)->ip_dyn_features,
+ osb->s_feature_incompat);
+ ret = -EROFS;
+ goto out;
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ numbytes = end - start;
+ memset(idata->id_data + start, 0, numbytes);
+
+ /*
+ * No need to worry about the data page here - it's been
+ * truncated already and inline data doesn't need it for
+ * pushing zero's to disk, so we'll let readpage pick it up
+ * later.
+ */
+ if (trunc) {
+ i_size_write(inode, start);
+ di->i_size = cpu_to_le64(start);
+ }
+
+ inode->i_blocks = ocfs2_inode_sector_count(inode);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
+ di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
+ di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+ ocfs2_journal_dirty(handle, di_bh);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+
+out:
+ return ret;
+}
+
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
{
/*
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 990df48ae8d..42ff94bd801 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -62,6 +62,11 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
}
+void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di);
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+ struct buffer_head *di_bh);
+
int ocfs2_truncate_log_init(struct ocfs2_super *osb);
void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb);
void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
@@ -115,6 +120,8 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
struct inode *inode,
struct buffer_head *fe_bh,
struct ocfs2_truncate_context *tc);
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+ unsigned int start, unsigned int end, int trunc);
int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
u32 cpos, struct buffer_head **leaf_bh);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index f37f25c931f..34d10452c56 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -206,9 +206,70 @@ bail:
return err;
}
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+ struct buffer_head *di_bh)
+{
+ void *kaddr;
+ unsigned int size;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
+ ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ return -EROFS;
+ }
+
+ size = i_size_read(inode);
+
+ if (size > PAGE_CACHE_SIZE ||
+ size > ocfs2_max_inline_data(inode->i_sb)) {
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has with inline data has bad size: %u",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
+ return -EROFS;
+ }
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ if (size)
+ memcpy(kaddr, di->id2.i_data.id_data, size);
+ /* Clear the remaining part of the page */
+ memset(kaddr + size, 0, PAGE_CACHE_SIZE - size);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ SetPageUptodate(page);
+
+ return 0;
+}
+
+static int ocfs2_readpage_inline(struct inode *inode, struct page *page)
+{
+ int ret;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ BUG_ON(!PageLocked(page));
+ BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
+ ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
+ OCFS2_BH_CACHED, inode);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_read_inline_data(inode, page, di_bh);
+out:
+ unlock_page(page);
+
+ brelse(di_bh);
+ return ret;
+}
+
static int ocfs2_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT;
int ret, unlock = 1;
@@ -222,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
goto out;
}
- if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) {
+ if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
ret = AOP_TRUNCATED_PAGE;
goto out_meta_unlock;
}
@@ -252,7 +313,10 @@ static int ocfs2_readpage(struct file *file, struct page *page)
goto out_alloc;
}
- ret = block_read_full_page(page, ocfs2_get_block);
+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ ret = ocfs2_readpage_inline(inode, page);
+ else
+ ret = block_read_full_page(page, ocfs2_get_block);
unlock = 0;
ocfs2_data_unlock(inode, 0);
@@ -301,12 +365,8 @@ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
{
int ret;
- down_read(&OCFS2_I(inode)->ip_alloc_sem);
-
ret = block_prepare_write(page, from, to, ocfs2_get_block);
- up_read(&OCFS2_I(inode)->ip_alloc_sem);
-
return ret;
}
@@ -401,7 +461,9 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
down_read(&OCFS2_I(inode)->ip_alloc_sem);
}
- err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL);
+ if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+ err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+ NULL);
if (!INODE_JOURNAL(inode)) {
up_read(&OCFS2_I(inode)->ip_alloc_sem);
@@ -415,7 +477,6 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
goto bail;
}
-
bail:
status = err ? 0 : p_blkno;
@@ -570,6 +631,13 @@ static ssize_t ocfs2_direct_IO(int rw,
mlog_entry_void();
+ /*
+ * Fallback to buffered I/O if we see an inode without
+ * extents.
+ */
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ return 0;
+
if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
/*
* We get PR data locks even for O_DIRECT. This
@@ -834,18 +902,22 @@ struct ocfs2_write_ctxt {
struct ocfs2_cached_dealloc_ctxt w_dealloc;
};
-static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages)
{
int i;
- for(i = 0; i < wc->w_num_pages; i++) {
- if (wc->w_pages[i] == NULL)
- continue;
-
- unlock_page(wc->w_pages[i]);
- mark_page_accessed(wc->w_pages[i]);
- page_cache_release(wc->w_pages[i]);
+ for(i = 0; i < num_pages; i++) {
+ if (pages[i]) {
+ unlock_page(pages[i]);
+ mark_page_accessed(pages[i]);
+ page_cache_release(pages[i]);
+ }
}
+}
+
+static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+{
+ ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages);
brelse(wc->w_di_bh);
kfree(wc);
@@ -1360,6 +1432,160 @@ out:
return ret;
}
+static int ocfs2_write_begin_inline(struct address_space *mapping,
+ struct inode *inode,
+ struct ocfs2_write_ctxt *wc)
+{
+ int ret;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct page *page;
+ handle_t *handle;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
+
+ page = find_or_create_page(mapping, 0, GFP_NOFS);
+ if (!page) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+ /*
+ * If we don't set w_num_pages then this page won't get unlocked
+ * and freed on cleanup of the write context.
+ */
+ wc->w_pages[0] = wc->w_target_page = page;
+ wc->w_num_pages = 1;
+
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, wc->w_di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ ocfs2_commit_trans(osb, handle);
+
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+ ocfs2_set_inode_data_inline(inode, di);
+
+ if (!PageUptodate(page)) {
+ ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh);
+ if (ret) {
+ ocfs2_commit_trans(osb, handle);
+
+ goto out;
+ }
+ }
+
+ wc->w_handle = handle;
+out:
+ return ret;
+}
+
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size)
+{
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ if (new_size < le16_to_cpu(di->id2.i_data.id_count))
+ return 1;
+ return 0;
+}
+
+static int ocfs2_try_to_write_inline_data(struct address_space *mapping,
+ struct inode *inode, loff_t pos,
+ unsigned len, struct page *mmap_page,
+ struct ocfs2_write_ctxt *wc)
+{
+ int ret, written = 0;
+ loff_t end = pos + len;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+ mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n",
+ (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos,
+ oi->ip_dyn_features);
+
+ /*
+ * Handle inodes which already have inline data 1st.
+ */
+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ if (mmap_page == NULL &&
+ ocfs2_size_fits_inline_data(wc->w_di_bh, end))
+ goto do_inline_write;
+
+ /*
+ * The write won't fit - we have to give this inode an
+ * inline extent list now.
+ */
+ ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh);
+ if (ret)
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Check whether the inode can accept inline data.
+ */
+ if (oi->ip_clusters != 0 || i_size_read(inode) != 0)
+ return 0;
+
+ /*
+ * Check whether the write can fit.
+ */
+ if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb))
+ return 0;
+
+do_inline_write:
+ ret = ocfs2_write_begin_inline(mapping, inode, wc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * This signals to the caller that the data can be written
+ * inline.
+ */
+ written = 1;
+out:
+ return written ? written : ret;
+}
+
+/*
+ * This function only does anything for file systems which can't
+ * handle sparse files.
+ *
+ * What we want to do here is fill in any hole between the current end
+ * of allocation and the end of our write. That way the rest of the
+ * write path can treat it as an non-allocating write, which has no
+ * special case code for sparse/nonsparse files.
+ */
+static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos,
+ unsigned len,
+ struct ocfs2_write_ctxt *wc)
+{
+ int ret;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ loff_t newsize = pos + len;
+
+ if (ocfs2_sparse_alloc(osb))
+ return 0;
+
+ if (newsize <= i_size_read(inode))
+ return 0;
+
+ ret = ocfs2_extend_no_holes(inode, newsize, newsize - len);
+ if (ret)
+ mlog_errno(ret);
+
+ return ret;
+}
+
int ocfs2_write_begin_nolock(struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
@@ -1381,6 +1607,25 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
return ret;
}
+ if (ocfs2_supports_inline_data(osb)) {
+ ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len,
+ mmap_page, wc);
+ if (ret == 1) {
+ ret = 0;
+ goto success;
+ }
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
&extents_to_split);
if (ret) {
@@ -1462,6 +1707,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
if (meta_ac)
ocfs2_free_alloc_context(meta_ac);
+success:
*pagep = wc->w_target_page;
*fsdata = wc;
return 0;
@@ -1529,6 +1775,31 @@ out_fail:
return ret;
}
+static void ocfs2_write_end_inline(struct inode *inode, loff_t pos,
+ unsigned len, unsigned *copied,
+ struct ocfs2_dinode *di,
+ struct ocfs2_write_ctxt *wc)
+{
+ void *kaddr;
+
+ if (unlikely(*copied < len)) {
+ if (!PageUptodate(wc->w_target_page)) {
+ *copied = 0;
+ return;
+ }
+ }
+
+ kaddr = kmap_atomic(wc->w_target_page, KM_USER0);
+ memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ mlog(0, "Data written to inode at offset %llu. "
+ "id_count = %u, copied = %u, i_dyn_features = 0x%x\n",
+ (unsigned long long)pos, *copied,
+ le16_to_cpu(di->id2.i_data.id_count),
+ le16_to_cpu(di->i_dyn_features));
+}
+
int ocfs2_write_end_nolock(struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
@@ -1542,6 +1813,11 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
handle_t *handle = wc->w_handle;
struct page *tmppage;
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ ocfs2_write_end_inline(inode, pos, len, &copied, di, wc);
+ goto out_write_size;
+ }
+
if (unlikely(copied < len)) {
if (!PageUptodate(wc->w_target_page))
copied = 0;
@@ -1579,6 +1855,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
block_commit_write(tmppage, from, to);
}
+out_write_size:
pos += copied;
if (pos > inode->i_size) {
i_size_write(inode, pos);
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index 389579bd64e..113560877db 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -34,6 +34,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
struct inode *inode, unsigned int from,
unsigned int to, int new);
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages);
+
int walk_page_buffers( handle_t *handle,
struct buffer_head *head,
unsigned from,
@@ -59,6 +61,10 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
struct page **pagep, void **fsdata,
struct buffer_head *di_bh, struct page *mmap_page);
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+ struct buffer_head *di_bh);
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size);
+
/* all ocfs2_dio_end_io()'s fault */
#define ocfs2_iocb_is_rw_locked(iocb) \
test_bit(0, (unsigned long *)&iocb->private)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index da2c2b442b4..f14b541fab9 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -216,7 +216,7 @@ static void o2hb_wait_on_io(struct o2hb_region *reg,
wait_for_completion(&wc->wc_io_complete);
}
-static int o2hb_bio_end_io(struct bio *bio,
+static void o2hb_bio_end_io(struct bio *bio,
int error)
{
struct o2hb_bio_wait_ctxt *wc = bio->bi_private;
@@ -228,7 +228,6 @@ static int o2hb_bio_end_io(struct bio *bio,
o2hb_bio_wait_dec(wc, 1);
bio_put(bio);
- return 0;
}
/* Setup a Bio to cover I/O against num_slots slots starting at
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index e9e042b93db..a4882c8df94 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = {
};
static struct kset mlog_kset = {
- .kobj = {.name = "logmask", .ktype = &mlog_ktype},
+ .kobj = {.ktype = &mlog_ktype},
};
int mlog_sys_init(struct kset *o2cb_subsys)
@@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
}
mlog_attr_ptrs[i] = NULL;
+ kobject_set_name(&mlog_kset.kobj, "logmask");
kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
return kset_register(&mlog_kset);
}
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 0d5fdde959c..7453b70c1a1 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -55,10 +55,16 @@
#include "journal.h"
#include "namei.h"
#include "suballoc.h"
+#include "super.h"
#include "uptodate.h"
#include "buffer_head_io.h"
+#define NAMEI_RA_CHUNKS 2
+#define NAMEI_RA_BLOCKS 4
+#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
static unsigned char ocfs2_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
@@ -66,12 +72,614 @@ static unsigned char ocfs2_filetype_table[] = {
static int ocfs2_extend_dir(struct ocfs2_super *osb,
struct inode *dir,
struct buffer_head *parent_fe_bh,
+ unsigned int blocks_wanted,
struct buffer_head **new_de_bh);
+static int ocfs2_do_extend_dir(struct super_block *sb,
+ handle_t *handle,
+ struct inode *dir,
+ struct buffer_head *parent_fe_bh,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ struct buffer_head **new_bh);
+
/*
- * ocfs2_readdir()
+ * bh passed here can be an inode block or a dir data block, depending
+ * on the inode inline data flag.
+ */
+static int ocfs2_check_dir_entry(struct inode * dir,
+ struct ocfs2_dir_entry * de,
+ struct buffer_head * bh,
+ unsigned long offset)
+{
+ const char *error_msg = NULL;
+ const int rlen = le16_to_cpu(de->rec_len);
+
+ if (rlen < OCFS2_DIR_REC_LEN(1))
+ error_msg = "rec_len is smaller than minimal";
+ else if (rlen % 4 != 0)
+ error_msg = "rec_len % 4 != 0";
+ else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
+ error_msg = "rec_len is too small for name_len";
+ else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+
+ if (error_msg != NULL)
+ mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
+ "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
+ (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
+ offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
+ de->name_len);
+ return error_msg == NULL ? 1 : 0;
+}
+
+static inline int ocfs2_match(int len,
+ const char * const name,
+ struct ocfs2_dir_entry *de)
+{
+ if (len != de->name_len)
+ return 0;
+ if (!de->inode)
+ return 0;
+ return !memcmp(name, de->name, len);
+}
+
+/*
+ * Returns 0 if not found, -1 on failure, and 1 on success
+ */
+static int inline ocfs2_search_dirblock(struct buffer_head *bh,
+ struct inode *dir,
+ const char *name, int namelen,
+ unsigned long offset,
+ char *first_de,
+ unsigned int bytes,
+ struct ocfs2_dir_entry **res_dir)
+{
+ struct ocfs2_dir_entry *de;
+ char *dlimit, *de_buf;
+ int de_len;
+ int ret = 0;
+
+ mlog_entry_void();
+
+ de_buf = first_de;
+ dlimit = de_buf + bytes;
+
+ while (de_buf < dlimit) {
+ /* this code is executed quadratically often */
+ /* do minimal checking `by hand' */
+
+ de = (struct ocfs2_dir_entry *) de_buf;
+
+ if (de_buf + namelen <= dlimit &&
+ ocfs2_match(namelen, name, de)) {
+ /* found a match - just to be sure, do a full check */
+ if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
+ ret = -1;
+ goto bail;
+ }
+ *res_dir = de;
+ ret = 1;
+ goto bail;
+ }
+
+ /* prevent looping on a bad block */
+ de_len = le16_to_cpu(de->rec_len);
+ if (de_len <= 0) {
+ ret = -1;
+ goto bail;
+ }
+
+ de_buf += de_len;
+ offset += de_len;
+ }
+
+bail:
+ mlog_exit(ret);
+ return ret;
+}
+
+static struct buffer_head *ocfs2_find_entry_id(const char *name,
+ int namelen,
+ struct inode *dir,
+ struct ocfs2_dir_entry **res_dir)
+{
+ int ret, found;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_dinode *di;
+ struct ocfs2_inline_data *data;
+
+ ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+ &di_bh, OCFS2_BH_CACHED, dir);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+ data = &di->id2.i_data;
+
+ found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0,
+ data->id_data, i_size_read(dir), res_dir);
+ if (found == 1)
+ return di_bh;
+
+ brelse(di_bh);
+out:
+ return NULL;
+}
+
+struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
+ struct inode *dir,
+ struct ocfs2_dir_entry **res_dir)
+{
+ struct super_block *sb;
+ struct buffer_head *bh_use[NAMEI_RA_SIZE];
+ struct buffer_head *bh, *ret = NULL;
+ unsigned long start, block, b;
+ int ra_max = 0; /* Number of bh's in the readahead
+ buffer, bh_use[] */
+ int ra_ptr = 0; /* Current index into readahead
+ buffer */
+ int num = 0;
+ int nblocks, i, err;
+
+ mlog_entry_void();
+
+ sb = dir->i_sb;
+
+ nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+ start = OCFS2_I(dir)->ip_dir_start_lookup;
+ if (start >= nblocks)
+ start = 0;
+ block = start;
+
+restart:
+ do {
+ /*
+ * We deal with the read-ahead logic here.
+ */
+ if (ra_ptr >= ra_max) {
+ /* Refill the readahead buffer */
+ ra_ptr = 0;
+ b = block;
+ for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
+ /*
+ * Terminate if we reach the end of the
+ * directory and must wrap, or if our
+ * search has finished at this block.
+ */
+ if (b >= nblocks || (num && block == start)) {
+ bh_use[ra_max] = NULL;
+ break;
+ }
+ num++;
+
+ bh = ocfs2_bread(dir, b++, &err, 1);
+ bh_use[ra_max] = bh;
+ }
+ }
+ if ((bh = bh_use[ra_ptr++]) == NULL)
+ goto next;
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ /* read error, skip block & hope for the best */
+ ocfs2_error(dir->i_sb, "reading directory %llu, "
+ "offset %lu\n",
+ (unsigned long long)OCFS2_I(dir)->ip_blkno,
+ block);
+ brelse(bh);
+ goto next;
+ }
+ i = ocfs2_search_dirblock(bh, dir, name, namelen,
+ block << sb->s_blocksize_bits,
+ bh->b_data, sb->s_blocksize,
+ res_dir);
+ if (i == 1) {
+ OCFS2_I(dir)->ip_dir_start_lookup = block;
+ ret = bh;
+ goto cleanup_and_exit;
+ } else {
+ brelse(bh);
+ if (i < 0)
+ goto cleanup_and_exit;
+ }
+ next:
+ if (++block >= nblocks)
+ block = 0;
+ } while (block != start);
+
+ /*
+ * If the directory has grown while we were searching, then
+ * search the last part of the directory before giving up.
+ */
+ block = nblocks;
+ nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+ if (block < nblocks) {
+ start = 0;
+ goto restart;
+ }
+
+cleanup_and_exit:
+ /* Clean up the read-ahead blocks */
+ for (; ra_ptr < ra_max; ra_ptr++)
+ brelse(bh_use[ra_ptr]);
+
+ mlog_exit_ptr(ret);
+ return ret;
+}
+
+/*
+ * Try to find an entry of the provided name within 'dir'.
*
+ * If nothing was found, NULL is returned. Otherwise, a buffer_head
+ * and pointer to the dir entry are passed back.
+ *
+ * Caller can NOT assume anything about the contents of the
+ * buffer_head - it is passed back only so that it can be passed into
+ * any one of the manipulation functions (add entry, delete entry,
+ * etc). As an example, bh in the extent directory case is a data
+ * block, in the inline-data case it actually points to an inode.
*/
-int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
+ struct inode *dir,
+ struct ocfs2_dir_entry **res_dir)
+{
+ *res_dir = NULL;
+
+ if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ return ocfs2_find_entry_id(name, namelen, dir, res_dir);
+
+ return ocfs2_find_entry_el(name, namelen, dir, res_dir);
+}
+
+/*
+ * Update inode number and type of a previously found directory entry.
+ */
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+ struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+ struct inode *new_entry_inode)
+{
+ int ret;
+
+ /*
+ * The same code works fine for both inline-data and extent
+ * based directories, so no need to split this up.
+ */
+
+ ret = ocfs2_journal_access(handle, dir, de_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno);
+ ocfs2_set_de_type(de, new_entry_inode->i_mode);
+
+ ocfs2_journal_dirty(handle, de_bh);
+
+out:
+ return ret;
+}
+
+static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
+ struct ocfs2_dir_entry *de_del,
+ struct buffer_head *bh, char *first_de,
+ unsigned int bytes)
+{
+ struct ocfs2_dir_entry *de, *pde;
+ int i, status = -ENOENT;
+
+ mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
+
+ i = 0;
+ pde = NULL;
+ de = (struct ocfs2_dir_entry *) first_de;
+ while (i < bytes) {
+ if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
+ status = -EIO;
+ mlog_errno(status);
+ goto bail;
+ }
+ if (de == de_del) {
+ status = ocfs2_journal_access(handle, dir, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ status = -EIO;
+ mlog_errno(status);
+ goto bail;
+ }
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+ le16_to_cpu(de->rec_len));
+ else
+ de->inode = 0;
+ dir->i_version++;
+ status = ocfs2_journal_dirty(handle, bh);
+ goto bail;
+ }
+ i += le16_to_cpu(de->rec_len);
+ pde = de;
+ de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
+ }
+bail:
+ mlog_exit(status);
+ return status;
+}
+
+static inline int ocfs2_delete_entry_id(handle_t *handle,
+ struct inode *dir,
+ struct ocfs2_dir_entry *de_del,
+ struct buffer_head *bh)
+{
+ int ret;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_dinode *di;
+ struct ocfs2_inline_data *data;
+
+ ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+ &di_bh, OCFS2_BH_CACHED, dir);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+ data = &di->id2.i_data;
+
+ ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data,
+ i_size_read(dir));
+
+ brelse(di_bh);
+out:
+ return ret;
+}
+
+static inline int ocfs2_delete_entry_el(handle_t *handle,
+ struct inode *dir,
+ struct ocfs2_dir_entry *de_del,
+ struct buffer_head *bh)
+{
+ return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data,
+ bh->b_size);
+}
+
+/*
+ * ocfs2_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+int ocfs2_delete_entry(handle_t *handle,
+ struct inode *dir,
+ struct ocfs2_dir_entry *de_del,
+ struct buffer_head *bh)
+{
+ if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ return ocfs2_delete_entry_id(handle, dir, de_del, bh);
+
+ return ocfs2_delete_entry_el(handle, dir, de_del, bh);
+}
+
+/*
+ * Check whether 'de' has enough room to hold an entry of
+ * 'new_rec_len' bytes.
+ */
+static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de,
+ unsigned int new_rec_len)
+{
+ unsigned int de_really_used;
+
+ /* Check whether this is an empty record with enough space */
+ if (le64_to_cpu(de->inode) == 0 &&
+ le16_to_cpu(de->rec_len) >= new_rec_len)
+ return 1;
+
+ /*
+ * Record might have free space at the end which we can
+ * use.
+ */
+ de_really_used = OCFS2_DIR_REC_LEN(de->name_len);
+ if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len))
+ return 1;
+
+ return 0;
+}
+
+/* we don't always have a dentry for what we want to add, so people
+ * like orphan dir can call this instead.
+ *
+ * If you pass me insert_bh, I'll skip the search of the other dir
+ * blocks and put the record in there.
+ */
+int __ocfs2_add_entry(handle_t *handle,
+ struct inode *dir,
+ const char *name, int namelen,
+ struct inode *inode, u64 blkno,
+ struct buffer_head *parent_fe_bh,
+ struct buffer_head *insert_bh)
+{
+ unsigned long offset;
+ unsigned short rec_len;
+ struct ocfs2_dir_entry *de, *de1;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data;
+ struct super_block *sb = dir->i_sb;
+ int retval, status;
+ unsigned int size = sb->s_blocksize;
+ char *data_start = insert_bh->b_data;
+
+ mlog_entry_void();
+
+ if (!namelen)
+ return -EINVAL;
+
+ if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ data_start = di->id2.i_data.id_data;
+ size = i_size_read(dir);
+
+ BUG_ON(insert_bh != parent_fe_bh);
+ }
+
+ rec_len = OCFS2_DIR_REC_LEN(namelen);
+ offset = 0;
+ de = (struct ocfs2_dir_entry *) data_start;
+ while (1) {
+ BUG_ON((char *)de >= (size + data_start));
+
+ /* These checks should've already been passed by the
+ * prepare function, but I guess we can leave them
+ * here anyway. */
+ if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
+ retval = -ENOENT;
+ goto bail;
+ }
+ if (ocfs2_match(namelen, name, de)) {
+ retval = -EEXIST;
+ goto bail;
+ }
+
+ if (ocfs2_dirent_would_fit(de, rec_len)) {
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
+ if (retval < 0) {
+ mlog_errno(retval);
+ goto bail;
+ }
+
+ status = ocfs2_journal_access(handle, dir, insert_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ /* By now the buffer is marked for journaling */
+ offset += le16_to_cpu(de->rec_len);
+ if (le64_to_cpu(de->inode)) {
+ de1 = (struct ocfs2_dir_entry *)((char *) de +
+ OCFS2_DIR_REC_LEN(de->name_len));
+ de1->rec_len =
+ cpu_to_le16(le16_to_cpu(de->rec_len) -
+ OCFS2_DIR_REC_LEN(de->name_len));
+ de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+ de = de1;
+ }
+ de->file_type = OCFS2_FT_UNKNOWN;
+ if (blkno) {
+ de->inode = cpu_to_le64(blkno);
+ ocfs2_set_de_type(de, inode->i_mode);
+ } else
+ de->inode = 0;
+ de->name_len = namelen;
+ memcpy(de->name, name, namelen);
+
+ dir->i_version++;
+ status = ocfs2_journal_dirty(handle, insert_bh);
+ retval = 0;
+ goto bail;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+
+ /* when you think about it, the assert above should prevent us
+ * from ever getting here. */
+ retval = -ENOSPC;
+bail:
+
+ mlog_exit(retval);
+ return retval;
+}
+
+static int ocfs2_dir_foreach_blk_id(struct inode *inode,
+ unsigned long *f_version,
+ loff_t *f_pos, void *priv,
+ filldir_t filldir, int *filldir_err)
+{
+ int ret, i, filldir_ret;
+ unsigned long offset = *f_pos;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_dinode *di;
+ struct ocfs2_inline_data *data;
+ struct ocfs2_dir_entry *de;
+
+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
+ &di_bh, OCFS2_BH_CACHED, inode);
+ if (ret) {
+ mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ goto out;
+ }
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+ data = &di->id2.i_data;
+
+ while (*f_pos < i_size_read(inode)) {
+revalidate:
+ /* If the dir block has changed since the last call to
+ * readdir(2), then we might be pointing to an invalid
+ * dirent right now. Scan from the start of the block
+ * to make sure. */
+ if (*f_version != inode->i_version) {
+ for (i = 0; i < i_size_read(inode) && i < offset; ) {
+ de = (struct ocfs2_dir_entry *)
+ (data->id_data + i);
+ /* It's too expensive to do a full
+ * dirent test each time round this
+ * loop, but we do have to test at
+ * least that it is non-zero. A
+ * failure will be detected in the
+ * dirent test below. */
+ if (le16_to_cpu(de->rec_len) <
+ OCFS2_DIR_REC_LEN(1))
+ break;
+ i += le16_to_cpu(de->rec_len);
+ }
+ *f_pos = offset = i;
+ *f_version = inode->i_version;
+ }
+
+ de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos);
+ if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) {
+ /* On error, skip the f_pos to the end. */
+ *f_pos = i_size_read(inode);
+ goto out;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ if (le64_to_cpu(de->inode)) {
+ /* We might block in the next section
+ * if the data destination is
+ * currently swapped out. So, use a
+ * version stamp to detect whether or
+ * not the directory has been modified
+ * during the copy operation.
+ */
+ unsigned long version = *f_version;
+ unsigned char d_type = DT_UNKNOWN;
+
+ if (de->file_type < OCFS2_FT_MAX)
+ d_type = ocfs2_filetype_table[de->file_type];
+
+ filldir_ret = filldir(priv, de->name,
+ de->name_len,
+ *f_pos,
+ le64_to_cpu(de->inode),
+ d_type);
+ if (filldir_ret) {
+ if (filldir_err)
+ *filldir_err = filldir_ret;
+ break;
+ }
+ if (version != *f_version)
+ goto revalidate;
+ }
+ *f_pos += le16_to_cpu(de->rec_len);
+ }
+
+out:
+ brelse(di_bh);
+
+ return 0;
+}
+
+static int ocfs2_dir_foreach_blk_el(struct inode *inode,
+ unsigned long *f_version,
+ loff_t *f_pos, void *priv,
+ filldir_t filldir, int *filldir_err)
{
int error = 0;
unsigned long offset, blk, last_ra_blk = 0;
@@ -79,45 +687,23 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
struct buffer_head * bh, * tmp;
struct ocfs2_dir_entry * de;
int err;
- struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb = inode->i_sb;
unsigned int ra_sectors = 16;
- int lock_level = 0;
-
- mlog_entry("dirino=%llu\n",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
stored = 0;
bh = NULL;
- error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
- if (lock_level && error >= 0) {
- /* We release EX lock which used to update atime
- * and get PR lock again to reduce contention
- * on commonly accessed directories. */
- ocfs2_meta_unlock(inode, 1);
- lock_level = 0;
- error = ocfs2_meta_lock(inode, NULL, 0);
- }
- if (error < 0) {
- if (error != -ENOENT)
- mlog_errno(error);
- /* we haven't got any yet, so propagate the error. */
- stored = error;
- goto bail_nolock;
- }
+ offset = (*f_pos) & (sb->s_blocksize - 1);
- offset = filp->f_pos & (sb->s_blocksize - 1);
-
- while (!error && !stored && filp->f_pos < i_size_read(inode)) {
- blk = (filp->f_pos) >> sb->s_blocksize_bits;
+ while (!error && !stored && *f_pos < i_size_read(inode)) {
+ blk = (*f_pos) >> sb->s_blocksize_bits;
bh = ocfs2_bread(inode, blk, &err, 0);
if (!bh) {
mlog(ML_ERROR,
"directory #%llu contains a hole at offset %lld\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
- filp->f_pos);
- filp->f_pos += sb->s_blocksize - offset;
+ *f_pos);
+ *f_pos += sb->s_blocksize - offset;
continue;
}
@@ -143,7 +729,7 @@ revalidate:
* readdir(2), then we might be pointing to an invalid
* dirent right now. Scan from the start of the block
* to make sure. */
- if (filp->f_version != inode->i_version) {
+ if (*f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
de = (struct ocfs2_dir_entry *) (bh->b_data + i);
/* It's too expensive to do a full
@@ -158,21 +744,20 @@ revalidate:
i += le16_to_cpu(de->rec_len);
}
offset = i;
- filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+ *f_pos = ((*f_pos) & ~(sb->s_blocksize - 1))
| offset;
- filp->f_version = inode->i_version;
+ *f_version = inode->i_version;
}
- while (!error && filp->f_pos < i_size_read(inode)
+ while (!error && *f_pos < i_size_read(inode)
&& offset < sb->s_blocksize) {
de = (struct ocfs2_dir_entry *) (bh->b_data + offset);
if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
/* On error, skip the f_pos to the
next block. */
- filp->f_pos = (filp->f_pos |
- (sb->s_blocksize - 1)) + 1;
+ *f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1;
brelse(bh);
- goto bail;
+ goto out;
}
offset += le16_to_cpu(de->rec_len);
if (le64_to_cpu(de->inode)) {
@@ -183,36 +768,109 @@ revalidate:
* not the directory has been modified
* during the copy operation.
*/
- unsigned long version = filp->f_version;
+ unsigned long version = *f_version;
unsigned char d_type = DT_UNKNOWN;
if (de->file_type < OCFS2_FT_MAX)
d_type = ocfs2_filetype_table[de->file_type];
- error = filldir(dirent, de->name,
+ error = filldir(priv, de->name,
de->name_len,
- filp->f_pos,
- ino_from_blkno(sb, le64_to_cpu(de->inode)),
+ *f_pos,
+ le64_to_cpu(de->inode),
d_type);
- if (error)
+ if (error) {
+ if (filldir_err)
+ *filldir_err = error;
break;
- if (version != filp->f_version)
+ }
+ if (version != *f_version)
goto revalidate;
stored ++;
}
- filp->f_pos += le16_to_cpu(de->rec_len);
+ *f_pos += le16_to_cpu(de->rec_len);
}
offset = 0;
brelse(bh);
}
stored = 0;
-bail:
+out:
+ return stored;
+}
+
+static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version,
+ loff_t *f_pos, void *priv, filldir_t filldir,
+ int *filldir_err)
+{
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv,
+ filldir, filldir_err);
+
+ return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir,
+ filldir_err);
+}
+
+/*
+ * This is intended to be called from inside other kernel functions,
+ * so we fake some arguments.
+ */
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+ filldir_t filldir)
+{
+ int ret = 0, filldir_err = 0;
+ unsigned long version = inode->i_version;
+
+ while (*f_pos < i_size_read(inode)) {
+ ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv,
+ filldir, &filldir_err);
+ if (ret || filldir_err)
+ break;
+ }
+
+ if (ret > 0)
+ ret = -EIO;
+
+ return 0;
+}
+
+/*
+ * ocfs2_readdir()
+ *
+ */
+int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ int error = 0;
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ int lock_level = 0;
+
+ mlog_entry("dirino=%llu\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+ error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+ if (lock_level && error >= 0) {
+ /* We release EX lock which used to update atime
+ * and get PR lock again to reduce contention
+ * on commonly accessed directories. */
+ ocfs2_meta_unlock(inode, 1);
+ lock_level = 0;
+ error = ocfs2_meta_lock(inode, NULL, 0);
+ }
+ if (error < 0) {
+ if (error != -ENOENT)
+ mlog_errno(error);
+ /* we haven't got any yet, so propagate the error. */
+ goto bail_nolock;
+ }
+
+ error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
+ dirent, filldir, NULL);
+
ocfs2_meta_unlock(inode, lock_level);
bail_nolock:
- mlog_exit(stored);
+ mlog_exit(error);
- return stored;
+ return error;
}
/*
@@ -252,6 +910,23 @@ leave:
return status;
}
+/*
+ * Convenience function for callers which just want the block number
+ * mapped to a name and don't require the full dirent info, etc.
+ */
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+ int namelen, u64 *blkno)
+{
+ int ret;
+ struct buffer_head *bh = NULL;
+ struct ocfs2_dir_entry *dirent = NULL;
+
+ ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent);
+ brelse(bh);
+
+ return ret;
+}
+
/* Check for a name within a directory.
*
* Return 0 if the name does not exist
@@ -284,77 +959,414 @@ bail:
return ret;
}
+struct ocfs2_empty_dir_priv {
+ unsigned seen_dot;
+ unsigned seen_dot_dot;
+ unsigned seen_other;
+};
+static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
+ loff_t pos, u64 ino, unsigned type)
+{
+ struct ocfs2_empty_dir_priv *p = priv;
+
+ /*
+ * Check the positions of "." and ".." records to be sure
+ * they're in the correct place.
+ */
+ if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) {
+ p->seen_dot = 1;
+ return 0;
+ }
+
+ if (name_len == 2 && !strncmp("..", name, 2) &&
+ pos == OCFS2_DIR_REC_LEN(1)) {
+ p->seen_dot_dot = 1;
+ return 0;
+ }
+
+ p->seen_other = 1;
+ return 1;
+}
/*
* routine to check that the specified directory is empty (for rmdir)
+ *
+ * Returns 1 if dir is empty, zero otherwise.
*/
int ocfs2_empty_dir(struct inode *inode)
{
- unsigned long offset;
- struct buffer_head * bh;
- struct ocfs2_dir_entry * de, * de1;
- struct super_block * sb;
- int err;
+ int ret;
+ loff_t start = 0;
+ struct ocfs2_empty_dir_priv priv;
+
+ memset(&priv, 0, sizeof(priv));
+
+ ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir);
+ if (ret)
+ mlog_errno(ret);
- sb = inode->i_sb;
- if ((i_size_read(inode) <
- (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) ||
- !(bh = ocfs2_bread(inode, 0, &err, 0))) {
- mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n",
+ if (!priv.seen_dot || !priv.seen_dot_dot) {
+ mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno);
+ /*
+ * XXX: Is it really safe to allow an unlink to continue?
+ */
return 1;
}
- de = (struct ocfs2_dir_entry *) bh->b_data;
- de1 = (struct ocfs2_dir_entry *)
- ((char *)de + le16_to_cpu(de->rec_len));
- if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) ||
- !le64_to_cpu(de1->inode) ||
- strcmp(".", de->name) ||
- strcmp("..", de1->name)) {
- mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- brelse(bh);
- return 1;
+ return !priv.seen_other;
+}
+
+static void ocfs2_fill_initial_dirents(struct inode *inode,
+ struct inode *parent,
+ char *start, unsigned int size)
+{
+ struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start;
+
+ de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
+ de->name_len = 1;
+ de->rec_len =
+ cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+ strcpy(de->name, ".");
+ ocfs2_set_de_type(de, S_IFDIR);
+
+ de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
+ de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
+ de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1));
+ de->name_len = 2;
+ strcpy(de->name, "..");
+ ocfs2_set_de_type(de, S_IFDIR);
+}
+
+/*
+ * This works together with code in ocfs2_mknod_locked() which sets
+ * the inline-data flag and initializes the inline-data section.
+ */
+static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb,
+ handle_t *handle,
+ struct inode *parent,
+ struct inode *inode,
+ struct buffer_head *di_bh)
+{
+ int ret;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_inline_data *data = &di->id2.i_data;
+ unsigned int size = le16_to_cpu(data->id_count);
+
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
}
- offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
- de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len));
- while (offset < i_size_read(inode) ) {
- if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) {
- brelse(bh);
- bh = ocfs2_bread(inode,
- offset >> sb->s_blocksize_bits, &err, 0);
- if (!bh) {
- mlog(ML_ERROR, "dir %llu has a hole at %lu\n",
- (unsigned long long)OCFS2_I(inode)->ip_blkno, offset);
- offset += sb->s_blocksize;
- continue;
- }
- de = (struct ocfs2_dir_entry *) bh->b_data;
- }
- if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
- brelse(bh);
- return 1;
+
+ ocfs2_fill_initial_dirents(inode, parent, data->id_data, size);
+
+ ocfs2_journal_dirty(handle, di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ i_size_write(inode, size);
+ inode->i_nlink = 2;
+ inode->i_blocks = ocfs2_inode_sector_count(inode);
+
+ ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+
+out:
+ return ret;
+}
+
+static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
+ handle_t *handle,
+ struct inode *parent,
+ struct inode *inode,
+ struct buffer_head *fe_bh,
+ struct ocfs2_alloc_context *data_ac)
+{
+ int status;
+ struct buffer_head *new_bh = NULL;
+
+ mlog_entry_void();
+
+ status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
+ data_ac, NULL, &new_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+
+ ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+ status = ocfs2_journal_access(handle, inode, new_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ memset(new_bh->b_data, 0, osb->sb->s_blocksize);
+
+ ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data,
+ osb->sb->s_blocksize);
+
+ status = ocfs2_journal_dirty(handle, new_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+
+ i_size_write(inode, inode->i_sb->s_blocksize);
+ inode->i_nlink = 2;
+ inode->i_blocks = ocfs2_inode_sector_count(inode);
+ status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+
+ status = 0;
+bail:
+ if (new_bh)
+ brelse(new_bh);
+
+ mlog_exit(status);
+ return status;
+}
+
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+ handle_t *handle,
+ struct inode *parent,
+ struct inode *inode,
+ struct buffer_head *fe_bh,
+ struct ocfs2_alloc_context *data_ac)
+{
+ BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL);
+
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh);
+
+ return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh,
+ data_ac);
+}
+
+static void ocfs2_expand_last_dirent(char *start, unsigned int old_size,
+ unsigned int new_size)
+{
+ struct ocfs2_dir_entry *de;
+ struct ocfs2_dir_entry *prev_de;
+ char *de_buf, *limit;
+ unsigned int bytes = new_size - old_size;
+
+ limit = start + old_size;
+ de_buf = start;
+ de = (struct ocfs2_dir_entry *)de_buf;
+ do {
+ prev_de = de;
+ de_buf += le16_to_cpu(de->rec_len);
+ de = (struct ocfs2_dir_entry *)de_buf;
+ } while (de_buf < limit);
+
+ le16_add_cpu(&prev_de->rec_len, bytes);
+}
+
+/*
+ * We allocate enough clusters to fulfill "blocks_wanted", but set
+ * i_size to exactly one block. Ocfs2_extend_dir() will handle the
+ * rest automatically for us.
+ *
+ * *first_block_bh is a pointer to the 1st data block allocated to the
+ * directory.
+ */
+static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
+ unsigned int blocks_wanted,
+ struct buffer_head **first_block_bh)
+{
+ int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS;
+ u32 alloc, bit_off, len;
+ struct super_block *sb = dir->i_sb;
+ u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits;
+ struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+ struct ocfs2_inode_info *oi = OCFS2_I(dir);
+ struct ocfs2_alloc_context *data_ac;
+ struct buffer_head *dirdata_bh = NULL;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ handle_t *handle;
+
+ alloc = ocfs2_clusters_for_bytes(sb, bytes);
+
+ /*
+ * We should never need more than 2 clusters for this -
+ * maximum dirent size is far less than one block. In fact,
+ * the only time we'd need more than one cluster is if
+ * blocksize == clustersize and the dirent won't fit in the
+ * extra space that the expansion to a single block gives. As
+ * of today, that only happens on 4k/4k file systems.
+ */
+ BUG_ON(alloc > 2);
+
+ ret = ocfs2_reserve_clusters(osb, alloc, &data_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ down_write(&oi->ip_alloc_sem);
+
+ /*
+ * Prepare for worst case allocation scenario of two seperate
+ * extents.
+ */
+ if (alloc == 2)
+ credits += OCFS2_SUBALLOC_ALLOC;
+
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_sem;
+ }
+
+ /*
+ * Try to claim as many clusters as the bitmap can give though
+ * if we only get one now, that's enough to continue. The rest
+ * will be claimed after the conversion to extents.
+ */
+ ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * Operations are carefully ordered so that we set up the new
+ * data block first. The conversion from inline data to
+ * extents follows.
+ */
+ blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+ dirdata_bh = sb_getblk(sb, blkno);
+ if (!dirdata_bh) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
+
+ ret = ocfs2_journal_access(handle, dir, dirdata_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir));
+ memset(dirdata_bh->b_data + i_size_read(dir), 0,
+ sb->s_blocksize - i_size_read(dir));
+ ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir),
+ sb->s_blocksize);
+
+ ret = ocfs2_journal_dirty(handle, dirdata_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * Set extent, i_size, etc on the directory. After this, the
+ * inode should contain the same exact dirents as before and
+ * be fully accessible from system calls.
+ *
+ * We let the later dirent insert modify c/mtime - to the user
+ * the data hasn't changed.
+ */
+ ret = ocfs2_journal_access(handle, dir, di_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ spin_lock(&oi->ip_lock);
+ oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+ spin_unlock(&oi->ip_lock);
+
+ ocfs2_dinode_new_extent_list(dir, di);
+
+ i_size_write(dir, sb->s_blocksize);
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+
+ di->i_size = cpu_to_le64(sb->s_blocksize);
+ di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
+ di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+ dir->i_blocks = ocfs2_inode_sector_count(dir);
+
+ /*
+ * This should never fail as our extent list is empty and all
+ * related blocks have been journaled already.
+ */
+ ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
+ NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_dirty(handle, di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * We asked for two clusters, but only got one in the 1st
+ * pass. Claim the 2nd cluster as a separate extent.
+ */
+ if (alloc > len) {
+ ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+ &len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
}
- if (le64_to_cpu(de->inode)) {
- brelse(bh);
- return 0;
+ blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+
+ ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
+ len, 0, NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
}
- offset += le16_to_cpu(de->rec_len);
- de = (struct ocfs2_dir_entry *)
- ((char *)de + le16_to_cpu(de->rec_len));
}
- brelse(bh);
- return 1;
+
+ *first_block_bh = dirdata_bh;
+ dirdata_bh = NULL;
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+
+out_sem:
+ up_write(&oi->ip_alloc_sem);
+
+out:
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+
+ brelse(dirdata_bh);
+
+ return ret;
}
/* returns a bh of the 1st new block in the allocation. */
-int ocfs2_do_extend_dir(struct super_block *sb,
- handle_t *handle,
- struct inode *dir,
- struct buffer_head *parent_fe_bh,
- struct ocfs2_alloc_context *data_ac,
- struct ocfs2_alloc_context *meta_ac,
- struct buffer_head **new_bh)
+static int ocfs2_do_extend_dir(struct super_block *sb,
+ handle_t *handle,
+ struct inode *dir,
+ struct buffer_head *parent_fe_bh,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ struct buffer_head **new_bh)
{
int status;
int extend;
@@ -396,10 +1408,18 @@ bail:
return status;
}
-/* assumes you already have a cluster lock on the directory. */
+/*
+ * Assumes you already have a cluster lock on the directory.
+ *
+ * 'blocks_wanted' is only used if we have an inline directory which
+ * is to be turned into an extent based one. The size of the dirent to
+ * insert might be larger than the space gained by growing to just one
+ * block, so we may have to grow the inode by two blocks in that case.
+ */
static int ocfs2_extend_dir(struct ocfs2_super *osb,
struct inode *dir,
struct buffer_head *parent_fe_bh,
+ unsigned int blocks_wanted,
struct buffer_head **new_de_bh)
{
int status = 0;
@@ -415,6 +1435,38 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
mlog_entry_void();
+ if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ status = ocfs2_expand_inline_dir(dir, parent_fe_bh,
+ blocks_wanted, &new_bh);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }
+
+ if (blocks_wanted == 1) {
+ /*
+ * If the new dirent will fit inside the space
+ * created by pushing out to one block, then
+ * we can complete the operation
+ * here. Otherwise we have to expand i_size
+ * and format the 2nd block below.
+ */
+ BUG_ON(new_bh == NULL);
+ goto bail_bh;
+ }
+
+ /*
+ * Get rid of 'new_bh' - we want to format the 2nd
+ * data block and return that instead.
+ */
+ brelse(new_bh);
+ new_bh = NULL;
+
+ dir_i_size = i_size_read(dir);
+ credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+ goto do_extend;
+ }
+
dir_i_size = i_size_read(dir);
mlog(0, "extending dir %llu (i_size = %lld)\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
@@ -452,6 +1504,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
}
+do_extend:
down_write(&OCFS2_I(dir)->ip_alloc_sem);
drop_alloc_sem = 1;
@@ -497,6 +1550,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
goto bail;
}
+bail_bh:
*new_de_bh = new_bh;
get_bh(*new_de_bh);
bail:
@@ -517,41 +1571,71 @@ bail:
return status;
}
-/*
- * Search the dir for a good spot, extending it if necessary. The
- * block containing an appropriate record is returned in ret_de_bh.
- */
-int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
- struct inode *dir,
- struct buffer_head *parent_fe_bh,
- const char *name,
- int namelen,
- struct buffer_head **ret_de_bh)
+static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
+ const char *name, int namelen,
+ struct buffer_head **ret_de_bh,
+ unsigned int *blocks_wanted)
{
- unsigned long offset;
- struct buffer_head * bh = NULL;
- unsigned short rec_len;
- struct ocfs2_dinode *fe;
- struct ocfs2_dir_entry *de;
- struct super_block *sb;
- int status;
+ int ret;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_dir_entry *de, *last_de = NULL;
+ char *de_buf, *limit;
+ unsigned long offset = 0;
+ unsigned int rec_len, new_rec_len;
+
+ de_buf = di->id2.i_data.id_data;
+ limit = de_buf + i_size_read(dir);
+ rec_len = OCFS2_DIR_REC_LEN(namelen);
- mlog_entry_void();
+ while (de_buf < limit) {
+ de = (struct ocfs2_dir_entry *)de_buf;
- mlog(0, "getting ready to insert namelen %d into dir %llu\n",
- namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+ if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) {
+ ret = -ENOENT;
+ goto out;
+ }
+ if (ocfs2_match(namelen, name, de)) {
+ ret = -EEXIST;
+ goto out;
+ }
+ if (ocfs2_dirent_would_fit(de, rec_len)) {
+ /* Ok, we found a spot. Return this bh and let
+ * the caller actually fill it in. */
+ *ret_de_bh = di_bh;
+ get_bh(*ret_de_bh);
+ ret = 0;
+ goto out;
+ }
- BUG_ON(!S_ISDIR(dir->i_mode));
- fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
- BUG_ON(le64_to_cpu(fe->i_size) != i_size_read(dir));
+ last_de = de;
+ de_buf += le16_to_cpu(de->rec_len);
+ offset += le16_to_cpu(de->rec_len);
+ }
- sb = dir->i_sb;
+ /*
+ * We're going to require expansion of the directory - figure
+ * out how many blocks we'll need so that a place for the
+ * dirent can be found.
+ */
+ *blocks_wanted = 1;
+ new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir));
+ if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len)))
+ *blocks_wanted = 2;
+
+ ret = -ENOSPC;
+out:
+ return ret;
+}
- if (!namelen) {
- status = -EINVAL;
- mlog_errno(status);
- goto bail;
- }
+static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
+ int namelen, struct buffer_head **ret_de_bh)
+{
+ unsigned long offset;
+ struct buffer_head *bh = NULL;
+ unsigned short rec_len;
+ struct ocfs2_dir_entry *de;
+ struct super_block *sb = dir->i_sb;
+ int status;
bh = ocfs2_bread(dir, 0, &status, 0);
if (!bh) {
@@ -568,17 +1652,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
bh = NULL;
if (i_size_read(dir) <= offset) {
- status = ocfs2_extend_dir(osb,
- dir,
- parent_fe_bh,
- &bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- BUG_ON(!bh);
- *ret_de_bh = bh;
- get_bh(*ret_de_bh);
+ /*
+ * Caller will have to expand this
+ * directory.
+ */
+ status = -ENOSPC;
goto bail;
}
bh = ocfs2_bread(dir,
@@ -600,10 +1678,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
status = -EEXIST;
goto bail;
}
- if (((le64_to_cpu(de->inode) == 0) &&
- (le16_to_cpu(de->rec_len) >= rec_len)) ||
- (le16_to_cpu(de->rec_len) >=
- (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
+ if (ocfs2_dirent_would_fit(de, rec_len)) {
/* Ok, we found a spot. Return this bh and let
* the caller actually fill it in. */
*ret_de_bh = bh;
@@ -623,3 +1698,61 @@ bail:
mlog_exit(status);
return status;
}
+
+int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
+ struct inode *dir,
+ struct buffer_head *parent_fe_bh,
+ const char *name,
+ int namelen,
+ struct buffer_head **ret_de_bh)
+{
+ int ret;
+ unsigned int blocks_wanted = 1;
+ struct buffer_head *bh = NULL;
+
+ mlog(0, "getting ready to insert namelen %d into dir %llu\n",
+ namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+
+ *ret_de_bh = NULL;
+
+ if (!namelen) {
+ ret = -EINVAL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name,
+ namelen, &bh, &blocks_wanted);
+ } else
+ ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh);
+
+ if (ret && ret != -ENOSPC) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (ret == -ENOSPC) {
+ /*
+ * We have to expand the directory to add this name.
+ */
+ BUG_ON(bh);
+
+ ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted,
+ &bh);
+ if (ret) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto out;
+ }
+
+ BUG_ON(!bh);
+ }
+
+ *ret_de_bh = bh;
+ bh = NULL;
+out:
+ if (bh)
+ brelse(bh);
+ return ret;
+}
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h
index 3f67e146864..ce48b9080d8 100644
--- a/fs/ocfs2/dir.h
+++ b/fs/ocfs2/dir.h
@@ -26,17 +26,49 @@
#ifndef OCFS2_DIR_H
#define OCFS2_DIR_H
+struct buffer_head *ocfs2_find_entry(const char *name,
+ int namelen,
+ struct inode *dir,
+ struct ocfs2_dir_entry **res_dir);
+int ocfs2_delete_entry(handle_t *handle,
+ struct inode *dir,
+ struct ocfs2_dir_entry *de_del,
+ struct buffer_head *bh);
+int __ocfs2_add_entry(handle_t *handle,
+ struct inode *dir,
+ const char *name, int namelen,
+ struct inode *inode, u64 blkno,
+ struct buffer_head *parent_fe_bh,
+ struct buffer_head *insert_bh);
+static inline int ocfs2_add_entry(handle_t *handle,
+ struct dentry *dentry,
+ struct inode *inode, u64 blkno,
+ struct buffer_head *parent_fe_bh,
+ struct buffer_head *insert_bh)
+{
+ return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
+ dentry->d_name.name, dentry->d_name.len,
+ inode, blkno, parent_fe_bh, insert_bh);
+}
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+ struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+ struct inode *new_entry_inode);
+
int ocfs2_check_dir_for_entry(struct inode *dir,
const char *name,
int namelen);
-int ocfs2_empty_dir(struct inode *inode); /* FIXME: to namei.c */
+int ocfs2_empty_dir(struct inode *inode);
int ocfs2_find_files_on_disk(const char *name,
int namelen,
u64 *blkno,
struct inode *inode,
struct buffer_head **dirent_bh,
struct ocfs2_dir_entry **dirent);
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+ int namelen, u64 *blkno);
int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir);
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+ filldir_t filldir);
int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
struct inode *dir,
struct buffer_head *parent_fe_bh,
@@ -44,11 +76,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
int namelen,
struct buffer_head **ret_de_bh);
struct ocfs2_alloc_context;
-int ocfs2_do_extend_dir(struct super_block *sb,
- handle_t *handle,
- struct inode *dir,
- struct buffer_head *parent_fe_bh,
- struct ocfs2_alloc_context *data_ac,
- struct ocfs2_alloc_context *meta_ac,
- struct buffer_head **new_bh);
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+ handle_t *handle,
+ struct inode *parent,
+ struct inode *inode,
+ struct buffer_head *fe_bh,
+ struct ocfs2_alloc_context *data_ac);
+
#endif /* OCFS2_DIR_H */
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index f71250ed166..41c76ff2fcf 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -1482,6 +1482,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
lvb->lvb_imtime_packed =
cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
lvb->lvb_iattr = cpu_to_be32(oi->ip_attr);
+ lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features);
lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
out:
@@ -1515,6 +1516,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
i_size_write(inode, be64_to_cpu(lvb->lvb_isize));
oi->ip_attr = be32_to_cpu(lvb->lvb_iattr);
+ oi->ip_dyn_features = be16_to_cpu(lvb->lvb_idynfeatures);
ocfs2_set_inode_flags(inode);
/* fast-symlinks are a special case */
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
index 492bad32a8c..87a785e4120 100644
--- a/fs/ocfs2/dlmglue.h
+++ b/fs/ocfs2/dlmglue.h
@@ -29,12 +29,12 @@
#include "dcache.h"
-#define OCFS2_LVB_VERSION 4
+#define OCFS2_LVB_VERSION 5
struct ocfs2_meta_lvb {
__u8 lvb_version;
__u8 lvb_reserved0;
- __be16 lvb_reserved1;
+ __be16 lvb_idynfeatures;
__be32 lvb_iclusters;
__be32 lvb_iuid;
__be32 lvb_igid;
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index bc48177bd18..c3bbc198f9c 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -88,8 +88,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
struct dentry *parent;
struct inode *inode;
struct inode *dir = child->d_inode;
- struct buffer_head *dirent_bh = NULL;
- struct ocfs2_dir_entry *dirent;
mlog_entry("(0x%p, '%.*s')\n", child,
child->d_name.len, child->d_name.name);
@@ -105,8 +103,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
goto bail;
}
- status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh,
- &dirent);
+ status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
if (status < 0) {
parent = ERR_PTR(-ENOENT);
goto bail_unlock;
@@ -131,9 +128,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
bail_unlock:
ocfs2_meta_unlock(dir, 0);
- if (dirent_bh)
- brelse(dirent_bh);
-
bail:
mlog_exit_ptr(parent);
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index 03c1d365c78..c58668a326f 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -387,6 +387,12 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
struct ocfs2_extent_rec *rec;
u32 coff;
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ ret = -ERANGE;
+ mlog_errno(ret);
+ goto out;
+ }
+
ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
num_clusters, extent_flags);
if (ret == 0)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index f3bc3658e7a..a62b14eb406 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -397,6 +397,15 @@ static int ocfs2_truncate_file(struct inode *inode,
unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(inode->i_mapping, new_i_size);
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ status = ocfs2_truncate_inline(inode, di_bh, new_i_size,
+ i_size_read(inode), 0);
+ if (status)
+ mlog_errno(status);
+
+ goto bail_unlock_data;
+ }
+
/* alright, we're going to need to do a full blown alloc size
* change. Orphan the inode so that recovery can complete the
* truncate if necessary. This does the task of marking
@@ -779,25 +788,6 @@ leave:
return status;
}
-static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
- u32 clusters_to_add, int mark_unwritten)
-{
- int ret;
-
- /*
- * The alloc sem blocks peope in read/write from reading our
- * allocation until we're done changing it. We depend on
- * i_mutex to block other extend/truncate calls while we're
- * here.
- */
- down_write(&OCFS2_I(inode)->ip_alloc_sem);
- ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add,
- mark_unwritten);
- up_write(&OCFS2_I(inode)->ip_alloc_sem);
-
- return ret;
-}
-
/* Some parts of this taken from generic_cont_expand, which turned out
* to be too fragile to do exactly what we need without us having to
* worry about recursive locking in ->prepare_write() and
@@ -889,25 +879,48 @@ out:
return ret;
}
-/*
- * A tail_to_skip value > 0 indicates that we're being called from
- * ocfs2_file_aio_write(). This has the following implications:
- *
- * - we don't want to update i_size
- * - di_bh will be NULL, which is fine because it's only used in the
- * case where we want to update i_size.
- * - ocfs2_zero_extend() will then only be filling the hole created
- * between i_size and the start of the write.
- */
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
+{
+ int ret;
+ u32 clusters_to_add;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+ clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
+ if (clusters_to_add < oi->ip_clusters)
+ clusters_to_add = 0;
+ else
+ clusters_to_add -= oi->ip_clusters;
+
+ if (clusters_to_add) {
+ ret = __ocfs2_extend_allocation(inode, oi->ip_clusters,
+ clusters_to_add, 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ /*
+ * Call this even if we don't add any clusters to the tree. We
+ * still need to zero the area between the old i_size and the
+ * new i_size.
+ */
+ ret = ocfs2_zero_extend(inode, zero_to);
+ if (ret < 0)
+ mlog_errno(ret);
+
+out:
+ return ret;
+}
+
static int ocfs2_extend_file(struct inode *inode,
struct buffer_head *di_bh,
- u64 new_i_size,
- size_t tail_to_skip)
+ u64 new_i_size)
{
- int ret = 0;
- u32 clusters_to_add = 0;
+ int ret = 0, data_locked = 0;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
- BUG_ON(!tail_to_skip && !di_bh);
+ BUG_ON(!di_bh);
/* setattr sometimes calls us like this. */
if (new_i_size == 0)
@@ -917,13 +930,18 @@ static int ocfs2_extend_file(struct inode *inode,
goto out;
BUG_ON(new_i_size < i_size_read(inode));
- if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
- BUG_ON(tail_to_skip != 0);
+ /*
+ * Fall through for converting inline data, even if the fs
+ * supports sparse files.
+ *
+ * The check for inline data here is legal - nobody can add
+ * the feature since we have i_mutex. We must check it again
+ * after acquiring ip_alloc_sem though, as paths like mmap
+ * might have raced us to converting the inode to extents.
+ */
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
goto out_update_size;
- }
-
- clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) -
- OCFS2_I(inode)->ip_clusters;
/*
* protect the pages that ocfs2_zero_extend is going to be
@@ -937,39 +955,52 @@ static int ocfs2_extend_file(struct inode *inode,
mlog_errno(ret);
goto out;
}
+ data_locked = 1;
+
+ /*
+ * The alloc sem blocks people in read/write from reading our
+ * allocation until we're done changing it. We depend on
+ * i_mutex to block other extend/truncate calls while we're
+ * here.
+ */
+ down_write(&oi->ip_alloc_sem);
+
+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ /*
+ * We can optimize small extends by keeping the inodes
+ * inline data.
+ */
+ if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) {
+ up_write(&oi->ip_alloc_sem);
+ goto out_update_size;
+ }
+
+ ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+ if (ret) {
+ up_write(&oi->ip_alloc_sem);
- if (clusters_to_add) {
- ret = ocfs2_extend_allocation(inode,
- OCFS2_I(inode)->ip_clusters,
- clusters_to_add, 0);
- if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
}
}
- /*
- * Call this even if we don't add any clusters to the tree. We
- * still need to zero the area between the old i_size and the
- * new i_size.
- */
- ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+ if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+ ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size);
+
+ up_write(&oi->ip_alloc_sem);
+
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
}
out_update_size:
- if (!tail_to_skip) {
- /* We're being called from ocfs2_setattr() which wants
- * us to update i_size */
- ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
- if (ret < 0)
- mlog_errno(ret);
- }
+ ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
+ if (ret < 0)
+ mlog_errno(ret);
out_unlock:
- if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+ if (data_locked)
ocfs2_data_unlock(inode, 1);
out:
@@ -1035,7 +1066,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (i_size_read(inode) > attr->ia_size)
status = ocfs2_truncate_file(inode, bh, attr->ia_size);
else
- status = ocfs2_extend_file(inode, bh, attr->ia_size, 0);
+ status = ocfs2_extend_file(inode, bh, attr->ia_size);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -1243,6 +1274,31 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode,
{
int ret;
u32 cpos, phys_cpos, clusters, alloc_size;
+ u64 end = start + len;
+ struct buffer_head *di_bh = NULL;
+
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+ OCFS2_I(inode)->ip_blkno, &di_bh,
+ OCFS2_BH_CACHED, inode);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Nothing to do if the requested reservation range
+ * fits within the inode.
+ */
+ if (ocfs2_size_fits_inline_data(di_bh, end))
+ goto out;
+
+ ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
/*
* We consider both start and len to be inclusive.
@@ -1288,6 +1344,8 @@ next:
ret = 0;
out:
+
+ brelse(di_bh);
return ret;
}
@@ -1469,6 +1527,14 @@ static int ocfs2_remove_inode_range(struct inode *inode,
if (byte_len == 0)
return 0;
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ ret = ocfs2_truncate_inline(inode, di_bh, byte_start,
+ byte_start + byte_len, 1);
+ if (ret)
+ mlog_errno(ret);
+ return ret;
+ }
+
trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
if (trunc_len >= trunc_start)
@@ -1713,15 +1779,13 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
int appending,
int *direct_io)
{
- int ret = 0, meta_level = appending;
+ int ret = 0, meta_level = 0;
struct inode *inode = dentry->d_inode;
- u32 clusters;
- loff_t newsize, saved_pos;
+ loff_t saved_pos, end;
/*
- * We sample i_size under a read level meta lock to see if our write
- * is extending the file, if it is we back off and get a write level
- * meta lock.
+ * We start with a read level meta lock and only jump to an ex
+ * if we need to make modifications here.
*/
for(;;) {
ret = ocfs2_meta_lock(inode, NULL, meta_level);
@@ -1763,87 +1827,47 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
saved_pos = *ppos;
}
- if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
- loff_t end = saved_pos + count;
+ end = saved_pos + count;
- /*
- * Skip the O_DIRECT checks if we don't need
- * them.
- */
- if (!direct_io || !(*direct_io))
- break;
-
- /*
- * Allowing concurrent direct writes means
- * i_size changes wouldn't be synchronized, so
- * one node could wind up truncating another
- * nodes writes.
- */
- if (end > i_size_read(inode)) {
- *direct_io = 0;
- break;
- }
-
- /*
- * We don't fill holes during direct io, so
- * check for them here. If any are found, the
- * caller will have to retake some cluster
- * locks and initiate the io as buffered.
- */
- ret = ocfs2_check_range_for_holes(inode, saved_pos,
- count);
- if (ret == 1) {
- *direct_io = 0;
- ret = 0;
- } else if (ret < 0)
- mlog_errno(ret);
+ /*
+ * Skip the O_DIRECT checks if we don't need
+ * them.
+ */
+ if (!direct_io || !(*direct_io))
break;
- }
/*
- * The rest of this loop is concerned with legacy file
- * systems which don't support sparse files.
+ * There's no sane way to do direct writes to an inode
+ * with inline data.
*/
-
- newsize = count + saved_pos;
-
- mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
- (long long) saved_pos, (long long) newsize,
- (long long) i_size_read(inode));
-
- /* No need for a higher level metadata lock if we're
- * never going past i_size. */
- if (newsize <= i_size_read(inode))
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ *direct_io = 0;
break;
-
- if (meta_level == 0) {
- ocfs2_meta_unlock(inode, meta_level);
- meta_level = 1;
- continue;
}
- spin_lock(&OCFS2_I(inode)->ip_lock);
- clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) -
- OCFS2_I(inode)->ip_clusters;
- spin_unlock(&OCFS2_I(inode)->ip_lock);
-
- mlog(0, "Writing at EOF, may need more allocation: "
- "i_size = %lld, newsize = %lld, need %u clusters\n",
- (long long) i_size_read(inode), (long long) newsize,
- clusters);
-
- /* We only want to continue the rest of this loop if
- * our extend will actually require more
- * allocation. */
- if (!clusters)
+ /*
+ * Allowing concurrent direct writes means
+ * i_size changes wouldn't be synchronized, so
+ * one node could wind up truncating another
+ * nodes writes.
+ */
+ if (end > i_size_read(inode)) {
+ *direct_io = 0;
break;
-
- ret = ocfs2_extend_file(inode, NULL, newsize, count);
- if (ret < 0) {
- if (ret != -ENOSPC)
- mlog_errno(ret);
- goto out_unlock;
}
+
+ /*
+ * We don't fill holes during direct io, so
+ * check for them here. If any are found, the
+ * caller will have to retake some cluster
+ * locks and initiate the io as buffered.
+ */
+ ret = ocfs2_check_range_for_holes(inode, saved_pos, count);
+ if (ret == 1) {
+ *direct_io = 0;
+ ret = 0;
+ } else if (ret < 0)
+ mlog_errno(ret);
break;
}
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 36fe27f268e..066f14add3a 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -47,6 +47,8 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
struct ocfs2_alloc_context *data_ac,
struct ocfs2_alloc_context *meta_ac,
enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
+ u64 zero_to);
int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
u32 clusters_to_add, u32 extents_to_split,
struct ocfs2_alloc_context **data_ac,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index c53a6763bbb..1d5e0cb0fda 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -241,6 +241,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+ OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
inode->i_version = 1;
inode->i_generation = le32_to_cpu(fe->i_generation);
@@ -513,6 +514,10 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
fe = (struct ocfs2_dinode *) fe_bh->b_data;
+ /*
+ * This check will also skip truncate of inodes with inline
+ * data and fast symlinks.
+ */
if (fe->i_clusters) {
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
@@ -1220,6 +1225,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
ocfs2_get_inode_flags(OCFS2_I(inode));
fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
+ fe->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features);
spin_unlock(&OCFS2_I(inode)->ip_lock);
fe->i_size = cpu_to_le64(i_size_read(inode));
@@ -1257,6 +1263,7 @@ void ocfs2_refresh_inode(struct inode *inode,
OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+ OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
ocfs2_set_inode_flags(inode);
i_size_write(inode, le64_to_cpu(fe->i_size));
inode->i_nlink = le16_to_cpu(fe->i_links_count);
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index a41d0817121..70e881c5553 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -51,6 +51,7 @@ struct ocfs2_inode_info
u32 ip_flags; /* see below */
u32 ip_attr; /* inode attributes */
+ u16 ip_dyn_features;
/* protected by recovery_lock. */
struct inode *ip_next_orphan;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index dbfb20bb27e..f9d01e25298 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -35,13 +35,13 @@
#include "ocfs2.h"
#include "alloc.h"
+#include "dir.h"
#include "dlmglue.h"
#include "extent_map.h"
#include "heartbeat.h"
#include "inode.h"
#include "journal.h"
#include "localalloc.h"
-#include "namei.h"
#include "slot_map.h"
#include "super.h"
#include "vote.h"
@@ -1213,17 +1213,49 @@ bail:
return status;
}
+struct ocfs2_orphan_filldir_priv {
+ struct inode *head;
+ struct ocfs2_super *osb;
+};
+
+static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
+ loff_t pos, u64 ino, unsigned type)
+{
+ struct ocfs2_orphan_filldir_priv *p = priv;
+ struct inode *iter;
+
+ if (name_len == 1 && !strncmp(".", name, 1))
+ return 0;
+ if (name_len == 2 && !strncmp("..", name, 2))
+ return 0;
+
+ /* Skip bad inodes so that recovery can continue */
+ iter = ocfs2_iget(p->osb, ino,
+ OCFS2_FI_FLAG_ORPHAN_RECOVERY);
+ if (IS_ERR(iter))
+ return 0;
+
+ mlog(0, "queue orphan %llu\n",
+ (unsigned long long)OCFS2_I(iter)->ip_blkno);
+ /* No locking is required for the next_orphan queue as there
+ * is only ever a single process doing orphan recovery. */
+ OCFS2_I(iter)->ip_next_orphan = p->head;
+ p->head = iter;
+
+ return 0;
+}
+
static int ocfs2_queue_orphans(struct ocfs2_super *osb,
int slot,
struct inode **head)
{
int status;
struct inode *orphan_dir_inode = NULL;
- struct inode *iter;
- unsigned long offset, blk, local;
- struct buffer_head *bh = NULL;
- struct ocfs2_dir_entry *de;
- struct super_block *sb = osb->sb;
+ struct ocfs2_orphan_filldir_priv priv;
+ loff_t pos = 0;
+
+ priv.osb = osb;
+ priv.head = *head;
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
@@ -1241,77 +1273,15 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
goto out;
}
- offset = 0;
- iter = NULL;
- while(offset < i_size_read(orphan_dir_inode)) {
- blk = offset >> sb->s_blocksize_bits;
-
- bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0);
- if (!bh)
- status = -EINVAL;
- if (status < 0) {
- if (bh)
- brelse(bh);
- mlog_errno(status);
- goto out_unlock;
- }
-
- local = 0;
- while(offset < i_size_read(orphan_dir_inode)
- && local < sb->s_blocksize) {
- de = (struct ocfs2_dir_entry *) (bh->b_data + local);
-
- if (!ocfs2_check_dir_entry(orphan_dir_inode,
- de, bh, local)) {
- status = -EINVAL;
- mlog_errno(status);
- brelse(bh);
- goto out_unlock;
- }
-
- local += le16_to_cpu(de->rec_len);
- offset += le16_to_cpu(de->rec_len);
-
- /* I guess we silently fail on no inode? */
- if (!le64_to_cpu(de->inode))
- continue;
- if (de->file_type > OCFS2_FT_MAX) {
- mlog(ML_ERROR,
- "block %llu contains invalid de: "
- "inode = %llu, rec_len = %u, "
- "name_len = %u, file_type = %u, "
- "name='%.*s'\n",
- (unsigned long long)bh->b_blocknr,
- (unsigned long long)le64_to_cpu(de->inode),
- le16_to_cpu(de->rec_len),
- de->name_len,
- de->file_type,
- de->name_len,
- de->name);
- continue;
- }
- if (de->name_len == 1 && !strncmp(".", de->name, 1))
- continue;
- if (de->name_len == 2 && !strncmp("..", de->name, 2))
- continue;
-
- iter = ocfs2_iget(osb, le64_to_cpu(de->inode),
- OCFS2_FI_FLAG_ORPHAN_RECOVERY);
- if (IS_ERR(iter))
- continue;
-
- mlog(0, "queue orphan %llu\n",
- (unsigned long long)OCFS2_I(iter)->ip_blkno);
- /* No locking is required for the next_orphan
- * queue as there is only ever a single
- * process doing orphan recovery. */
- OCFS2_I(iter)->ip_next_orphan = *head;
- *head = iter;
- }
- brelse(bh);
+ status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv,
+ ocfs2_orphan_filldir);
+ if (status) {
+ mlog_errno(status);
+ goto out;
}
-out_unlock:
+ *head = priv.head;
+
ocfs2_meta_unlock(orphan_dir_inode, 0);
out:
mutex_unlock(&orphan_dir_inode->i_mutex);
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index ce60aab013a..4b32e096156 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -282,6 +282,9 @@ int ocfs2_journal_dirty_data(handle_t *handle,
* prev. group desc. if we relink. */
#define OCFS2_SUBALLOC_ALLOC (3)
+#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC \
+ + OCFS2_INODE_UPDATE_CREDITS)
+
/* dinode + group descriptor update. We don't relink on free yet. */
#define OCFS2_SUBALLOC_FREE (2)
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 701e6d04ed5..729259016c1 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -64,29 +64,6 @@
#include "buffer_head_io.h"
-#define NAMEI_RA_CHUNKS 2
-#define NAMEI_RA_BLOCKS 4
-#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
-
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
- struct inode *dir,
- const char *name, int namelen,
- unsigned long offset,
- struct ocfs2_dir_entry **res_dir);
-
-static int ocfs2_delete_entry(handle_t *handle,
- struct inode *dir,
- struct ocfs2_dir_entry *de_del,
- struct buffer_head *bh);
-
-static int __ocfs2_add_entry(handle_t *handle,
- struct inode *dir,
- const char *name, int namelen,
- struct inode *inode, u64 blkno,
- struct buffer_head *parent_fe_bh,
- struct buffer_head *insert_bh);
-
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
struct inode *dir,
struct dentry *dentry, int mode,
@@ -97,13 +74,6 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
struct inode **ret_inode,
struct ocfs2_alloc_context *inode_ac);
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
- handle_t *handle,
- struct inode *parent,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_alloc_context *data_ac);
-
static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
struct inode **ret_orphan_dir,
struct inode *inode,
@@ -123,17 +93,6 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
struct inode *inode,
const char *symname);
-static inline int ocfs2_add_entry(handle_t *handle,
- struct dentry *dentry,
- struct inode *inode, u64 blkno,
- struct buffer_head *parent_fe_bh,
- struct buffer_head *insert_bh)
-{
- return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
- dentry->d_name.name, dentry->d_name.len,
- inode, blkno, parent_fe_bh, insert_bh);
-}
-
/* An orphan dir name is an 8 byte value, printed as a hex string */
#define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
@@ -142,10 +101,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
{
int status;
u64 blkno;
- struct buffer_head *dirent_bh = NULL;
struct inode *inode = NULL;
struct dentry *ret;
- struct ocfs2_dir_entry *dirent;
struct ocfs2_inode_info *oi;
mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
@@ -167,9 +124,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
goto bail;
}
- status = ocfs2_find_files_on_disk(dentry->d_name.name,
- dentry->d_name.len, &blkno,
- dir, &dirent_bh, &dirent);
+ status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name,
+ dentry->d_name.len, &blkno);
if (status < 0)
goto bail_add;
@@ -224,83 +180,12 @@ bail_unlock:
ocfs2_meta_unlock(dir, 0);
bail:
- if (dirent_bh)
- brelse(dirent_bh);
mlog_exit_ptr(ret);
return ret;
}
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
- handle_t *handle,
- struct inode *parent,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_alloc_context *data_ac)
-{
- int status;
- struct buffer_head *new_bh = NULL;
- struct ocfs2_dir_entry *de = NULL;
-
- mlog_entry_void();
-
- status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
- data_ac, NULL, &new_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
-
- ocfs2_set_new_buffer_uptodate(inode, new_bh);
-
- status = ocfs2_journal_access(handle, inode, new_bh,
- OCFS2_JOURNAL_ACCESS_CREATE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- memset(new_bh->b_data, 0, osb->sb->s_blocksize);
-
- de = (struct ocfs2_dir_entry *) new_bh->b_data;
- de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
- de->name_len = 1;
- de->rec_len =
- cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
- strcpy(de->name, ".");
- ocfs2_set_de_type(de, S_IFDIR);
- de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
- de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
- de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize -
- OCFS2_DIR_REC_LEN(1));
- de->name_len = 2;
- strcpy(de->name, "..");
- ocfs2_set_de_type(de, S_IFDIR);
-
- status = ocfs2_journal_dirty(handle, new_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
-
- i_size_write(inode, inode->i_sb->s_blocksize);
- inode->i_nlink = 2;
- inode->i_blocks = ocfs2_inode_sector_count(inode);
- status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
-
- status = 0;
-bail:
- if (new_bh)
- brelse(new_bh);
-
- mlog_exit(status);
- return status;
-}
-
static int ocfs2_mknod(struct inode *dir,
struct dentry *dentry,
int mode,
@@ -365,9 +250,8 @@ static int ocfs2_mknod(struct inode *dir,
goto leave;
}
- /* are we making a directory? If so, reserve a cluster for his
- * 1st extent. */
- if (S_ISDIR(mode)) {
+ /* Reserve a cluster if creating an extent based directory. */
+ if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
status = ocfs2_reserve_clusters(osb, 1, &data_ac);
if (status < 0) {
if (status != -ENOSPC)
@@ -564,10 +448,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
cpu_to_le32(CURRENT_TIME.tv_nsec);
fe->i_dtime = 0;
- fel = &fe->id2.i_list;
- fel->l_tree_depth = 0;
- fel->l_next_free_rec = 0;
- fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+ /*
+ * If supported, directories start with inline data.
+ */
+ if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {
+ u16 feat = le16_to_cpu(fe->i_dyn_features);
+
+ fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
+
+ fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));
+ } else {
+ fel = &fe->id2.i_list;
+ fel->l_tree_depth = 0;
+ fel->l_next_free_rec = 0;
+ fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+ }
status = ocfs2_journal_dirty(handle, *new_fe_bh);
if (status < 0) {
@@ -1048,11 +943,6 @@ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
ocfs2_meta_unlock(inode2, 1);
}
-#define PARENT_INO(buffer) \
- ((struct ocfs2_dir_entry *) \
- ((char *)buffer + \
- le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode
-
static int ocfs2_rename(struct inode *old_dir,
struct dentry *old_dentry,
struct inode *new_dir,
@@ -1070,12 +960,12 @@ static int ocfs2_rename(struct inode *old_dir,
struct buffer_head *old_inode_bh = NULL;
struct buffer_head *insert_entry_bh = NULL;
struct ocfs2_super *osb = NULL;
- u64 newfe_blkno;
+ u64 newfe_blkno, old_de_ino;
handle_t *handle = NULL;
struct buffer_head *old_dir_bh = NULL;
struct buffer_head *new_dir_bh = NULL;
- struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry
- // and new_dentry
+ struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL,
+ *new_de = NULL;
struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
// this is the 1st dirent bh
@@ -1159,27 +1049,35 @@ static int ocfs2_rename(struct inode *old_dir,
}
if (S_ISDIR(old_inode->i_mode)) {
- status = -EIO;
- old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
- if (!old_inode_de_bh)
+ u64 old_inode_parent;
+
+ status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent,
+ old_inode, &old_inode_de_bh,
+ &old_inode_dot_dot_de);
+ if (status) {
+ status = -EIO;
goto bail;
+ }
- status = -EIO;
- if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) !=
- OCFS2_I(old_dir)->ip_blkno)
+ if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) {
+ status = -EIO;
goto bail;
- status = -EMLINK;
- if (!new_inode && new_dir!=old_dir &&
- new_dir->i_nlink >= OCFS2_LINK_MAX)
+ }
+
+ if (!new_inode && new_dir != old_dir &&
+ new_dir->i_nlink >= OCFS2_LINK_MAX) {
+ status = -EMLINK;
goto bail;
+ }
}
- status = -ENOENT;
- old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
- old_dentry->d_name.len,
- old_dir, &old_de);
- if (!old_de_bh)
+ status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
+ old_dentry->d_name.len,
+ &old_de_ino);
+ if (status) {
+ status = -ENOENT;
goto bail;
+ }
/*
* Check for inode number is _not_ due to possible IO errors.
@@ -1187,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir,
* and merrily kill the link to whatever was created under the
* same name. Goodbye sticky bit ;-<
*/
- if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno)
+ if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) {
+ status = -ENOENT;
goto bail;
+ }
/* check if the target already exists (in which case we need
* to delete it */
@@ -1321,20 +1221,13 @@ static int ocfs2_rename(struct inode *old_dir,
}
/* change the dirent to point to the correct inode */
- status = ocfs2_journal_access(handle, new_dir, new_de_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
+ status = ocfs2_update_entry(new_dir, handle, new_de_bh,
+ new_de, old_inode);
if (status < 0) {
mlog_errno(status);
goto bail;
}
- new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno);
- new_de->file_type = old_de->file_type;
new_dir->i_version++;
- status = ocfs2_journal_dirty(handle, new_de_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
if (S_ISDIR(new_inode->i_mode))
newfe->i_links_count = 0;
@@ -1370,7 +1263,21 @@ static int ocfs2_rename(struct inode *old_dir,
} else
mlog_errno(status);
- /* now that the name has been added to new_dir, remove the old name */
+ /*
+ * Now that the name has been added to new_dir, remove the old name.
+ *
+ * We don't keep any directory entry context around until now
+ * because the insert might have changed the type of directory
+ * we're dealing with.
+ */
+ old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
+ old_dentry->d_name.len,
+ old_dir, &old_de);
+ if (!old_de_bh) {
+ status = -EIO;
+ goto bail;
+ }
+
status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
if (status < 0) {
mlog_errno(status);
@@ -1383,12 +1290,8 @@ static int ocfs2_rename(struct inode *old_dir,
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
if (old_inode_de_bh) {
- status = ocfs2_journal_access(handle, old_inode,
- old_inode_de_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- PARENT_INO(old_inode_de_bh->b_data) =
- cpu_to_le64(OCFS2_I(new_dir)->ip_blkno);
- status = ocfs2_journal_dirty(handle, old_inode_de_bh);
+ status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh,
+ old_inode_dot_dot_de, new_dir);
old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;
@@ -1767,329 +1670,6 @@ bail:
return status;
}
-int ocfs2_check_dir_entry(struct inode * dir,
- struct ocfs2_dir_entry * de,
- struct buffer_head * bh,
- unsigned long offset)
-{
- const char *error_msg = NULL;
- const int rlen = le16_to_cpu(de->rec_len);
-
- if (rlen < OCFS2_DIR_REC_LEN(1))
- error_msg = "rec_len is smaller than minimal";
- else if (rlen % 4 != 0)
- error_msg = "rec_len % 4 != 0";
- else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
- error_msg = "rec_len is too small for name_len";
- else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
- error_msg = "directory entry across blocks";
-
- if (error_msg != NULL)
- mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
- "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
- (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
- offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
- de->name_len);
- return error_msg == NULL ? 1 : 0;
-}
-
-/* we don't always have a dentry for what we want to add, so people
- * like orphan dir can call this instead.
- *
- * If you pass me insert_bh, I'll skip the search of the other dir
- * blocks and put the record in there.
- */
-static int __ocfs2_add_entry(handle_t *handle,
- struct inode *dir,
- const char *name, int namelen,
- struct inode *inode, u64 blkno,
- struct buffer_head *parent_fe_bh,
- struct buffer_head *insert_bh)
-{
- unsigned long offset;
- unsigned short rec_len;
- struct ocfs2_dir_entry *de, *de1;
- struct super_block *sb;
- int retval, status;
-
- mlog_entry_void();
-
- sb = dir->i_sb;
-
- if (!namelen)
- return -EINVAL;
-
- rec_len = OCFS2_DIR_REC_LEN(namelen);
- offset = 0;
- de = (struct ocfs2_dir_entry *) insert_bh->b_data;
- while (1) {
- BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data);
- /* These checks should've already been passed by the
- * prepare function, but I guess we can leave them
- * here anyway. */
- if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
- retval = -ENOENT;
- goto bail;
- }
- if (ocfs2_match(namelen, name, de)) {
- retval = -EEXIST;
- goto bail;
- }
- if (((le64_to_cpu(de->inode) == 0) &&
- (le16_to_cpu(de->rec_len) >= rec_len)) ||
- (le16_to_cpu(de->rec_len) >=
- (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
- if (retval < 0) {
- mlog_errno(retval);
- goto bail;
- }
-
- status = ocfs2_journal_access(handle, dir, insert_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- /* By now the buffer is marked for journaling */
- offset += le16_to_cpu(de->rec_len);
- if (le64_to_cpu(de->inode)) {
- de1 = (struct ocfs2_dir_entry *)((char *) de +
- OCFS2_DIR_REC_LEN(de->name_len));
- de1->rec_len =
- cpu_to_le16(le16_to_cpu(de->rec_len) -
- OCFS2_DIR_REC_LEN(de->name_len));
- de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
- de = de1;
- }
- de->file_type = OCFS2_FT_UNKNOWN;
- if (blkno) {
- de->inode = cpu_to_le64(blkno);
- ocfs2_set_de_type(de, inode->i_mode);
- } else
- de->inode = 0;
- de->name_len = namelen;
- memcpy(de->name, name, namelen);
-
- dir->i_version++;
- status = ocfs2_journal_dirty(handle, insert_bh);
- retval = 0;
- goto bail;
- }
- offset += le16_to_cpu(de->rec_len);
- de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
- }
-
- /* when you think about it, the assert above should prevent us
- * from ever getting here. */
- retval = -ENOSPC;
-bail:
-
- mlog_exit(retval);
- return retval;
-}
-
-
-/*
- * ocfs2_delete_entry deletes a directory entry by merging it with the
- * previous entry
- */
-static int ocfs2_delete_entry(handle_t *handle,
- struct inode *dir,
- struct ocfs2_dir_entry *de_del,
- struct buffer_head *bh)
-{
- struct ocfs2_dir_entry *de, *pde;
- int i, status = -ENOENT;
-
- mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
-
- i = 0;
- pde = NULL;
- de = (struct ocfs2_dir_entry *) bh->b_data;
- while (i < bh->b_size) {
- if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
- status = -EIO;
- mlog_errno(status);
- goto bail;
- }
- if (de == de_del) {
- status = ocfs2_journal_access(handle, dir, bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- status = -EIO;
- mlog_errno(status);
- goto bail;
- }
- if (pde)
- pde->rec_len =
- cpu_to_le16(le16_to_cpu(pde->rec_len) +
- le16_to_cpu(de->rec_len));
- else
- de->inode = 0;
- dir->i_version++;
- status = ocfs2_journal_dirty(handle, bh);
- goto bail;
- }
- i += le16_to_cpu(de->rec_len);
- pde = de;
- de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
- }
-bail:
- mlog_exit(status);
- return status;
-}
-
-/*
- * Returns 0 if not found, -1 on failure, and 1 on success
- */
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
- struct inode *dir,
- const char *name, int namelen,
- unsigned long offset,
- struct ocfs2_dir_entry **res_dir)
-{
- struct ocfs2_dir_entry *de;
- char *dlimit, *de_buf;
- int de_len;
- int ret = 0;
-
- mlog_entry_void();
-
- de_buf = bh->b_data;
- dlimit = de_buf + dir->i_sb->s_blocksize;
-
- while (de_buf < dlimit) {
- /* this code is executed quadratically often */
- /* do minimal checking `by hand' */
-
- de = (struct ocfs2_dir_entry *) de_buf;
-
- if (de_buf + namelen <= dlimit &&
- ocfs2_match(namelen, name, de)) {
- /* found a match - just to be sure, do a full check */
- if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
- ret = -1;
- goto bail;
- }
- *res_dir = de;
- ret = 1;
- goto bail;
- }
-
- /* prevent looping on a bad block */
- de_len = le16_to_cpu(de->rec_len);
- if (de_len <= 0) {
- ret = -1;
- goto bail;
- }
-
- de_buf += de_len;
- offset += de_len;
- }
-
-bail:
- mlog_exit(ret);
- return ret;
-}
-
-struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
- struct inode *dir,
- struct ocfs2_dir_entry **res_dir)
-{
- struct super_block *sb;
- struct buffer_head *bh_use[NAMEI_RA_SIZE];
- struct buffer_head *bh, *ret = NULL;
- unsigned long start, block, b;
- int ra_max = 0; /* Number of bh's in the readahead
- buffer, bh_use[] */
- int ra_ptr = 0; /* Current index into readahead
- buffer */
- int num = 0;
- int nblocks, i, err;
-
- mlog_entry_void();
-
- *res_dir = NULL;
- sb = dir->i_sb;
-
- nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
- start = OCFS2_I(dir)->ip_dir_start_lookup;
- if (start >= nblocks)
- start = 0;
- block = start;
-
-restart:
- do {
- /*
- * We deal with the read-ahead logic here.
- */
- if (ra_ptr >= ra_max) {
- /* Refill the readahead buffer */
- ra_ptr = 0;
- b = block;
- for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
- /*
- * Terminate if we reach the end of the
- * directory and must wrap, or if our
- * search has finished at this block.
- */
- if (b >= nblocks || (num && block == start)) {
- bh_use[ra_max] = NULL;
- break;
- }
- num++;
-
- bh = ocfs2_bread(dir, b++, &err, 1);
- bh_use[ra_max] = bh;
- }
- }
- if ((bh = bh_use[ra_ptr++]) == NULL)
- goto next;
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- /* read error, skip block & hope for the best */
- ocfs2_error(dir->i_sb, "reading directory %llu, "
- "offset %lu\n",
- (unsigned long long)OCFS2_I(dir)->ip_blkno,
- block);
- brelse(bh);
- goto next;
- }
- i = ocfs2_search_dirblock(bh, dir, name, namelen,
- block << sb->s_blocksize_bits,
- res_dir);
- if (i == 1) {
- OCFS2_I(dir)->ip_dir_start_lookup = block;
- ret = bh;
- goto cleanup_and_exit;
- } else {
- brelse(bh);
- if (i < 0)
- goto cleanup_and_exit;
- }
- next:
- if (++block >= nblocks)
- block = 0;
- } while (block != start);
-
- /*
- * If the directory has grown while we were searching, then
- * search the last part of the directory before giving up.
- */
- block = nblocks;
- nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
- if (block < nblocks) {
- start = 0;
- goto restart;
- }
-
-cleanup_and_exit:
- /* Clean up the read-ahead blocks */
- for (; ra_ptr < ra_max; ra_ptr++)
- brelse(bh_use[ra_ptr]);
-
- mlog_exit_ptr(ret);
- return ret;
-}
-
static int ocfs2_blkno_stringify(u64 blkno, char *name)
{
int status, namelen;
diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h
index 0975c7b7212..688aef64c87 100644
--- a/fs/ocfs2/namei.h
+++ b/fs/ocfs2/namei.h
@@ -30,29 +30,10 @@ extern const struct inode_operations ocfs2_dir_iops;
struct dentry *ocfs2_get_parent(struct dentry *child);
-int ocfs2_check_dir_entry (struct inode *dir,
- struct ocfs2_dir_entry *de,
- struct buffer_head *bh,
- unsigned long offset);
-struct buffer_head *ocfs2_find_entry(const char *name,
- int namelen,
- struct inode *dir,
- struct ocfs2_dir_entry **res_dir);
int ocfs2_orphan_del(struct ocfs2_super *osb,
handle_t *handle,
struct inode *orphan_dir_inode,
struct inode *inode,
struct buffer_head *orphan_dir_bh);
-static inline int ocfs2_match(int len,
- const char * const name,
- struct ocfs2_dir_entry *de)
-{
- if (len != de->name_len)
- return 0;
- if (!de->inode)
- return 0;
- return !memcmp(name, de->name, len);
-}
-
#endif /* OCFS2_NAMEI_H */
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 58307853fb4..60a23e1906b 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -319,6 +319,13 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
return 0;
}
+static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
+{
+ if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
+ return 1;
+ return 0;
+}
+
/* set / clear functions because cluster events can make these happen
* in parallel so we want the transitions to be atomic. this also
* means that any future flags osb_flags must be protected by spinlock
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 82f8a75b207..6ef876759a7 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -87,7 +87,8 @@
#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB
#define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
- | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
+ | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
+ | OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
/*
@@ -111,6 +112,20 @@
#define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010
/*
+ * Tunefs sets this incompat flag before starting an operation which
+ * would require cleanup on abort. This is done to protect users from
+ * inadvertently mounting the fs after an aborted run without
+ * fsck-ing.
+ *
+ * s_tunefs_flags on the super block describes precisely which
+ * operations were in progress.
+ */
+#define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG 0x0020
+
+/* Support for data packed into inode blocks */
+#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040
+
+/*
* backup superblock flag is used to indicate that this volume
* has backup superblocks.
*/
@@ -130,6 +145,11 @@
#define OCFS2_MAX_BACKUP_SUPERBLOCKS 6
/*
+ * Flags on ocfs2_super_block.s_tunefs_flags
+ */
+#define OCFS2_TUNEFS_INPROG_REMOVE_SLOT 0x0001 /* Removing slots */
+
+/*
* Flags on ocfs2_dinode.i_flags
*/
#define OCFS2_VALID_FL (0x00000001) /* Inode is valid */
@@ -146,6 +166,17 @@
#define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */
#define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */
+/*
+ * Flags on ocfs2_dinode.i_dyn_features
+ *
+ * These can change much more often than i_flags. When adding flags,
+ * keep in mind that i_dyn_features is only 16 bits wide.
+ */
+#define OCFS2_INLINE_DATA_FL (0x0001) /* Data stored in inode block */
+#define OCFS2_HAS_XATTR_FL (0x0002)
+#define OCFS2_INLINE_XATTR_FL (0x0004)
+#define OCFS2_INDEXED_DIR_FL (0x0008)
+
/* Inode attributes, keep in sync with EXT2 */
#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */
#define OCFS2_UNRM_FL (0x00000002) /* Undelete */
@@ -447,8 +478,8 @@ struct ocfs2_super_block {
__le32 s_clustersize_bits; /* Clustersize for this fs */
/*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts
before tunefs required */
- __le16 s_reserved1;
- __le32 s_reserved2;
+ __le16 s_tunefs_flag;
+ __le32 s_reserved1;
__le64 s_first_cluster_group; /* Block offset of 1st cluster
* group header */
/*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
@@ -471,6 +502,19 @@ struct ocfs2_local_alloc
};
/*
+ * Data-in-inode header. This is only used if i_dyn_features has
+ * OCFS2_INLINE_DATA_FL set.
+ */
+struct ocfs2_inline_data
+{
+/*00*/ __le16 id_count; /* Number of bytes that can be used
+ * for data, starting at id_data */
+ __le16 id_reserved0;
+ __le32 id_reserved1;
+ __u8 id_data[0]; /* Start of user data */
+};
+
+/*
* On disk inode for OCFS2
*/
struct ocfs2_dinode {
@@ -502,7 +546,7 @@ struct ocfs2_dinode {
__le32 i_attr;
__le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL
was set in i_flags */
- __le16 i_reserved1;
+ __le16 i_dyn_features;
/*70*/ __le64 i_reserved2[8];
/*B8*/ union {
__le64 i_pad1; /* Generic way to refer to this
@@ -528,6 +572,7 @@ struct ocfs2_dinode {
struct ocfs2_chain_list i_chain;
struct ocfs2_extent_list i_list;
struct ocfs2_truncate_log i_dealloc;
+ struct ocfs2_inline_data i_data;
__u8 i_symlink[0];
} id2;
/* Actual on-disk size is one block */
@@ -577,6 +622,12 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
offsetof(struct ocfs2_dinode, id2.i_symlink);
}
+static inline int ocfs2_max_inline_data(struct super_block *sb)
+{
+ return sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
{
int size;
@@ -656,6 +707,11 @@ static inline int ocfs2_fast_symlink_chars(int blocksize)
return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink);
}
+static inline int ocfs2_max_inline_data(int blocksize)
+{
+ return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
static inline int ocfs2_extent_recs_per_inode(int blocksize)
{
int size;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index c034b5129c1..0e2a1b45bf9 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -39,6 +39,7 @@
#include <linux/parser.h>
#include <linux/crc32.h>
#include <linux/debugfs.h>
+#include <linux/mount.h>
#include <cluster/nodemanager.h>
@@ -91,6 +92,7 @@ struct mount_options
static int ocfs2_parse_options(struct super_block *sb, char *options,
struct mount_options *mopt,
int is_remount);
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt);
static void ocfs2_put_super(struct super_block *sb);
static int ocfs2_mount_volume(struct super_block *sb);
static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
@@ -105,7 +107,7 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait);
static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb);
static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb);
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb);
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
static int ocfs2_fill_local_node_info(struct ocfs2_super *osb);
static int ocfs2_check_volume(struct ocfs2_super *osb);
static int ocfs2_verify_volume(struct ocfs2_dinode *di,
@@ -133,6 +135,7 @@ static const struct super_operations ocfs2_sops = {
.write_super = ocfs2_write_super,
.put_super = ocfs2_put_super,
.remount_fs = ocfs2_remount,
+ .show_options = ocfs2_show_options,
};
enum {
@@ -177,7 +180,7 @@ static void ocfs2_write_super(struct super_block *sb)
static int ocfs2_sync_fs(struct super_block *sb, int wait)
{
- int status = 0;
+ int status;
tid_t target;
struct ocfs2_super *osb = OCFS2_SB(sb);
@@ -275,9 +278,9 @@ bail:
return status;
}
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb)
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb)
{
- int status = 0, i;
+ int i;
struct inode *inode;
mlog_entry_void();
@@ -302,8 +305,7 @@ static int ocfs2_release_system_inodes(struct ocfs2_super *osb)
osb->root_inode = NULL;
}
- mlog_exit(status);
- return status;
+ mlog_exit(0);
}
/* We're allocating fs objects, use GFP_NOFS */
@@ -453,7 +455,7 @@ static int ocfs2_sb_probe(struct super_block *sb,
struct buffer_head **bh,
int *sector_size)
{
- int status = 0, tmpstat;
+ int status, tmpstat;
struct ocfs1_vol_disk_hdr *hdr;
struct ocfs2_dinode *di;
int blksize;
@@ -830,6 +832,41 @@ bail:
return status;
}
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+ struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
+ unsigned long opts = osb->s_mount_opt;
+
+ if (opts & OCFS2_MOUNT_HB_LOCAL)
+ seq_printf(s, ",_netdev,heartbeat=local");
+ else
+ seq_printf(s, ",heartbeat=none");
+
+ if (opts & OCFS2_MOUNT_NOINTR)
+ seq_printf(s, ",nointr");
+
+ if (opts & OCFS2_MOUNT_DATA_WRITEBACK)
+ seq_printf(s, ",data=writeback");
+ else
+ seq_printf(s, ",data=ordered");
+
+ if (opts & OCFS2_MOUNT_BARRIER)
+ seq_printf(s, ",barrier=1");
+
+ if (opts & OCFS2_MOUNT_ERRORS_PANIC)
+ seq_printf(s, ",errors=panic");
+ else
+ seq_printf(s, ",errors=remount-ro");
+
+ if (osb->preferred_slot != OCFS2_INVALID_SLOT)
+ seq_printf(s, ",preferred_slot=%d", osb->preferred_slot);
+
+ if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
+ seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
+
+ return 0;
+}
+
static int __init ocfs2_init(void)
{
int status;
@@ -1209,12 +1246,13 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
tmp = ocfs2_request_umount_vote(osb);
if (tmp < 0)
mlog_errno(tmp);
+ }
- if (osb->slot_num != OCFS2_INVALID_SLOT)
- ocfs2_put_slot(osb);
+ if (osb->slot_num != OCFS2_INVALID_SLOT)
+ ocfs2_put_slot(osb);
+ if (osb->dlm)
ocfs2_super_unlock(osb, 1);
- }
ocfs2_release_system_inodes(osb);
@@ -1275,7 +1313,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
struct buffer_head *bh,
int sector_size)
{
- int status = 0;
+ int status;
int i, cbits, bbits;
struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
struct inode *inode = NULL;
@@ -1596,7 +1634,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
static int ocfs2_check_volume(struct ocfs2_super *osb)
{
- int status = 0;
+ int status;
int dirty;
int local;
struct ocfs2_dinode *local_alloc = NULL; /* only used if we
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
index 5df6e35d09b..fd2e846e3e6 100644
--- a/fs/ocfs2/sysfile.c
+++ b/fs/ocfs2/sysfile.c
@@ -100,17 +100,14 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
char namebuf[40];
struct inode *inode = NULL;
u64 blkno;
- struct buffer_head *dirent_bh = NULL;
- struct ocfs2_dir_entry *de = NULL;
int status = 0;
ocfs2_sprintf_system_inode_name(namebuf,
sizeof(namebuf),
type, slot);
- status = ocfs2_find_files_on_disk(namebuf, strlen(namebuf),
- &blkno, osb->sys_root_inode,
- &dirent_bh, &de);
+ status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
+ strlen(namebuf), &blkno);
if (status < 0) {
goto bail;
}
@@ -122,8 +119,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
goto bail;
}
bail:
- if (dirent_bh)
- brelse(dirent_bh);
+
return inode;
}
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 783c57ec07d..722e12e5acc 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
p->partno = part;
p->policy = disk->policy;
- if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
- snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
+ if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
+ kobject_set_name(&p->kobj, "%sp%d",
+ kobject_name(&disk->kobj), part);
else
- snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
+ kobject_set_name(&p->kobj, "%s%d",
+ kobject_name(&disk->kobj),part);
p->kobj.parent = &disk->kobj;
p->kobj.ktype = &ktype_part;
kobject_init(&p->kobj);
@@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk)
struct hd_struct *p;
int err;
- strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
+ kobject_set_name(&disk->kobj, "%s", disk->disk_name);
/* ewww... some of these buggers have / in name... */
- s = strchr(disk->kobj.name, '/');
+ s = strchr(disk->kobj.k_name, '/');
if (s)
*s = '!';
if ((err = kobject_add(&disk->kobj)))
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c
index 794118da4ef..c95e6a62c01 100644
--- a/fs/partitions/sun.c
+++ b/fs/partitions/sun.c
@@ -95,8 +95,8 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev)
* So that old Linux-Sun partitions continue to work,
* alow the VTOC to be used under the additional condition ...
*/
- use_vtoc = use_vtoc || !(label->vtoc.sanity |
- label->vtoc.version | label->vtoc.nparts);
+ use_vtoc = use_vtoc || !(label->vtoc.sanity ||
+ label->vtoc.version || label->vtoc.nparts);
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
for (i = 0; i < nparts; i++, p++) {
unsigned long st_sector;
diff --git a/fs/pipe.c b/fs/pipe.c
index 6b3d91a691b..e66ec48e95d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -45,8 +45,7 @@ void pipe_wait(struct pipe_inode_info *pipe)
* Pipes are system-local resources, so sleeping on them
* is considered a noninteractive wait:
*/
- prepare_to_wait(&pipe->wait, &wait,
- TASK_INTERRUPTIBLE | TASK_NONINTERACTIVE);
+ prepare_to_wait(&pipe->wait, &wait, TASK_INTERRUPTIBLE);
if (pipe->inode)
mutex_unlock(&pipe->inode->i_mutex);
schedule();
@@ -383,7 +382,7 @@ redo:
/* Signal writers asynchronously that there is more room. */
if (do_wakeup) {
- wake_up_interruptible(&pipe->wait);
+ wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
if (ret > 0)
@@ -556,7 +555,7 @@ redo2:
out:
mutex_unlock(&inode->i_mutex);
if (do_wakeup) {
- wake_up_interruptible(&pipe->wait);
+ wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
}
if (ret > 0)
@@ -650,7 +649,7 @@ pipe_release(struct inode *inode, int decr, int decw)
if (!pipe->readers && !pipe->writers) {
free_pipe_info(inode);
} else {
- wake_up_interruptible(&pipe->wait);
+ wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index ee4814dd98f..27b59f5f3bd 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -370,6 +370,11 @@ static cputime_t task_stime(struct task_struct *p)
}
#endif
+static cputime_t task_gtime(struct task_struct *p)
+{
+ return p->gtime;
+}
+
static int do_task_stat(struct task_struct *task, char *buffer, int whole)
{
unsigned long vsize, eip, esp, wchan = ~0UL;
@@ -385,6 +390,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
unsigned long cmin_flt = 0, cmaj_flt = 0;
unsigned long min_flt = 0, maj_flt = 0;
cputime_t cutime, cstime, utime, stime;
+ cputime_t cgtime, gtime;
unsigned long rsslim = 0;
char tcomm[sizeof(task->comm)];
unsigned long flags;
@@ -403,6 +409,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
sigemptyset(&sigign);
sigemptyset(&sigcatch);
cutime = cstime = utime = stime = cputime_zero;
+ cgtime = gtime = cputime_zero;
rcu_read_lock();
if (lock_task_sighand(task, &flags)) {
@@ -420,6 +427,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
cmaj_flt = sig->cmaj_flt;
cutime = sig->cutime;
cstime = sig->cstime;
+ cgtime = sig->cgtime;
rsslim = sig->rlim[RLIMIT_RSS].rlim_cur;
/* add up live thread stats at the group level */
@@ -430,6 +438,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
maj_flt += t->maj_flt;
utime = cputime_add(utime, task_utime(t));
stime = cputime_add(stime, task_stime(t));
+ gtime = cputime_add(gtime, task_gtime(t));
t = next_thread(t);
} while (t != task);
@@ -437,6 +446,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
maj_flt += sig->maj_flt;
utime = cputime_add(utime, sig->utime);
stime = cputime_add(stime, sig->stime);
+ gtime += cputime_add(gtime, sig->gtime);
}
sid = signal_session(sig);
@@ -454,6 +464,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
maj_flt = task->maj_flt;
utime = task_utime(task);
stime = task_stime(task);
+ gtime = task_gtime(task);
}
/* scale priority and nice values from timeslices to -20..20 */
@@ -471,7 +482,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n",
task->pid,
tcomm,
state,
@@ -516,7 +527,9 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
task_cpu(task),
task->rt_priority,
task->policy,
- (unsigned long long)delayacct_blkio_ticks(task));
+ (unsigned long long)delayacct_blkio_ticks(task),
+ cputime_to_clock_t(gtime),
+ cputime_to_clock_t(cgtime));
if (mm)
mmput(mm);
return res;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 19489b0d555..e5d0953d4db 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -304,7 +304,7 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
return sprintf(buffer, "%llu %llu %lu\n",
task->sched_info.cpu_time,
task->sched_info.run_delay,
- task->sched_info.pcnt);
+ task->sched_info.pcount);
}
#endif
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index bee251cb87c..0071939c009 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -66,7 +66,6 @@ extern int get_stram_list(char *);
extern int get_filesystem_list(char *);
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);
-extern int get_locks_status (char *, char **, off_t, int);
static int proc_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
@@ -443,6 +442,7 @@ static int show_stat(struct seq_file *p, void *v)
int i;
unsigned long jif;
cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
+ cputime64_t guest;
u64 sum = 0;
struct timespec boottime;
unsigned int *per_irq_sum;
@@ -453,6 +453,7 @@ static int show_stat(struct seq_file *p, void *v)
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
+ guest = cputime64_zero;
getboottime(&boottime);
jif = boottime.tv_sec;
@@ -467,6 +468,7 @@ static int show_stat(struct seq_file *p, void *v)
irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
+ guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
for (j = 0; j < NR_IRQS; j++) {
unsigned int temp = kstat_cpu(i).irqs[j];
sum += temp;
@@ -474,7 +476,7 @@ static int show_stat(struct seq_file *p, void *v)
}
}
- seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+ seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
(unsigned long long)cputime64_to_clock_t(user),
(unsigned long long)cputime64_to_clock_t(nice),
(unsigned long long)cputime64_to_clock_t(system),
@@ -482,7 +484,8 @@ static int show_stat(struct seq_file *p, void *v)
(unsigned long long)cputime64_to_clock_t(iowait),
(unsigned long long)cputime64_to_clock_t(irq),
(unsigned long long)cputime64_to_clock_t(softirq),
- (unsigned long long)cputime64_to_clock_t(steal));
+ (unsigned long long)cputime64_to_clock_t(steal),
+ (unsigned long long)cputime64_to_clock_t(guest));
for_each_online_cpu(i) {
/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
@@ -494,7 +497,9 @@ static int show_stat(struct seq_file *p, void *v)
irq = kstat_cpu(i).cpustat.irq;
softirq = kstat_cpu(i).cpustat.softirq;
steal = kstat_cpu(i).cpustat.steal;
- seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu\n",
+ guest = kstat_cpu(i).cpustat.guest;
+ seq_printf(p,
+ "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
i,
(unsigned long long)cputime64_to_clock_t(user),
(unsigned long long)cputime64_to_clock_t(nice),
@@ -503,7 +508,8 @@ static int show_stat(struct seq_file *p, void *v)
(unsigned long long)cputime64_to_clock_t(iowait),
(unsigned long long)cputime64_to_clock_t(irq),
(unsigned long long)cputime64_to_clock_t(softirq),
- (unsigned long long)cputime64_to_clock_t(steal));
+ (unsigned long long)cputime64_to_clock_t(steal),
+ (unsigned long long)cputime64_to_clock_t(guest));
}
seq_printf(p, "intr %llu", (unsigned long long)sum);
@@ -617,16 +623,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}
-static int locks_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int locks_open(struct inode *inode, struct file *filp)
{
- int len = get_locks_status(page, start, off, count);
-
- if (len < count)
- *eof = 1;
- return len;
+ return seq_open(filp, &locks_seq_operations);
}
+static const struct file_operations proc_locks_operations = {
+ .open = locks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -684,7 +692,6 @@ void __init proc_misc_init(void)
#endif
{"filesystems", filesystems_read_proc},
{"cmdline", cmdline_read_proc},
- {"locks", locks_read_proc},
{"execdomains", execdomains_read_proc},
{NULL,}
};
@@ -702,6 +709,7 @@ void __init proc_misc_init(void)
entry->proc_fops = &proc_kmsg_operations;
}
#endif
+ create_seq_entry("locks", 0, &proc_locks_operations);
create_seq_entry("devices", 0, &proc_devinfo_operations);
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK
diff --git a/fs/read_write.c b/fs/read_write.c
index 507ddff48a9..124693e8d3f 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -205,7 +205,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
goto Einval;
- if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
+ if (unlikely(inode->i_flock && mandatory_lock(inode))) {
int retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
inode, file, pos, count);
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index 67176af8515..283c5720c9d 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -45,7 +45,7 @@ static LIST_HEAD(smb_servers);
static DEFINE_SPINLOCK(servers_lock);
#define SMBIOD_DATA_READY (1<<0)
-static long smbiod_flags;
+static unsigned long smbiod_flags;
static int smbiod(void *);
static int smbiod_start(void);
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 5afe2a26f5d..006fc64227d 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -1,9 +1,15 @@
/*
- * bin.c - binary file operations for sysfs.
+ * fs/sysfs/bin.c - sysfs binary file implementation
*
* Copyright (c) 2003 Patrick Mochel
* Copyright (c) 2003 Matthew Wilcox
* Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
*/
#undef DEBUG
@@ -14,9 +20,9 @@
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include "sysfs.h"
@@ -30,8 +36,8 @@ static int
fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
{
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
- struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
int rc;
/* need attr_sd for attr, its parent for kobj */
@@ -87,8 +93,8 @@ static int
flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
{
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
- struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
int rc;
/* need attr_sd for attr, its parent for kobj */
@@ -140,8 +146,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
{
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
- struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
int rc;
mutex_lock(&bb->mutex);
@@ -167,12 +173,12 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
static int open(struct inode * inode, struct file * file)
{
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
- struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+ struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
struct bin_buffer *bb = NULL;
int error;
- /* need attr_sd for attr */
- if (!sysfs_get_active(attr_sd))
+ /* binary file operations requires both @sd and its parent */
+ if (!sysfs_get_active_two(attr_sd))
return -ENODEV;
error = -EACCES;
@@ -193,13 +199,12 @@ static int open(struct inode * inode, struct file * file)
mutex_init(&bb->mutex);
file->private_data = bb;
- /* open succeeded, put active reference and pin attr_sd */
- sysfs_put_active(attr_sd);
- sysfs_get(attr_sd);
+ /* open succeeded, put active references */
+ sysfs_put_active_two(attr_sd);
return 0;
err_out:
- sysfs_put_active(attr_sd);
+ sysfs_put_active_two(attr_sd);
kfree(bb);
return error;
}
@@ -211,7 +216,6 @@ static int release(struct inode * inode, struct file * file)
if (bb->mmapped)
sysfs_put_active_two(attr_sd);
- sysfs_put(attr_sd);
kfree(bb->buffer);
kfree(bb);
return 0;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 83e76b3813c..9161db4d6b5 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -1,5 +1,13 @@
/*
- * dir.c - Operations for sysfs directories.
+ * fs/sysfs/dir.c - sysfs core and dir operation implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
*/
#undef DEBUG
@@ -11,10 +19,11 @@
#include <linux/namei.h>
#include <linux/idr.h>
#include <linux/completion.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "sysfs.h"
DEFINE_MUTEX(sysfs_mutex);
+DEFINE_MUTEX(sysfs_rename_mutex);
spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -25,18 +34,28 @@ static DEFINE_IDA(sysfs_ino_ida);
* @sd: sysfs_dirent of interest
*
* Link @sd into its sibling list which starts from
- * sd->s_parent->s_children.
+ * sd->s_parent->s_dir.children.
*
* Locking:
* mutex_lock(sysfs_mutex)
*/
-void sysfs_link_sibling(struct sysfs_dirent *sd)
+static void sysfs_link_sibling(struct sysfs_dirent *sd)
{
struct sysfs_dirent *parent_sd = sd->s_parent;
+ struct sysfs_dirent **pos;
BUG_ON(sd->s_sibling);
- sd->s_sibling = parent_sd->s_children;
- parent_sd->s_children = sd;
+
+ /* Store directory entries in order by ino. This allows
+ * readdir to properly restart without having to add a
+ * cursor into the s_dir.children list.
+ */
+ for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
+ if (sd->s_ino < (*pos)->s_ino)
+ break;
+ }
+ sd->s_sibling = *pos;
+ *pos = sd;
}
/**
@@ -44,16 +63,17 @@ void sysfs_link_sibling(struct sysfs_dirent *sd)
* @sd: sysfs_dirent of interest
*
* Unlink @sd from its sibling list which starts from
- * sd->s_parent->s_children.
+ * sd->s_parent->s_dir.children.
*
* Locking:
* mutex_lock(sysfs_mutex)
*/
-void sysfs_unlink_sibling(struct sysfs_dirent *sd)
+static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
{
struct sysfs_dirent **pos;
- for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
+ for (pos = &sd->s_parent->s_dir.children; *pos;
+ pos = &(*pos)->s_sibling) {
if (*pos == sd) {
*pos = sd->s_sibling;
sd->s_sibling = NULL;
@@ -67,96 +87,39 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd)
* @sd: sysfs_dirent of interest
*
* Get dentry for @sd. Dentry is looked up if currently not
- * present. This function climbs sysfs_dirent tree till it
- * reaches a sysfs_dirent with valid dentry attached and descends
- * down from there looking up dentry for each step.
+ * present. This function descends from the root looking up
+ * dentry for each step.
*
* LOCKING:
- * Kernel thread context (may sleep)
+ * mutex_lock(sysfs_rename_mutex)
*
* RETURNS:
* Pointer to found dentry on success, ERR_PTR() value on error.
*/
struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
{
- struct sysfs_dirent *cur;
- struct dentry *parent_dentry, *dentry;
- int i, depth;
-
- /* Find the first parent which has valid s_dentry and get the
- * dentry.
- */
- mutex_lock(&sysfs_mutex);
- restart0:
- spin_lock(&sysfs_assoc_lock);
- restart1:
- spin_lock(&dcache_lock);
+ struct dentry *dentry = dget(sysfs_sb->s_root);
- dentry = NULL;
- depth = 0;
- cur = sd;
- while (!cur->s_dentry || !cur->s_dentry->d_inode) {
- if (cur->s_flags & SYSFS_FLAG_REMOVED) {
- dentry = ERR_PTR(-ENOENT);
- depth = 0;
- break;
- }
- cur = cur->s_parent;
- depth++;
- }
- if (!IS_ERR(dentry))
- dentry = dget_locked(cur->s_dentry);
+ while (dentry->d_fsdata != sd) {
+ struct sysfs_dirent *cur;
+ struct dentry *parent;
- spin_unlock(&dcache_lock);
- spin_unlock(&sysfs_assoc_lock);
-
- /* from the found dentry, look up depth times */
- while (depth--) {
- /* find and get depth'th ancestor */
- for (cur = sd, i = 0; cur && i < depth; i++)
+ /* find the first ancestor which hasn't been looked up */
+ cur = sd;
+ while (cur->s_parent != dentry->d_fsdata)
cur = cur->s_parent;
- /* This can happen if tree structure was modified due
- * to move/rename. Restart.
- */
- if (i != depth) {
- dput(dentry);
- goto restart0;
- }
-
- sysfs_get(cur);
-
- mutex_unlock(&sysfs_mutex);
-
/* look it up */
- parent_dentry = dentry;
- dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
+ parent = dentry;
+ mutex_lock(&parent->d_inode->i_mutex);
+ dentry = lookup_one_len_kern(cur->s_name, parent,
strlen(cur->s_name));
- dput(parent_dentry);
-
- if (IS_ERR(dentry)) {
- sysfs_put(cur);
- return dentry;
- }
+ mutex_unlock(&parent->d_inode->i_mutex);
+ dput(parent);
- mutex_lock(&sysfs_mutex);
- spin_lock(&sysfs_assoc_lock);
-
- /* This, again, can happen if tree structure has
- * changed and we looked up the wrong thing. Restart.
- */
- if (cur->s_dentry != dentry) {
- dput(dentry);
- sysfs_put(cur);
- goto restart1;
- }
-
- spin_unlock(&sysfs_assoc_lock);
-
- sysfs_put(cur);
+ if (IS_ERR(dentry))
+ break;
}
-
- mutex_unlock(&sysfs_mutex);
return dentry;
}
@@ -319,7 +282,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
parent_sd = sd->s_parent;
if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
- sysfs_put(sd->s_elem.symlink.target_sd);
+ sysfs_put(sd->s_symlink.target_sd);
if (sysfs_type(sd) & SYSFS_COPY_NAME)
kfree(sd->s_name);
kfree(sd->s_iattr);
@@ -335,22 +298,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
{
struct sysfs_dirent * sd = dentry->d_fsdata;
- if (sd) {
- /* sd->s_dentry is protected with sysfs_assoc_lock.
- * This allows sysfs_drop_dentry() to dereference it.
- */
- spin_lock(&sysfs_assoc_lock);
-
- /* The dentry might have been deleted or another
- * lookup could have happened updating sd->s_dentry to
- * point the new dentry. Ignore if it isn't pointing
- * to this dentry.
- */
- if (sd->s_dentry == dentry)
- sd->s_dentry = NULL;
- spin_unlock(&sysfs_assoc_lock);
- sysfs_put(sd);
- }
+ sysfs_put(sd);
iput(inode);
}
@@ -378,7 +326,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_active, 0);
- atomic_set(&sd->s_event, 1);
sd->s_name = name;
sd->s_mode = mode;
@@ -393,30 +340,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
return NULL;
}
-/**
- * sysfs_attach_dentry - associate sysfs_dirent with dentry
- * @sd: target sysfs_dirent
- * @dentry: dentry to associate
- *
- * Associate @sd with @dentry. This is protected by
- * sysfs_assoc_lock to avoid race with sysfs_d_iput().
- *
- * LOCKING:
- * mutex_lock(sysfs_mutex)
- */
-static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
-{
- dentry->d_op = &sysfs_dentry_ops;
- dentry->d_fsdata = sysfs_get(sd);
-
- /* protect sd->s_dentry against sysfs_d_iput */
- spin_lock(&sysfs_assoc_lock);
- sd->s_dentry = dentry;
- spin_unlock(&sysfs_assoc_lock);
-
- d_rehash(dentry);
-}
-
static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
struct sysfs_dirent *sd = arg;
@@ -480,10 +403,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
* @sd: sysfs_dirent to be added
*
* Get @acxt->parent_sd and set sd->s_parent to it and increment
- * nlink of parent inode if @sd is a directory. @sd is NOT
- * linked into the children list of the parent. The caller
- * should invoke sysfs_link_sibling() after this function
- * completes if @sd needs to be on the children list.
+ * nlink of parent inode if @sd is a directory and link into the
+ * children list of the parent.
*
* This function should be called between calls to
* sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -491,15 +412,30 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
*
* LOCKING:
* Determined by sysfs_addrm_start().
+ *
+ * RETURNS:
+ * 0 on success, -EEXIST if entry with the given name already
+ * exists.
*/
-void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
+ if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) {
+ printk(KERN_WARNING "sysfs: duplicate filename '%s' "
+ "can not be created\n", sd->s_name);
+ WARN_ON(1);
+ return -EEXIST;
+ }
+
sd->s_parent = sysfs_get(acxt->parent_sd);
if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
inc_nlink(acxt->parent_inode);
acxt->cnt++;
+
+ sysfs_link_sibling(sd);
+
+ return 0;
}
/**
@@ -508,9 +444,7 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
* @sd: sysfs_dirent to be added
*
* Mark @sd removed and drop nlink of parent inode if @sd is a
- * directory. @sd is NOT unlinked from the children list of the
- * parent. The caller is repsonsible for removing @sd from the
- * children list before calling this function.
+ * directory. @sd is unlinked from the children list.
*
* This function should be called between calls to
* sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -521,7 +455,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
*/
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
- BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED));
+ BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
+
+ sysfs_unlink_sibling(sd);
sd->s_flags |= SYSFS_FLAG_REMOVED;
sd->s_sibling = acxt->removed;
@@ -540,53 +476,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
* Drop dentry for @sd. @sd must have been unlinked from its
* parent on entry to this function such that it can't be looked
* up anymore.
- *
- * @sd->s_dentry which is protected with sysfs_assoc_lock points
- * to the currently associated dentry but we're not holding a
- * reference to it and racing with dput(). Grab dcache_lock and
- * verify dentry before dropping it. If @sd->s_dentry is NULL or
- * dput() beats us, no need to bother.
*/
static void sysfs_drop_dentry(struct sysfs_dirent *sd)
{
- struct dentry *dentry = NULL;
struct inode *inode;
+ struct dentry *dentry;
- /* We're not holding a reference to ->s_dentry dentry but the
- * field will stay valid as long as sysfs_assoc_lock is held.
+ inode = ilookup(sysfs_sb, sd->s_ino);
+ if (!inode)
+ return;
+
+ /* Drop any existing dentries associated with sd.
+ *
+ * For the dentry to be properly freed we need to grab a
+ * reference to the dentry under the dcache lock, unhash it,
+ * and then put it. The playing with the dentry count allows
+ * dput to immediately free the dentry if it is not in use.
*/
- spin_lock(&sysfs_assoc_lock);
+repeat:
spin_lock(&dcache_lock);
-
- /* drop dentry if it's there and dput() didn't kill it yet */
- if (sd->s_dentry && sd->s_dentry->d_inode) {
- dentry = dget_locked(sd->s_dentry);
+ list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ if (d_unhashed(dentry))
+ continue;
+ dget_locked(dentry);
spin_lock(&dentry->d_lock);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
+ dput(dentry);
+ goto repeat;
}
-
spin_unlock(&dcache_lock);
- spin_unlock(&sysfs_assoc_lock);
-
- /* dentries for shadowed inodes are pinned, unpin */
- if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
- dput(dentry);
- dput(dentry);
/* adjust nlink and update timestamp */
- inode = ilookup(sysfs_sb, sd->s_ino);
- if (inode) {
- mutex_lock(&inode->i_mutex);
+ mutex_lock(&inode->i_mutex);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = CURRENT_TIME;
+ drop_nlink(inode);
+ if (sysfs_type(sd) == SYSFS_DIR)
drop_nlink(inode);
- if (sysfs_type(sd) == SYSFS_DIR)
- drop_nlink(inode);
- mutex_unlock(&inode->i_mutex);
- iput(inode);
- }
+ mutex_unlock(&inode->i_mutex);
+
+ iput(inode);
}
/**
@@ -599,11 +531,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
*
* LOCKING:
* All mutexes acquired by sysfs_addrm_start() are released.
- *
- * RETURNS:
- * Number of added/removed sysfs_dirents since sysfs_addrm_start().
*/
-int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
{
/* release resources acquired by sysfs_addrm_start() */
mutex_unlock(&sysfs_mutex);
@@ -629,8 +558,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
sysfs_deactivate(sd);
sysfs_put(sd);
}
-
- return acxt->cnt;
}
/**
@@ -651,8 +578,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
{
struct sysfs_dirent *sd;
- for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
- if (sysfs_type(sd) && !strcmp(sd->s_name, name))
+ for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
+ if (!strcmp(sd->s_name, name))
return sd;
return NULL;
}
@@ -690,28 +617,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
+ int rc;
/* allocate */
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
if (!sd)
return -ENOMEM;
- sd->s_elem.dir.kobj = kobj;
+ sd->s_dir.kobj = kobj;
/* link in */
sysfs_addrm_start(&acxt, parent_sd);
+ rc = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_finish(&acxt);
- if (!sysfs_find_dirent(parent_sd, name)) {
- sysfs_add_one(&acxt, sd);
- sysfs_link_sibling(sd);
- }
-
- if (!sysfs_addrm_finish(&acxt)) {
+ if (rc == 0)
+ *p_sd = sd;
+ else
sysfs_put(sd);
- return -EEXIST;
- }
- *p_sd = sd;
- return 0;
+ return rc;
}
int sysfs_create_subdir(struct kobject *kobj, const char *name,
@@ -723,24 +647,18 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
/**
* sysfs_create_dir - create a directory for an object.
* @kobj: object we're creating directory for.
- * @shadow_parent: parent object.
*/
-int sysfs_create_dir(struct kobject *kobj,
- struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
{
struct sysfs_dirent *parent_sd, *sd;
int error = 0;
BUG_ON(!kobj);
- if (shadow_parent_sd)
- parent_sd = shadow_parent_sd;
- else if (kobj->parent)
+ if (kobj->parent)
parent_sd = kobj->parent->sd;
- else if (sysfs_mount && sysfs_mount->mnt_sb)
- parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
else
- return -EFAULT;
+ parent_sd = &sysfs_root;
error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
if (!error)
@@ -748,39 +666,20 @@ int sysfs_create_dir(struct kobject *kobj,
return error;
}
-static int sysfs_count_nlink(struct sysfs_dirent *sd)
-{
- struct sysfs_dirent *child;
- int nr = 0;
-
- for (child = sd->s_children; child; child = child->s_sibling)
- if (sysfs_type(child) == SYSFS_DIR)
- nr++;
- return nr + 2;
-}
-
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
struct dentry *ret = NULL;
- struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
- struct sysfs_dirent * sd;
- struct bin_attribute *bin_attr;
+ struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
+ struct sysfs_dirent *sd;
struct inode *inode;
- int found = 0;
mutex_lock(&sysfs_mutex);
- for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
- if (sysfs_type(sd) &&
- !strcmp(sd->s_name, dentry->d_name.name)) {
- found = 1;
- break;
- }
- }
+ sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
/* no such entry */
- if (!found)
+ if (!sd)
goto out_unlock;
/* attach dentry and inode */
@@ -790,33 +689,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
goto out_unlock;
}
- if (inode->i_state & I_NEW) {
- /* initialize inode according to type */
- switch (sysfs_type(sd)) {
- case SYSFS_DIR:
- inode->i_op = &sysfs_dir_inode_operations;
- inode->i_fop = &sysfs_dir_operations;
- inode->i_nlink = sysfs_count_nlink(sd);
- break;
- case SYSFS_KOBJ_ATTR:
- inode->i_size = PAGE_SIZE;
- inode->i_fop = &sysfs_file_operations;
- break;
- case SYSFS_KOBJ_BIN_ATTR:
- bin_attr = sd->s_elem.bin_attr.bin_attr;
- inode->i_size = bin_attr->size;
- inode->i_fop = &bin_fops;
- break;
- case SYSFS_KOBJ_LINK:
- inode->i_op = &sysfs_symlink_inode_operations;
- break;
- default:
- BUG();
- }
- }
-
- sysfs_instantiate(dentry, inode);
- sysfs_attach_dentry(sd, dentry);
+ /* instantiate and hash dentry */
+ dentry->d_op = &sysfs_dentry_ops;
+ dentry->d_fsdata = sysfs_get(sd);
+ d_instantiate(dentry, inode);
+ d_rehash(dentry);
out_unlock:
mutex_unlock(&sysfs_mutex);
@@ -833,7 +710,6 @@ static void remove_dir(struct sysfs_dirent *sd)
struct sysfs_addrm_cxt acxt;
sysfs_addrm_start(&acxt, sd->s_parent);
- sysfs_unlink_sibling(sd);
sysfs_remove_one(&acxt, sd);
sysfs_addrm_finish(&acxt);
}
@@ -854,15 +730,13 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
sysfs_addrm_start(&acxt, dir_sd);
- pos = &dir_sd->s_children;
+ pos = &dir_sd->s_dir.children;
while (*pos) {
struct sysfs_dirent *sd = *pos;
- if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
- *pos = sd->s_sibling;
- sd->s_sibling = NULL;
+ if (sysfs_type(sd) != SYSFS_DIR)
sysfs_remove_one(&acxt, sd);
- } else
+ else
pos = &(*pos)->s_sibling;
}
sysfs_addrm_finish(&acxt);
@@ -890,90 +764,68 @@ void sysfs_remove_dir(struct kobject * kobj)
__sysfs_remove_dir(sd);
}
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
- const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
{
struct sysfs_dirent *sd = kobj->sd;
- struct dentry *new_parent = NULL;
+ struct dentry *parent = NULL;
struct dentry *old_dentry = NULL, *new_dentry = NULL;
const char *dup_name = NULL;
int error;
- /* get dentries */
+ mutex_lock(&sysfs_rename_mutex);
+
+ error = 0;
+ if (strcmp(sd->s_name, new_name) == 0)
+ goto out; /* nothing to rename */
+
+ /* get the original dentry */
old_dentry = sysfs_get_dentry(sd);
if (IS_ERR(old_dentry)) {
error = PTR_ERR(old_dentry);
- goto out_dput;
- }
-
- new_parent = sysfs_get_dentry(new_parent_sd);
- if (IS_ERR(new_parent)) {
- error = PTR_ERR(new_parent);
- goto out_dput;
+ goto out;
}
- /* lock new_parent and get dentry for new name */
- mutex_lock(&new_parent->d_inode->i_mutex);
+ parent = old_dentry->d_parent;
- new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
- if (IS_ERR(new_dentry)) {
- error = PTR_ERR(new_dentry);
- goto out_unlock;
- }
+ /* lock parent and get dentry for new name */
+ mutex_lock(&parent->d_inode->i_mutex);
+ mutex_lock(&sysfs_mutex);
- /* By allowing two different directories with the same
- * d_parent we allow this routine to move between different
- * shadows of the same directory
- */
- error = -EINVAL;
- if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
- new_dentry->d_parent->d_inode != new_parent->d_inode ||
- old_dentry == new_dentry)
+ error = -EEXIST;
+ if (sysfs_find_dirent(sd->s_parent, new_name))
goto out_unlock;
- error = -EEXIST;
- if (new_dentry->d_inode)
+ error = -ENOMEM;
+ new_dentry = d_alloc_name(parent, new_name);
+ if (!new_dentry)
goto out_unlock;
/* rename kobject and sysfs_dirent */
error = -ENOMEM;
new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
- goto out_drop;
+ goto out_unlock;
error = kobject_set_name(kobj, "%s", new_name);
if (error)
- goto out_drop;
-
- mutex_lock(&sysfs_mutex);
+ goto out_unlock;
dup_name = sd->s_name;
sd->s_name = new_name;
- /* move under the new parent */
+ /* rename */
d_add(new_dentry, NULL);
- d_move(sd->s_dentry, new_dentry);
-
- sysfs_unlink_sibling(sd);
- sysfs_get(new_parent_sd);
- sysfs_put(sd->s_parent);
- sd->s_parent = new_parent_sd;
- sysfs_link_sibling(sd);
-
- mutex_unlock(&sysfs_mutex);
+ d_move(old_dentry, new_dentry);
error = 0;
- goto out_unlock;
-
- out_drop:
- d_drop(new_dentry);
out_unlock:
- mutex_unlock(&new_parent->d_inode->i_mutex);
- out_dput:
+ mutex_unlock(&sysfs_mutex);
+ mutex_unlock(&parent->d_inode->i_mutex);
kfree(dup_name);
- dput(new_parent);
dput(old_dentry);
dput(new_dentry);
+ out:
+ mutex_unlock(&sysfs_rename_mutex);
return error;
}
@@ -985,96 +837,69 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
struct dentry *old_dentry = NULL, *new_dentry = NULL;
int error;
+ mutex_lock(&sysfs_rename_mutex);
BUG_ON(!sd->s_parent);
new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
+ error = 0;
+ if (sd->s_parent == new_parent_sd)
+ goto out; /* nothing to move */
+
/* get dentries */
old_dentry = sysfs_get_dentry(sd);
if (IS_ERR(old_dentry)) {
error = PTR_ERR(old_dentry);
- goto out_dput;
+ goto out;
}
- old_parent = sd->s_parent->s_dentry;
+ old_parent = old_dentry->d_parent;
new_parent = sysfs_get_dentry(new_parent_sd);
if (IS_ERR(new_parent)) {
error = PTR_ERR(new_parent);
- goto out_dput;
+ goto out;
}
- if (old_parent->d_inode == new_parent->d_inode) {
- error = 0;
- goto out_dput; /* nothing to move */
- }
again:
mutex_lock(&old_parent->d_inode->i_mutex);
if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
mutex_unlock(&old_parent->d_inode->i_mutex);
goto again;
}
+ mutex_lock(&sysfs_mutex);
- new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
- if (IS_ERR(new_dentry)) {
- error = PTR_ERR(new_dentry);
+ error = -EEXIST;
+ if (sysfs_find_dirent(new_parent_sd, sd->s_name))
goto out_unlock;
- } else
- error = 0;
+
+ error = -ENOMEM;
+ new_dentry = d_alloc_name(new_parent, sd->s_name);
+ if (!new_dentry)
+ goto out_unlock;
+
+ error = 0;
d_add(new_dentry, NULL);
- d_move(sd->s_dentry, new_dentry);
+ d_move(old_dentry, new_dentry);
dput(new_dentry);
/* Remove from old parent's list and insert into new parent's list. */
- mutex_lock(&sysfs_mutex);
-
sysfs_unlink_sibling(sd);
sysfs_get(new_parent_sd);
sysfs_put(sd->s_parent);
sd->s_parent = new_parent_sd;
sysfs_link_sibling(sd);
- mutex_unlock(&sysfs_mutex);
-
out_unlock:
+ mutex_unlock(&sysfs_mutex);
mutex_unlock(&new_parent->d_inode->i_mutex);
mutex_unlock(&old_parent->d_inode->i_mutex);
- out_dput:
+ out:
dput(new_parent);
dput(old_dentry);
dput(new_dentry);
+ mutex_unlock(&sysfs_rename_mutex);
return error;
}
-static int sysfs_dir_open(struct inode *inode, struct file *file)
-{
- struct dentry * dentry = file->f_path.dentry;
- struct sysfs_dirent * parent_sd = dentry->d_fsdata;
- struct sysfs_dirent * sd;
-
- sd = sysfs_new_dirent("_DIR_", 0, 0);
- if (sd) {
- mutex_lock(&sysfs_mutex);
- sd->s_parent = sysfs_get(parent_sd);
- sysfs_link_sibling(sd);
- mutex_unlock(&sysfs_mutex);
- }
-
- file->private_data = sd;
- return sd ? 0 : -ENOMEM;
-}
-
-static int sysfs_dir_close(struct inode *inode, struct file *file)
-{
- struct sysfs_dirent * cursor = file->private_data;
-
- mutex_lock(&sysfs_mutex);
- sysfs_unlink_sibling(cursor);
- mutex_unlock(&sysfs_mutex);
-
- release_sysfs_dirent(cursor);
-
- return 0;
-}
-
/* Relationship between s_mode and the DT_xxx types */
static inline unsigned char dt_type(struct sysfs_dirent *sd)
{
@@ -1085,232 +910,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
struct dentry *dentry = filp->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
- struct sysfs_dirent *cursor = filp->private_data;
- struct sysfs_dirent **pos;
+ struct sysfs_dirent *pos;
ino_t ino;
- int i = filp->f_pos;
- switch (i) {
- case 0:
- ino = parent_sd->s_ino;
- if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
- break;
+ if (filp->f_pos == 0) {
+ ino = parent_sd->s_ino;
+ if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
filp->f_pos++;
- i++;
- /* fallthrough */
- case 1:
- if (parent_sd->s_parent)
- ino = parent_sd->s_parent->s_ino;
- else
- ino = parent_sd->s_ino;
- if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
- break;
+ }
+ if (filp->f_pos == 1) {
+ if (parent_sd->s_parent)
+ ino = parent_sd->s_parent->s_ino;
+ else
+ ino = parent_sd->s_ino;
+ if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
filp->f_pos++;
- i++;
- /* fallthrough */
- default:
- mutex_lock(&sysfs_mutex);
-
- pos = &parent_sd->s_children;
- while (*pos != cursor)
- pos = &(*pos)->s_sibling;
-
- /* unlink cursor */
- *pos = cursor->s_sibling;
-
- if (filp->f_pos == 2)
- pos = &parent_sd->s_children;
-
- for ( ; *pos; pos = &(*pos)->s_sibling) {
- struct sysfs_dirent *next = *pos;
- const char * name;
- int len;
-
- if (!sysfs_type(next))
- continue;
-
- name = next->s_name;
- len = strlen(name);
- ino = next->s_ino;
-
- if (filldir(dirent, name, len, filp->f_pos, ino,
- dt_type(next)) < 0)
- break;
+ }
+ if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {
+ mutex_lock(&sysfs_mutex);
- filp->f_pos++;
- }
+ /* Skip the dentries we have already reported */
+ pos = parent_sd->s_dir.children;
+ while (pos && (filp->f_pos > pos->s_ino))
+ pos = pos->s_sibling;
- /* put cursor back in */
- cursor->s_sibling = *pos;
- *pos = cursor;
+ for ( ; pos; pos = pos->s_sibling) {
+ const char * name;
+ int len;
- mutex_unlock(&sysfs_mutex);
- }
- return 0;
-}
-
-static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
-{
- struct dentry * dentry = file->f_path.dentry;
+ name = pos->s_name;
+ len = strlen(name);
+ filp->f_pos = ino = pos->s_ino;
- switch (origin) {
- case 1:
- offset += file->f_pos;
- case 0:
- if (offset >= 0)
+ if (filldir(dirent, name, len, filp->f_pos, ino,
+ dt_type(pos)) < 0)
break;
- default:
- return -EINVAL;
- }
- if (offset != file->f_pos) {
- mutex_lock(&sysfs_mutex);
-
- file->f_pos = offset;
- if (file->f_pos >= 2) {
- struct sysfs_dirent *sd = dentry->d_fsdata;
- struct sysfs_dirent *cursor = file->private_data;
- struct sysfs_dirent **pos;
- loff_t n = file->f_pos - 2;
-
- sysfs_unlink_sibling(cursor);
-
- pos = &sd->s_children;
- while (n && *pos) {
- struct sysfs_dirent *next = *pos;
- if (sysfs_type(next))
- n--;
- pos = &(*pos)->s_sibling;
- }
-
- cursor->s_sibling = *pos;
- *pos = cursor;
}
-
+ if (!pos)
+ filp->f_pos = INT_MAX;
mutex_unlock(&sysfs_mutex);
}
-
- return offset;
-}
-
-
-/**
- * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- * @kobj: object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
- void * (*follow_link)(struct dentry *, struct nameidata *))
-{
- struct dentry *dentry;
- struct inode *inode;
- struct inode_operations *i_op;
-
- /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
- dentry = sysfs_get_dentry(kobj->sd);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- inode = dentry->d_inode;
- if (inode->i_op != &sysfs_dir_inode_operations) {
- dput(dentry);
- return -EINVAL;
- }
-
- i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
- if (!i_op)
- return -ENOMEM;
-
- memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
- i_op->follow_link = follow_link;
-
- /* Locking of inode->i_op?
- * Since setting i_op is a single word write and they
- * are atomic we should be ok here.
- */
- inode->i_op = i_op;
return 0;
}
-/**
- * sysfs_create_shadow_dir - create a shadow directory for an object.
- * @kobj: object we're creating directory for.
- *
- * sysfs_make_shadowed_dir must already have been called on this
- * directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
- struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
- struct dentry *dir, *parent, *shadow;
- struct inode *inode;
- struct sysfs_dirent *sd;
- struct sysfs_addrm_cxt acxt;
-
- dir = sysfs_get_dentry(kobj->sd);
- if (IS_ERR(dir)) {
- sd = (void *)dir;
- goto out;
- }
- parent = dir->d_parent;
-
- inode = dir->d_inode;
- sd = ERR_PTR(-EINVAL);
- if (!sysfs_is_shadowed_inode(inode))
- goto out_dput;
-
- shadow = d_alloc(parent, &dir->d_name);
- if (!shadow)
- goto nomem;
-
- sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
- if (!sd)
- goto nomem;
- sd->s_elem.dir.kobj = kobj;
-
- sysfs_addrm_start(&acxt, parent_sd);
-
- /* add but don't link into children list */
- sysfs_add_one(&acxt, sd);
-
- /* attach and instantiate dentry */
- sysfs_attach_dentry(sd, shadow);
- d_instantiate(shadow, igrab(inode));
- inc_nlink(inode); /* tj: synchronization? */
-
- sysfs_addrm_finish(&acxt);
-
- dget(shadow); /* Extra count - pin the dentry in core */
-
- goto out_dput;
-
- nomem:
- dput(shadow);
- sd = ERR_PTR(-ENOMEM);
- out_dput:
- dput(dir);
- out:
- return sd;
-}
-
-/**
- * sysfs_remove_shadow_dir - remove an object's directory.
- * @shadow_sd: sysfs_dirent of shadow directory
- *
- * The only thing special about this is that we remove any files in
- * the directory before we remove the directory, and we've inlined
- * what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
- __sysfs_remove_dir(shadow_sd);
-}
const struct file_operations sysfs_dir_operations = {
- .open = sysfs_dir_open,
- .release = sysfs_dir_close,
- .llseek = sysfs_dir_lseek,
.read = generic_read_dir,
.readdir = sysfs_readdir,
};
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 3e1cc062a74..d3be1e7fb48 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -1,15 +1,22 @@
/*
- * file.c - operations for regular (text) files.
+ * fs/sysfs/file.c - sysfs regular (text) file implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
*/
#include <linux/module.h>
-#include <linux/fsnotify.h>
#include <linux/kobject.h>
#include <linux/namei.h>
#include <linux/poll.h>
#include <linux/list.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include "sysfs.h"
@@ -50,14 +57,33 @@ static struct sysfs_ops subsys_sysfs_ops = {
.store = subsys_attr_store,
};
+/*
+ * There's one sysfs_buffer for each open file and one
+ * sysfs_open_dirent for each sysfs_dirent with one or more open
+ * files.
+ *
+ * filp->private_data points to sysfs_buffer and
+ * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open
+ * is protected by sysfs_open_dirent_lock.
+ */
+static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
+
+struct sysfs_open_dirent {
+ atomic_t refcnt;
+ atomic_t event;
+ wait_queue_head_t poll;
+ struct list_head buffers; /* goes through sysfs_buffer.list */
+};
+
struct sysfs_buffer {
size_t count;
loff_t pos;
char * page;
struct sysfs_ops * ops;
- struct semaphore sem;
+ struct mutex mutex;
int needs_read_fill;
int event;
+ struct list_head list;
};
/**
@@ -74,7 +100,7 @@ struct sysfs_buffer {
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
struct sysfs_ops * ops = buffer->ops;
int ret = 0;
ssize_t count;
@@ -88,8 +114,8 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
if (!sysfs_get_active_two(attr_sd))
return -ENODEV;
- buffer->event = atomic_read(&attr_sd->s_event);
- count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
+ buffer->event = atomic_read(&attr_sd->s_attr.open->event);
+ count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
sysfs_put_active_two(attr_sd);
@@ -128,7 +154,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct sysfs_buffer * buffer = file->private_data;
ssize_t retval = 0;
- down(&buffer->sem);
+ mutex_lock(&buffer->mutex);
if (buffer->needs_read_fill) {
retval = fill_read_buffer(file->f_path.dentry,buffer);
if (retval)
@@ -139,7 +165,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count);
out:
- up(&buffer->sem);
+ mutex_unlock(&buffer->mutex);
return retval;
}
@@ -189,7 +215,7 @@ static int
flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
{
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
struct sysfs_ops * ops = buffer->ops;
int rc;
@@ -197,7 +223,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t
if (!sysfs_get_active_two(attr_sd))
return -ENODEV;
- rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
+ rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
sysfs_put_active_two(attr_sd);
@@ -228,20 +254,102 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
struct sysfs_buffer * buffer = file->private_data;
ssize_t len;
- down(&buffer->sem);
+ mutex_lock(&buffer->mutex);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
len = flush_write_buffer(file->f_path.dentry, buffer, len);
if (len > 0)
*ppos += len;
- up(&buffer->sem);
+ mutex_unlock(&buffer->mutex);
return len;
}
+/**
+ * sysfs_get_open_dirent - get or create sysfs_open_dirent
+ * @sd: target sysfs_dirent
+ * @buffer: sysfs_buffer for this instance of open
+ *
+ * If @sd->s_attr.open exists, increment its reference count;
+ * otherwise, create one. @buffer is chained to the buffers
+ * list.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sysfs_get_open_dirent(struct sysfs_dirent *sd,
+ struct sysfs_buffer *buffer)
+{
+ struct sysfs_open_dirent *od, *new_od = NULL;
+
+ retry:
+ spin_lock(&sysfs_open_dirent_lock);
+
+ if (!sd->s_attr.open && new_od) {
+ sd->s_attr.open = new_od;
+ new_od = NULL;
+ }
+
+ od = sd->s_attr.open;
+ if (od) {
+ atomic_inc(&od->refcnt);
+ list_add_tail(&buffer->list, &od->buffers);
+ }
+
+ spin_unlock(&sysfs_open_dirent_lock);
+
+ if (od) {
+ kfree(new_od);
+ return 0;
+ }
+
+ /* not there, initialize a new one and retry */
+ new_od = kmalloc(sizeof(*new_od), GFP_KERNEL);
+ if (!new_od)
+ return -ENOMEM;
+
+ atomic_set(&new_od->refcnt, 0);
+ atomic_set(&new_od->event, 1);
+ init_waitqueue_head(&new_od->poll);
+ INIT_LIST_HEAD(&new_od->buffers);
+ goto retry;
+}
+
+/**
+ * sysfs_put_open_dirent - put sysfs_open_dirent
+ * @sd: target sysfs_dirent
+ * @buffer: associated sysfs_buffer
+ *
+ * Put @sd->s_attr.open and unlink @buffer from the buffers list.
+ * If reference count reaches zero, disassociate and free it.
+ *
+ * LOCKING:
+ * None.
+ */
+static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
+ struct sysfs_buffer *buffer)
+{
+ struct sysfs_open_dirent *od = sd->s_attr.open;
+
+ spin_lock(&sysfs_open_dirent_lock);
+
+ list_del(&buffer->list);
+ if (atomic_dec_and_test(&od->refcnt))
+ sd->s_attr.open = NULL;
+ else
+ od = NULL;
+
+ spin_unlock(&sysfs_open_dirent_lock);
+
+ kfree(od);
+}
+
static int sysfs_open_file(struct inode *inode, struct file *file)
{
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error;
@@ -294,33 +402,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
if (!buffer)
goto err_out;
- init_MUTEX(&buffer->sem);
+ mutex_init(&buffer->mutex);
buffer->needs_read_fill = 1;
buffer->ops = ops;
file->private_data = buffer;
- /* open succeeded, put active references and pin attr_sd */
+ /* make sure we have open dirent struct */
+ error = sysfs_get_open_dirent(attr_sd, buffer);
+ if (error)
+ goto err_free;
+
+ /* open succeeded, put active references */
sysfs_put_active_two(attr_sd);
- sysfs_get(attr_sd);
return 0;
+ err_free:
+ kfree(buffer);
err_out:
sysfs_put_active_two(attr_sd);
return error;
}
-static int sysfs_release(struct inode * inode, struct file * filp)
+static int sysfs_release(struct inode *inode, struct file *filp)
{
- struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
+ struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata;
struct sysfs_buffer *buffer = filp->private_data;
- sysfs_put(attr_sd);
+ sysfs_put_open_dirent(sd, buffer);
+
+ if (buffer->page)
+ free_page((unsigned long)buffer->page);
+ kfree(buffer);
- if (buffer) {
- if (buffer->page)
- free_page((unsigned long)buffer->page);
- kfree(buffer);
- }
return 0;
}
@@ -335,24 +448,24 @@ static int sysfs_release(struct inode * inode, struct file * filp)
* again will not get new data, or reset the state of 'poll'.
* Reminder: this only works for attributes which actively support
* it, and it is not possible to test an attribute from userspace
- * to see if it supports poll (Nether 'poll' or 'select' return
+ * to see if it supports poll (Neither 'poll' nor 'select' return
* an appropriate error code). When in doubt, set a suitable timeout value.
*/
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
{
struct sysfs_buffer * buffer = filp->private_data;
struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
- struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ struct sysfs_open_dirent *od = attr_sd->s_attr.open;
/* need parent for the kobj, grab both */
if (!sysfs_get_active_two(attr_sd))
goto trigger;
- poll_wait(filp, &kobj->poll, wait);
+ poll_wait(filp, &od->poll, wait);
sysfs_put_active_two(attr_sd);
- if (buffer->event != atomic_read(&attr_sd->s_event))
+ if (buffer->event != atomic_read(&od->event))
goto trigger;
return 0;
@@ -373,8 +486,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr)
if (sd && attr)
sd = sysfs_find_dirent(sd, attr);
if (sd) {
- atomic_inc(&sd->s_event);
- wake_up_interruptible(&k->poll);
+ struct sysfs_open_dirent *od;
+
+ spin_lock(&sysfs_open_dirent_lock);
+
+ od = sd->s_attr.open;
+ if (od) {
+ atomic_inc(&od->event);
+ wake_up_interruptible(&od->poll);
+ }
+
+ spin_unlock(&sysfs_open_dirent_lock);
}
mutex_unlock(&sysfs_mutex);
@@ -397,25 +519,21 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
+ int rc;
sd = sysfs_new_dirent(attr->name, mode, type);
if (!sd)
return -ENOMEM;
- sd->s_elem.attr.attr = (void *)attr;
+ sd->s_attr.attr = (void *)attr;
sysfs_addrm_start(&acxt, dir_sd);
+ rc = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_finish(&acxt);
- if (!sysfs_find_dirent(dir_sd, attr->name)) {
- sysfs_add_one(&acxt, sd);
- sysfs_link_sibling(sd);
- }
-
- if (!sysfs_addrm_finish(&acxt)) {
+ if (rc)
sysfs_put(sd);
- return -EEXIST;
- }
- return 0;
+ return rc;
}
@@ -457,42 +575,6 @@ int sysfs_add_file_to_group(struct kobject *kobj,
}
EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
-
-/**
- * sysfs_update_file - update the modified timestamp on an object attribute.
- * @kobj: object we're acting for.
- * @attr: attribute descriptor.
- */
-int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
-{
- struct sysfs_dirent *victim_sd = NULL;
- struct dentry *victim = NULL;
- int rc;
-
- rc = -ENOENT;
- victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
- if (!victim_sd)
- goto out;
-
- victim = sysfs_get_dentry(victim_sd);
- if (IS_ERR(victim)) {
- rc = PTR_ERR(victim);
- victim = NULL;
- goto out;
- }
-
- mutex_lock(&victim->d_inode->i_mutex);
- victim->d_inode->i_mtime = CURRENT_TIME;
- fsnotify_modify(victim);
- mutex_unlock(&victim->d_inode->i_mutex);
- rc = 0;
- out:
- dput(victim);
- sysfs_put(victim_sd);
- return rc;
-}
-
-
/**
* sysfs_chmod_file - update the modified mode value on an object attribute.
* @kobj: object we're acting for.
@@ -513,7 +595,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
if (!victim_sd)
goto out;
+ mutex_lock(&sysfs_rename_mutex);
victim = sysfs_get_dentry(victim_sd);
+ mutex_unlock(&sysfs_rename_mutex);
if (IS_ERR(victim)) {
rc = PTR_ERR(victim);
victim = NULL;
@@ -521,10 +605,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
}
inode = victim->d_inode;
+
mutex_lock(&inode->i_mutex);
+
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
rc = notify_change(victim, &newattrs);
+
+ if (rc == 0) {
+ mutex_lock(&sysfs_mutex);
+ victim_sd->s_mode = newattrs.ia_mode;
+ mutex_unlock(&sysfs_mutex);
+ }
+
mutex_unlock(&inode->i_mutex);
out:
dput(victim);
@@ -632,4 +725,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
EXPORT_SYMBOL_GPL(sysfs_create_file);
EXPORT_SYMBOL_GPL(sysfs_remove_file);
-EXPORT_SYMBOL_GPL(sysfs_update_file);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index f318b73c790..d1972374655 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,8 +13,6 @@
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/err.h>
-#include <linux/fs.h>
-#include <asm/semaphore.h>
#include "sysfs.h"
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 10d1b52899f..9236635111f 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -1,7 +1,11 @@
/*
- * inode.c - basic inode and dentry operations.
+ * fs/sysfs/inode.c - basic sysfs inode and dentry operations
*
- * sysfs is Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
*
* Please see Documentation/filesystems/sysfs.txt for more information.
*/
@@ -14,7 +18,6 @@
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/sched.h>
-#include <asm/semaphore.h>
#include "sysfs.h"
extern struct super_block * sysfs_sb;
@@ -34,16 +37,6 @@ static const struct inode_operations sysfs_inode_operations ={
.setattr = sysfs_setattr,
};
-void sysfs_delete_inode(struct inode *inode)
-{
- /* Free the shadowed directory inode operations */
- if (sysfs_is_shadowed_inode(inode)) {
- kfree(inode->i_op);
- inode->i_op = NULL;
- }
- return generic_delete_inode(inode);
-}
-
int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
{
struct inode * inode = dentry->d_inode;
@@ -133,8 +126,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
*/
static struct lock_class_key sysfs_inode_imutex_key;
+static int sysfs_count_nlink(struct sysfs_dirent *sd)
+{
+ struct sysfs_dirent *child;
+ int nr = 0;
+
+ for (child = sd->s_dir.children; child; child = child->s_sibling)
+ if (sysfs_type(child) == SYSFS_DIR)
+ nr++;
+
+ return nr + 2;
+}
+
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
+ struct bin_attribute *bin_attr;
+
inode->i_blocks = 0;
inode->i_mapping->a_ops = &sysfs_aops;
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
@@ -150,6 +157,32 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
set_inode_attr(inode, sd->s_iattr);
} else
set_default_inode_attr(inode, sd->s_mode);
+
+
+ /* initialize inode according to type */
+ switch (sysfs_type(sd)) {
+ case SYSFS_DIR:
+ inode->i_op = &sysfs_dir_inode_operations;
+ inode->i_fop = &sysfs_dir_operations;
+ inode->i_nlink = sysfs_count_nlink(sd);
+ break;
+ case SYSFS_KOBJ_ATTR:
+ inode->i_size = PAGE_SIZE;
+ inode->i_fop = &sysfs_file_operations;
+ break;
+ case SYSFS_KOBJ_BIN_ATTR:
+ bin_attr = sd->s_bin_attr.bin_attr;
+ inode->i_size = bin_attr->size;
+ inode->i_fop = &bin_fops;
+ break;
+ case SYSFS_KOBJ_LINK:
+ inode->i_op = &sysfs_symlink_inode_operations;
+ break;
+ default:
+ BUG();
+ }
+
+ unlock_new_inode(inode);
}
/**
@@ -177,50 +210,24 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
return inode;
}
-/**
- * sysfs_instantiate - instantiate dentry
- * @dentry: dentry to be instantiated
- * @inode: inode associated with @sd
- *
- * Unlock @inode if locked and instantiate @dentry with @inode.
- *
- * LOCKING:
- * None.
- */
-void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
-{
- BUG_ON(!dentry || dentry->d_inode);
-
- if (inode->i_state & I_NEW)
- unlock_new_inode(inode);
-
- d_instantiate(dentry, inode);
-}
-
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
{
struct sysfs_addrm_cxt acxt;
- struct sysfs_dirent **pos, *sd;
+ struct sysfs_dirent *sd;
if (!dir_sd)
return -ENOENT;
sysfs_addrm_start(&acxt, dir_sd);
- for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
- sd = *pos;
-
- if (!sysfs_type(sd))
- continue;
- if (!strcmp(sd->s_name, name)) {
- *pos = sd->s_sibling;
- sd->s_sibling = NULL;
- sysfs_remove_one(&acxt, sd);
- break;
- }
- }
+ sd = sysfs_find_dirent(dir_sd, name);
+ if (sd)
+ sysfs_remove_one(&acxt, sd);
+
+ sysfs_addrm_finish(&acxt);
- if (sysfs_addrm_finish(&acxt))
+ if (sd)
return 0;
- return -ENOENT;
+ else
+ return -ENOENT;
}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index fbc7b65fe26..c76c540be3c 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -1,5 +1,13 @@
/*
- * mount.c - operations for initializing and mounting sysfs.
+ * fs/sysfs/symlink.c - operations for initializing and mounting sysfs
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
*/
#define DEBUG
@@ -8,25 +16,25 @@
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/init.h>
-#include <asm/semaphore.h>
#include "sysfs.h"
/* Random magic number */
#define SYSFS_MAGIC 0x62656572
-struct vfsmount *sysfs_mount;
+static struct vfsmount *sysfs_mount;
struct super_block * sysfs_sb = NULL;
struct kmem_cache *sysfs_dir_cachep;
static const struct super_operations sysfs_ops = {
.statfs = simple_statfs,
- .drop_inode = sysfs_delete_inode,
+ .drop_inode = generic_delete_inode,
};
struct sysfs_dirent sysfs_root = {
+ .s_name = "",
.s_count = ATOMIC_INIT(1),
- .s_flags = SYSFS_ROOT,
+ .s_flags = SYSFS_DIR,
.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
.s_ino = 1,
};
@@ -50,11 +58,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM;
}
- inode->i_op = &sysfs_dir_inode_operations;
- inode->i_fop = &sysfs_dir_operations;
- inc_nlink(inode); /* directory, account for "." */
- unlock_new_inode(inode);
-
/* instantiate and link root dentry */
root = d_alloc_root(inode);
if (!root) {
@@ -62,7 +65,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
iput(inode);
return -ENOMEM;
}
- sysfs_root.s_dentry = root;
root->d_fsdata = &sysfs_root;
sb->s_root = root;
return 0;
@@ -77,7 +79,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type,
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.get_sb = sysfs_get_sb,
- .kill_sb = kill_litter_super,
+ .kill_sb = kill_anon_super,
};
int __init sysfs_init(void)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 4ce687f0b5d..3eac20c63c4 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -1,5 +1,13 @@
/*
- * symlink.c - operations for sysfs symlinks.
+ * fs/sysfs/symlink.c - sysfs symlink implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
*/
#include <linux/fs.h>
@@ -7,7 +15,7 @@
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/namei.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "sysfs.h"
@@ -60,10 +68,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
BUG_ON(!name);
- if (!kobj) {
- if (sysfs_mount && sysfs_mount->mnt_sb)
- parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
- } else
+ if (!kobj)
+ parent_sd = &sysfs_root;
+ else
parent_sd = kobj->sd;
error = -EFAULT;
@@ -87,20 +94,15 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
if (!sd)
goto out_put;
- sd->s_elem.symlink.target_sd = target_sd;
+ sd->s_symlink.target_sd = target_sd;
target_sd = NULL; /* reference is now owned by the symlink */
sysfs_addrm_start(&acxt, parent_sd);
+ error = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_finish(&acxt);
- if (!sysfs_find_dirent(parent_sd, name)) {
- sysfs_add_one(&acxt, sd);
- sysfs_link_sibling(sd);
- }
-
- if (!sysfs_addrm_finish(&acxt)) {
- error = -EEXIST;
+ if (error)
goto out_put;
- }
return 0;
@@ -148,7 +150,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path)
{
struct sysfs_dirent *sd = dentry->d_fsdata;
struct sysfs_dirent *parent_sd = sd->s_parent;
- struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
+ struct sysfs_dirent *target_sd = sd->s_symlink.target_sd;
int error;
mutex_lock(&sysfs_mutex);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 6b8c8d76d30..f0326f281d1 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -1,20 +1,39 @@
+/*
+ * fs/sysfs/sysfs.h - sysfs internal header file
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+struct sysfs_open_dirent;
+
+/* type-specific structures for sysfs_dirent->s_* union members */
struct sysfs_elem_dir {
- struct kobject * kobj;
+ struct kobject *kobj;
+ /* children list starts here and goes through sd->s_sibling */
+ struct sysfs_dirent *children;
};
struct sysfs_elem_symlink {
- struct sysfs_dirent * target_sd;
+ struct sysfs_dirent *target_sd;
};
struct sysfs_elem_attr {
- struct attribute * attr;
+ struct attribute *attr;
+ struct sysfs_open_dirent *open;
};
struct sysfs_elem_bin_attr {
- struct bin_attribute * bin_attr;
+ struct bin_attribute *bin_attr;
};
/*
+ * sysfs_dirent - the building block of sysfs hierarchy. Each and
+ * every sysfs node is represented by single sysfs_dirent.
+ *
* As long as s_count reference is held, the sysfs_dirent itself is
* accessible. Dereferencing s_elem or any other outer entity
* requires s_active reference.
@@ -22,28 +41,43 @@ struct sysfs_elem_bin_attr {
struct sysfs_dirent {
atomic_t s_count;
atomic_t s_active;
- struct sysfs_dirent * s_parent;
- struct sysfs_dirent * s_sibling;
- struct sysfs_dirent * s_children;
- const char * s_name;
+ struct sysfs_dirent *s_parent;
+ struct sysfs_dirent *s_sibling;
+ const char *s_name;
union {
- struct sysfs_elem_dir dir;
- struct sysfs_elem_symlink symlink;
- struct sysfs_elem_attr attr;
- struct sysfs_elem_bin_attr bin_attr;
- } s_elem;
+ struct sysfs_elem_dir s_dir;
+ struct sysfs_elem_symlink s_symlink;
+ struct sysfs_elem_attr s_attr;
+ struct sysfs_elem_bin_attr s_bin_attr;
+ };
unsigned int s_flags;
- umode_t s_mode;
ino_t s_ino;
- struct dentry * s_dentry;
- struct iattr * s_iattr;
- atomic_t s_event;
+ umode_t s_mode;
+ struct iattr *s_iattr;
};
-#define SD_DEACTIVATED_BIAS INT_MIN
+#define SD_DEACTIVATED_BIAS INT_MIN
+
+#define SYSFS_TYPE_MASK 0x00ff
+#define SYSFS_DIR 0x0001
+#define SYSFS_KOBJ_ATTR 0x0002
+#define SYSFS_KOBJ_BIN_ATTR 0x0004
+#define SYSFS_KOBJ_LINK 0x0008
+#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
+
+#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
+#define SYSFS_FLAG_REMOVED 0x0200
+
+static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
+{
+ return sd->s_flags & SYSFS_TYPE_MASK;
+}
+/*
+ * Context structure to be used while adding/removing nodes.
+ */
struct sysfs_addrm_cxt {
struct sysfs_dirent *parent_sd;
struct inode *parent_inode;
@@ -51,63 +85,47 @@ struct sysfs_addrm_cxt {
int cnt;
};
-extern struct vfsmount * sysfs_mount;
+/*
+ * mount.c
+ */
extern struct sysfs_dirent sysfs_root;
+extern struct super_block *sysfs_sb;
extern struct kmem_cache *sysfs_dir_cachep;
-extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
-extern void sysfs_link_sibling(struct sysfs_dirent *sd);
-extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
-extern void sysfs_put_active(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
-extern void sysfs_put_active_two(struct sysfs_dirent *sd);
-extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
- struct sysfs_dirent *parent_sd);
-extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt,
- struct sysfs_dirent *sd);
-extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
- struct sysfs_dirent *sd);
-extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
-
-extern void sysfs_delete_inode(struct inode *inode);
-extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
-extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
-
-extern void release_sysfs_dirent(struct sysfs_dirent * sd);
-extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
- const unsigned char *name);
-extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
- const unsigned char *name);
-extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
- int type);
-
-extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
- const struct attribute *attr, int type);
-extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
-extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
-
-extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
- struct sysfs_dirent **p_sd);
-extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
-
-extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
-
-extern spinlock_t sysfs_assoc_lock;
+/*
+ * dir.c
+ */
extern struct mutex sysfs_mutex;
-extern struct super_block * sysfs_sb;
+extern struct mutex sysfs_rename_mutex;
+extern spinlock_t sysfs_assoc_lock;
+
extern const struct file_operations sysfs_dir_operations;
-extern const struct file_operations sysfs_file_operations;
-extern const struct file_operations bin_fops;
extern const struct inode_operations sysfs_dir_inode_operations;
-extern const struct inode_operations sysfs_symlink_inode_operations;
-
-static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
-{
- return sd->s_flags & SYSFS_TYPE_MASK;
-}
-static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
+void sysfs_put_active(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
+void sysfs_put_active_two(struct sysfs_dirent *sd);
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *parent_sd);
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
+
+struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name);
+struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name);
+struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
+
+void release_sysfs_dirent(struct sysfs_dirent *sd);
+
+int sysfs_create_subdir(struct kobject *kobj, const char *name,
+ struct sysfs_dirent **p_sd);
+void sysfs_remove_subdir(struct sysfs_dirent *sd);
+
+static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd)
{
if (sd) {
WARN_ON(!atomic_read(&sd->s_count));
@@ -116,13 +134,33 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
return sd;
}
-static inline void sysfs_put(struct sysfs_dirent * sd)
+static inline void sysfs_put(struct sysfs_dirent *sd)
{
if (sd && atomic_dec_and_test(&sd->s_count))
release_sysfs_dirent(sd);
}
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
- return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
+/*
+ * inode.c
+ */
+struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
+int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
+
+/*
+ * file.c
+ */
+extern const struct file_operations sysfs_file_operations;
+
+int sysfs_add_file(struct sysfs_dirent *dir_sd,
+ const struct attribute *attr, int type);
+
+/*
+ * bin.c
+ */
+extern const struct file_operations bin_fops;
+
+/*
+ * symlink.c
+ */
+extern const struct inode_operations sysfs_symlink_inode_operations;
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 3f13519436a..6f4c29e9c3d 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -323,7 +323,7 @@ xfs_iomap_valid(
/*
* BIO completion handler for buffered IO.
*/
-STATIC int
+STATIC void
xfs_end_bio(
struct bio *bio,
int error)
@@ -339,7 +339,6 @@ xfs_end_bio(
bio_put(bio);
xfs_finish_ioend(ioend, 0);
- return 0;
}
STATIC void
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 6a75f4d984a..39f44ee572e 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1103,7 +1103,7 @@ _xfs_buf_ioend(
}
}
-STATIC int
+STATIC void
xfs_buf_bio_end_io(
struct bio *bio,
int error)
@@ -1139,7 +1139,6 @@ xfs_buf_bio_end_io(
_xfs_buf_ioend(bp, 1);
bio_put(bio);
- return 0;
}
STATIC void
diff --git a/include/asm-arm/arch-davinci/i2c.h b/include/asm-arm/arch-davinci/i2c.h
new file mode 100644
index 00000000000..e2f54168abd
--- /dev/null
+++ b/include/asm-arm/arch-davinci/i2c.h
@@ -0,0 +1,21 @@
+/*
+ * DaVinci I2C controller platfrom_device info
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@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_ARCH_I2C_H
+#define __ASM_ARCH_I2C_H
+
+/* All frequencies are expressed in kHz */
+struct davinci_i2c_platform_data {
+ unsigned int bus_freq; /* standard bus frequency */
+ unsigned int bus_delay; /* transaction delay */
+};
+
+#endif /* __ASM_ARCH_I2C_H */
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 1d3caa42a38..eebe56e74d6 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -228,12 +228,12 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
*/
#ifndef ioread8
#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; })
-#define ioread16(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
-#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
+#define ioread16(p) ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __v; })
+#define ioread32(p) ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __v; })
#define iowrite8(v,p) __raw_writeb(v, p)
-#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p)
-#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p)
+#define iowrite16(v,p) __raw_writew((__force __u16)cpu_to_le16(v), p)
+#define iowrite32(v,p) __raw_writel((__force __u32)cpu_to_le32(v), p)
#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
diff --git a/include/asm-blackfin/mach-bf548/bf54x_keys.h b/include/asm-blackfin/mach-bf548/bf54x_keys.h
new file mode 100644
index 00000000000..1fb4ec77cc2
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/bf54x_keys.h
@@ -0,0 +1,17 @@
+#ifndef _BFIN_KPAD_H
+#define _BFIN_KPAD_H
+
+struct bfin_kpad_platform_data {
+ int rows;
+ int cols;
+ const unsigned int *keymap;
+ unsigned short keymapsize;
+ unsigned short repeat;
+ u32 debounce_time; /* in ns */
+ u32 coldrive_time; /* in ns */
+ u32 keyup_test_interval; /* in ms */
+};
+
+#define KEYVAL(col, row, val) (((1 << col) << 24) | ((1 << row) << 16) | (val))
+
+#endif
diff --git a/include/asm-blackfin/mach-bf548/dma.h b/include/asm-blackfin/mach-bf548/dma.h
index fcc8b4c34c6..14cb10cc24a 100644
--- a/include/asm-blackfin/mach-bf548/dma.h
+++ b/include/asm-blackfin/mach-bf548/dma.h
@@ -55,6 +55,7 @@
#define CH_SPORT3_RX 20
#define CH_SPORT3_TX 21
#define CH_SDH 22
+#define CH_NFC 22
#define CH_SPI2 23
#define CH_MEM_STREAM0_DEST 24
diff --git a/include/asm-blackfin/nand.h b/include/asm-blackfin/nand.h
new file mode 100644
index 00000000000..afbaafa793f
--- /dev/null
+++ b/include/asm-blackfin/nand.h
@@ -0,0 +1,47 @@
+/* linux/include/asm-blackfin/nand.h
+ *
+ * Copyright (c) 2007 Analog Devices, Inc.
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * BF5XX - NAND flash controller platfrom_device info
+ *
+ * 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.
+ */
+
+/* struct bf5xx_nand_platform
+ *
+ * define a interface between platfrom board specific code and
+ * bf54x NFC driver.
+ *
+ * nr_partitions = number of partitions pointed to be partitoons (or zero)
+ * partitions = mtd partition list
+ */
+
+#define NFC_PG_SIZE_256 0
+#define NFC_PG_SIZE_512 1
+#define NFC_PG_SIZE_OFFSET 9
+
+#define NFC_NWIDTH_8 0
+#define NFC_NWIDTH_16 1
+#define NFC_NWIDTH_OFFSET 8
+
+#define NFC_RDDLY_OFFSET 4
+#define NFC_WRDLY_OFFSET 0
+
+#define NFC_STAT_NBUSY 1
+
+struct bf5xx_nand_platform {
+ /* NAND chip information */
+ unsigned short page_size;
+ unsigned short data_width;
+
+ /* RD/WR strobe delay timing information, all times in SCLK cycles */
+ unsigned short rd_dly;
+ unsigned short wr_dly;
+
+ /* NAND MTD partition information */
+ int nr_partitions;
+ struct mtd_partition *partitions;
+};
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index 6931af525da..9f5663ba19f 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -253,7 +253,10 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
__typeof__(*(ptr)) __xg_new = (new); \
\
switch (sizeof(__xg_orig)) { \
- case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \
+ case 4: __xg_orig = (__force __typeof__(*ptr)) \
+ __cmpxchg_32((__force uint32_t *)__xg_ptr, \
+ (__force uint32_t)__xg_test, \
+ (__force uint32_t)__xg_new); break; \
default: \
__xg_orig = 0; \
asm volatile("break"); \
diff --git a/include/asm-generic/libata-portmap.h b/include/asm-generic/libata-portmap.h
index 62fb3618293..cf14f2ff40b 100644
--- a/include/asm-generic/libata-portmap.h
+++ b/include/asm-generic/libata-portmap.h
@@ -1,12 +1,7 @@
#ifndef __ASM_GENERIC_LIBATA_PORTMAP_H
#define __ASM_GENERIC_LIBATA_PORTMAP_H
-#define ATA_PRIMARY_CMD 0x1F0
-#define ATA_PRIMARY_CTL 0x3F6
#define ATA_PRIMARY_IRQ(dev) 14
-
-#define ATA_SECONDARY_CMD 0x170
-#define ATA_SECONDARY_CTL 0x376
#define ATA_SECONDARY_IRQ(dev) 15
#endif
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 0240e0506a0..5615440027e 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -153,7 +153,8 @@
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
*(.text) \
- *(.text.init.refok)
+ *(.text.init.refok) \
+ *(.exit.text.refok)
/* sched.text is aling to function alignment to secure we have same
* address even at second ld pass when generating System.map */
diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
index 6299b51575b..3ca6d5c14b2 100644
--- a/include/asm-ia64/dma-mapping.h
+++ b/include/asm-ia64/dma-mapping.h
@@ -6,6 +6,7 @@
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <asm/machvec.h>
+#include <asm/scatterlist.h>
#define dma_alloc_coherent platform_dma_alloc_coherent
/* coherent mem. is cheap */
diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
index edd5d01028d..823553bf12e 100644
--- a/include/asm-ia64/mca.h
+++ b/include/asm-ia64/mca.h
@@ -151,6 +151,8 @@ extern void ia64_mca_cmc_vector_setup(void);
extern int ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *));
extern void ia64_unreg_MCA_extension(void);
extern u64 ia64_get_rnat(u64 *);
+extern void ia64_mca_printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
struct ia64_mca_notify_die {
struct ia64_sal_os_state *sos;
diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
index 46cadf5aaac..1f5412d6f9b 100644
--- a/include/asm-ia64/sal.h
+++ b/include/asm-ia64/sal.h
@@ -46,25 +46,28 @@
extern spinlock_t sal_lock;
/* SAL spec _requires_ eight args for each call. */
-#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7) \
- result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7)
+#define __IA64_FW_CALL(entry,result,a0,a1,a2,a3,a4,a5,a6,a7) \
+ result = (*entry)(a0,a1,a2,a3,a4,a5,a6,a7)
-# define SAL_CALL(result,args...) do { \
+# define IA64_FW_CALL(entry,result,args...) do { \
unsigned long __ia64_sc_flags; \
struct ia64_fpreg __ia64_sc_fr[6]; \
ia64_save_scratch_fpregs(__ia64_sc_fr); \
spin_lock_irqsave(&sal_lock, __ia64_sc_flags); \
- __SAL_CALL(result, args); \
+ __IA64_FW_CALL(entry, result, args); \
spin_unlock_irqrestore(&sal_lock, __ia64_sc_flags); \
ia64_load_scratch_fpregs(__ia64_sc_fr); \
} while (0)
+# define SAL_CALL(result,args...) \
+ IA64_FW_CALL(ia64_sal, result, args);
+
# define SAL_CALL_NOLOCK(result,args...) do { \
unsigned long __ia64_scn_flags; \
struct ia64_fpreg __ia64_scn_fr[6]; \
ia64_save_scratch_fpregs(__ia64_scn_fr); \
local_irq_save(__ia64_scn_flags); \
- __SAL_CALL(result, args); \
+ __IA64_FW_CALL(ia64_sal, result, args); \
local_irq_restore(__ia64_scn_flags); \
ia64_load_scratch_fpregs(__ia64_scn_fr); \
} while (0)
@@ -73,7 +76,7 @@ extern spinlock_t sal_lock;
struct ia64_fpreg __ia64_scs_fr[6]; \
ia64_save_scratch_fpregs(__ia64_scs_fr); \
preempt_disable(); \
- __SAL_CALL(result, args); \
+ __IA64_FW_CALL(ia64_sal, result, args); \
preempt_enable(); \
ia64_load_scratch_fpregs(__ia64_scs_fr); \
} while (0)
diff --git a/include/asm-m68k/Kbuild b/include/asm-m68k/Kbuild
index c68e1680da0..1a922fad76f 100644
--- a/include/asm-m68k/Kbuild
+++ b/include/asm-m68k/Kbuild
@@ -1 +1,2 @@
include include/asm-generic/Kbuild.asm
+header-y += cachectl.h
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
index a30fe9c6414..87f77b11931 100644
--- a/include/asm-m68k/unistd.h
+++ b/include/asm-m68k/unistd.h
@@ -351,6 +351,9 @@
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+/* whitelist for checksyscalls */
+#define __IGNORE_restart_syscall
+
/*
* "Conditional" syscalls
*
diff --git a/include/asm-mips/fw/cfe/cfe_api.h b/include/asm-mips/fw/cfe/cfe_api.h
index 41cf050b681..1003e7156bf 100644
--- a/include/asm-mips/fw/cfe/cfe_api.h
+++ b/include/asm-mips/fw/cfe/cfe_api.h
@@ -154,7 +154,7 @@ int64_t cfe_getticks(void);
#define cfe_readblk(a, b, c, d) __cfe_readblk(a, b, c, d)
#define cfe_setenv(a, b) __cfe_setenv(a, b)
#define cfe_write(a, b, c) __cfe_write(a, b, c)
-#define cfe_writeblk(a, b, c, d __cfe_writeblk(a, b, c, d)
+#define cfe_writeblk(a, b, c, d) __cfe_writeblk(a, b, c, d)
#endif /* CFE_API_IMPL_NAMESPACE */
int cfe_close(int handle);
diff --git a/include/asm-mips/mach-au1x00/prom.h b/include/asm-mips/mach-au1x00/prom.h
new file mode 100644
index 00000000000..e38715577c5
--- /dev/null
+++ b/include/asm-mips/mach-au1x00/prom.h
@@ -0,0 +1,13 @@
+#ifndef __AU1X00_PROM_H
+#define __AU1X00_PROM_H
+
+extern int prom_argc;
+extern char **prom_argv;
+extern char **prom_envp;
+
+extern void prom_init_cmdline(void);
+extern char *prom_getcmdline(void);
+extern char *prom_getenv(char *envname);
+extern int prom_get_ethernet_addr(char *ethernet_addr);
+
+#endif
diff --git a/include/asm-powerpc/dcr-mmio.h b/include/asm-powerpc/dcr-mmio.h
index 6b82c3ba495..08532ff1899 100644
--- a/include/asm-powerpc/dcr-mmio.h
+++ b/include/asm-powerpc/dcr-mmio.h
@@ -33,16 +33,16 @@ typedef struct {
extern dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
unsigned int dcr_c);
-extern void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c);
+extern void dcr_unmap(dcr_host_t host, unsigned int dcr_c);
static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n)
{
- return in_be32(host.token + dcr_n * host.stride);
+ return in_be32(host.token + ((host.base + dcr_n) * host.stride));
}
static inline void dcr_write(dcr_host_t host, unsigned int dcr_n, u32 value)
{
- out_be32(host.token + dcr_n * host.stride, value);
+ out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
}
extern u64 of_translate_dcr_address(struct device_node *dev,
diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h
index f41058c0f6c..8dbb1ab0aa0 100644
--- a/include/asm-powerpc/dcr-native.h
+++ b/include/asm-powerpc/dcr-native.h
@@ -29,9 +29,9 @@ typedef struct {
#define DCR_MAP_OK(host) (1)
#define dcr_map(dev, dcr_n, dcr_c) ((dcr_host_t){ .base = (dcr_n) })
-#define dcr_unmap(host, dcr_n, dcr_c) do {} while (0)
-#define dcr_read(host, dcr_n) mfdcr(dcr_n)
-#define dcr_write(host, dcr_n, value) mtdcr(dcr_n, value)
+#define dcr_unmap(host, dcr_c) do {} while (0)
+#define dcr_read(host, dcr_n) mfdcr(dcr_n + host.base)
+#define dcr_write(host, dcr_n, value) mtdcr(dcr_n + host.base, value)
/* Device Control Registers */
void __mtdcr(int reg, unsigned int val);
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index affba7052fb..0d0589ef8ea 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -138,12 +138,12 @@ DEF_MMIO_IN_BE(in_be64, 64, ld);
/* There is no asm instructions for 64 bits reverse loads and stores */
static inline u64 in_le64(const volatile u64 __iomem *addr)
{
- return le64_to_cpu(in_be64(addr));
+ return swab64(in_be64(addr));
}
static inline void out_le64(volatile u64 __iomem *addr, u64 val)
{
- out_be64(addr, cpu_to_le64(val));
+ out_be64(addr, swab64(val));
}
#endif /* __powerpc64__ */
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index ec2a8a2c737..93262f2546a 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -20,7 +20,7 @@ struct of_device
extern ssize_t of_device_get_modalias(struct of_device *ofdev,
char *str, ssize_t len);
extern int of_device_uevent(struct device *dev,
- char **envp, int num_envp, char *buffer, int buffer_size);
+ struct kobj_uevent_env *env);
/* This is just here during the transition */
#include <linux/of_device.h>
diff --git a/include/asm-s390/cache.h b/include/asm-s390/cache.h
index cdf431b061b..9b866816863 100644
--- a/include/asm-s390/cache.h
+++ b/include/asm-s390/cache.h
@@ -14,8 +14,6 @@
#define L1_CACHE_BYTES 256
#define L1_CACHE_SHIFT 8
-#define ARCH_KMALLOC_MINALIGN 8
-
#define __read_mostly __attribute__((__section__(".data.read_mostly")))
#endif
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index 1aeda27d5a8..066aa70518c 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -67,36 +67,55 @@ ccw_device_id_match(const struct ccw_device_id *array,
return NULL;
}
-/* The struct ccw device is our replacement for the globally accessible
- * ioinfo array. ioinfo will mutate into a subchannel device later.
+/**
+ * struct ccw_device - channel attached device
+ * @ccwlock: pointer to device lock
+ * @id: id of this device
+ * @drv: ccw driver for this device
+ * @dev: embedded device structure
+ * @online: online status of device
+ * @handler: interrupt handler
*
- * Reference: Documentation/s390/driver-model.txt */
+ * @handler is a member of the device rather than the driver since a driver
+ * can have different interrupt handlers for different ccw devices
+ * (multi-subchannel drivers).
+ */
struct ccw_device {
spinlock_t *ccwlock;
+/* private: */
struct ccw_device_private *private; /* cio private information */
- struct ccw_device_id id; /* id of this device, driver_info is
- set by ccw_find_driver */
- struct ccw_driver *drv; /* */
- struct device dev; /* */
+/* public: */
+ struct ccw_device_id id;
+ struct ccw_driver *drv;
+ struct device dev;
int online;
- /* This is sick, but a driver can have different interrupt handlers
- for different ccw_devices (multi-subchannel drivers)... */
void (*handler) (struct ccw_device *, unsigned long, struct irb *);
};
-/* Each ccw driver registers with the ccw root bus */
+/**
+ * struct ccw driver - device driver for channel attached devices
+ * @owner: owning module
+ * @ids: ids supported by this driver
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: called when setting device online
+ * @set_offline: called when setting device offline
+ * @notify: notify driver of device state changes
+ * @shutdown: called at device shutdown
+ * @driver: embedded device driver structure
+ * @name: device driver name
+ */
struct ccw_driver {
- struct module *owner; /* for automatic MOD_INC_USE_COUNT */
- struct ccw_device_id *ids; /* probe driver with these devs */
- int (*probe) (struct ccw_device *); /* ask driver to probe dev */
+ struct module *owner;
+ struct ccw_device_id *ids;
+ int (*probe) (struct ccw_device *);
void (*remove) (struct ccw_device *);
- /* device is no longer available */
int (*set_online) (struct ccw_device *);
int (*set_offline) (struct ccw_device *);
int (*notify) (struct ccw_device *, int);
- struct device_driver driver; /* higher level structure, don't init
- this from your driver */
+ void (*shutdown) (struct ccw_device *);
+ struct device_driver driver;
char *name;
};
@@ -124,36 +143,10 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
/* Allow forced onlining of boxed devices. */
#define CCWDEV_ALLOW_FORCE 0x0008
-/*
- * ccw_device_start()
- *
- * Start a S/390 channel program. When the interrupt arrives, the
- * IRQ handler is called, either immediately, delayed (dev-end missing,
- * or sense required) or never (no IRQ handler registered).
- * Depending on the action taken, ccw_device_start() returns:
- * 0 - Success
- * -EBUSY - Device busy, or status pending
- * -ENODEV - Device not operational
- * -EINVAL - Device invalid for operation
- */
extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, unsigned long);
-/*
- * ccw_device_start_timeout()
- *
- * This function notifies the device driver if the channel program has not
- * completed during the specified time. If a timeout occurs, the channel
- * program is terminated via xsch(), hsch() or csch().
- */
extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, unsigned long, int);
-/*
- * ccw_device_start_key()
- * ccw_device_start_key_timeout()
- *
- * Same as ccw_device_start() and ccw_device_start_timeout(), except a
- * storage key != default key can be provided for the I/O.
- */
extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, __u8, unsigned long);
extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *,
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index 925b3ddfa14..7109c7cab87 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -4,19 +4,41 @@
struct ccw_device;
struct ccw_driver;
+/**
+ * struct ccwgroup_device - ccw group device
+ * @creator_id: unique number of the driver
+ * @state: online/offline state
+ * @count: number of attached slave devices
+ * @dev: embedded device structure
+ * @cdev: variable number of slave devices, allocated as needed
+ */
struct ccwgroup_device {
- unsigned long creator_id; /* unique number of the driver */
+ unsigned long creator_id;
enum {
CCWGROUP_OFFLINE,
CCWGROUP_ONLINE,
} state;
+/* private: */
atomic_t onoff;
struct mutex reg_mutex;
- unsigned int count; /* number of attached slave devices */
- struct device dev; /* master device */
- struct ccw_device *cdev[0]; /* variable number, allocate as needed */
+/* public: */
+ unsigned int count;
+ struct device dev;
+ struct ccw_device *cdev[0];
};
+/**
+ * struct ccwgroup_driver - driver for ccw group devices
+ * @owner: driver owner
+ * @name: driver name
+ * @max_slaves: maximum number of slave devices
+ * @driver_id: unique id
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: function called when device is set online
+ * @set_offline: function called when device is set offline
+ * @driver: embedded driver structure
+ */
struct ccwgroup_driver {
struct module *owner;
char *name;
@@ -28,7 +50,7 @@ struct ccwgroup_driver {
int (*set_online) (struct ccwgroup_device *);
int (*set_offline) (struct ccwgroup_device *);
- struct device_driver driver; /* this driver */
+ struct device_driver driver;
};
extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 1982fb34416..2f08c16e44a 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -15,30 +15,50 @@
#define LPM_ANYPATH 0xff
#define __MAX_CSSID 0
-/*
- * subchannel status word
+/**
+ * struct scsw - subchannel status word
+ * @key: subchannel key
+ * @sctl: suspend control
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @pfch: prefetch
+ * @isic: initial-status interruption control
+ * @alcc: adress-limit checking control
+ * @ssi: supress-suspended interruption
+ * @zcc: zero condition code
+ * @ectl: extended control
+ * @pno: path not operational
+ * @res: reserved
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @cpa: channel program address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @count: residual count
*/
struct scsw {
- __u32 key : 4; /* subchannel key */
- __u32 sctl : 1; /* suspend control */
- __u32 eswf : 1; /* ESW format */
- __u32 cc : 2; /* deferred condition code */
- __u32 fmt : 1; /* format */
- __u32 pfch : 1; /* prefetch */
- __u32 isic : 1; /* initial-status interruption control */
- __u32 alcc : 1; /* address-limit checking control */
- __u32 ssi : 1; /* supress-suspended interruption */
- __u32 zcc : 1; /* zero condition code */
- __u32 ectl : 1; /* extended control */
- __u32 pno : 1; /* path not operational */
- __u32 res : 1; /* reserved */
- __u32 fctl : 3; /* function control */
- __u32 actl : 7; /* activity control */
- __u32 stctl : 5; /* status control */
- __u32 cpa; /* channel program address */
- __u32 dstat : 8; /* device status */
- __u32 cstat : 8; /* subchannel status */
- __u32 count : 16; /* residual count */
+ __u32 key : 4;
+ __u32 sctl : 1;
+ __u32 eswf : 1;
+ __u32 cc : 2;
+ __u32 fmt : 1;
+ __u32 pfch : 1;
+ __u32 isic : 1;
+ __u32 alcc : 1;
+ __u32 ssi : 1;
+ __u32 zcc : 1;
+ __u32 ectl : 1;
+ __u32 pno : 1;
+ __u32 res : 1;
+ __u32 fctl : 3;
+ __u32 actl : 7;
+ __u32 stctl : 5;
+ __u32 cpa;
+ __u32 dstat : 8;
+ __u32 cstat : 8;
+ __u32 count : 16;
} __attribute__ ((packed));
#define SCSW_FCTL_CLEAR_FUNC 0x1
@@ -110,11 +130,22 @@ struct scsw {
#define SNS2_ENV_DATA_PRESENT 0x10
#define SNS2_INPRECISE_END 0x04
+/**
+ * struct ccw1 - channel command word
+ * @cmd_code: command code
+ * @flags: flags, like IDA adressing, etc.
+ * @count: byte count
+ * @cda: data address
+ *
+ * The ccw is the basic structure to build channel programs that perform
+ * operations with the device or the control unit. Only Format-1 channel
+ * command words are supported.
+ */
struct ccw1 {
- __u8 cmd_code; /* command code */
- __u8 flags; /* flags, like IDA addressing, etc. */
- __u16 count; /* byte count */
- __u32 cda; /* data address */
+ __u8 cmd_code;
+ __u8 flags;
+ __u16 count;
+ __u32 cda;
} __attribute__ ((packed,aligned(8)));
#define CCW_FLAG_DC 0x80
@@ -140,102 +171,162 @@ struct ccw1 {
#define SENSE_MAX_COUNT 0x20
+/**
+ * struct erw - extended report word
+ * @res0: reserved
+ * @auth: authorization check
+ * @pvrf: path-verification-required flag
+ * @cpt: channel-path timeout
+ * @fsavf: failing storage address validity flag
+ * @cons: concurrent sense
+ * @scavf: secondary ccw address validity flag
+ * @fsaf: failing storage address format
+ * @scnt: sense count, if @cons == %1
+ * @res16: reserved
+ */
struct erw {
- __u32 res0 : 3; /* reserved */
- __u32 auth : 1; /* Authorization check */
- __u32 pvrf : 1; /* path-verification-required flag */
- __u32 cpt : 1; /* channel-path timeout */
- __u32 fsavf : 1; /* Failing storage address validity flag */
- __u32 cons : 1; /* concurrent-sense */
- __u32 scavf : 1; /* Secondary ccw address validity flag */
- __u32 fsaf : 1; /* Failing storage address format */
- __u32 scnt : 6; /* sense count if cons == 1 */
- __u32 res16 : 16; /* reserved */
+ __u32 res0 : 3;
+ __u32 auth : 1;
+ __u32 pvrf : 1;
+ __u32 cpt : 1;
+ __u32 fsavf : 1;
+ __u32 cons : 1;
+ __u32 scavf : 1;
+ __u32 fsaf : 1;
+ __u32 scnt : 6;
+ __u32 res16 : 16;
} __attribute__ ((packed));
-/*
- * subchannel logout area
+/**
+ * struct sublog - subchannel logout area
+ * @res0: reserved
+ * @esf: extended status flags
+ * @lpum: last path used mask
+ * @arep: ancillary report
+ * @fvf: field-validity flags
+ * @sacc: storage access code
+ * @termc: termination code
+ * @devsc: device-status check
+ * @serr: secondary error
+ * @ioerr: i/o-error alert
+ * @seqc: sequence code
*/
struct sublog {
- __u32 res0 : 1; /* reserved */
- __u32 esf : 7; /* extended status flags */
- __u32 lpum : 8; /* last path used mask */
- __u32 arep : 1; /* ancillary report */
- __u32 fvf : 5; /* field-validity flags */
- __u32 sacc : 2; /* storage access code */
- __u32 termc : 2; /* termination code */
- __u32 devsc : 1; /* device-status check */
- __u32 serr : 1; /* secondary error */
- __u32 ioerr : 1; /* i/o-error alert */
- __u32 seqc : 3; /* sequence code */
+ __u32 res0 : 1;
+ __u32 esf : 7;
+ __u32 lpum : 8;
+ __u32 arep : 1;
+ __u32 fvf : 5;
+ __u32 sacc : 2;
+ __u32 termc : 2;
+ __u32 devsc : 1;
+ __u32 serr : 1;
+ __u32 ioerr : 1;
+ __u32 seqc : 3;
} __attribute__ ((packed));
-/*
- * Format 0 Extended Status Word (ESW)
+/**
+ * struct esw0 - Format 0 Extended Status Word (ESW)
+ * @sublog: subchannel logout
+ * @erw: extended report word
+ * @faddr: failing storage address
+ * @saddr: secondary ccw address
*/
struct esw0 {
- struct sublog sublog; /* subchannel logout */
- struct erw erw; /* extended report word */
- __u32 faddr[2]; /* failing storage address */
- __u32 saddr; /* secondary ccw address */
+ struct sublog sublog;
+ struct erw erw;
+ __u32 faddr[2];
+ __u32 saddr;
} __attribute__ ((packed));
-/*
- * Format 1 Extended Status Word (ESW)
+/**
+ * struct esw1 - Format 1 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @zero16: reserved zeros
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
*/
struct esw1 {
- __u8 zero0; /* reserved zeros */
- __u8 lpum; /* last path used mask */
- __u16 zero16; /* reserved zeros */
- struct erw erw; /* extended report word */
- __u32 zeros[3]; /* 2 fullwords of zeros */
+ __u8 zero0;
+ __u8 lpum;
+ __u16 zero16;
+ struct erw erw;
+ __u32 zeros[3];
} __attribute__ ((packed));
-/*
- * Format 2 Extended Status Word (ESW)
+/**
+ * struct esw2 - Format 2 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @dcti: device-connect-time interval
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
*/
struct esw2 {
- __u8 zero0; /* reserved zeros */
- __u8 lpum; /* last path used mask */
- __u16 dcti; /* device-connect-time interval */
- struct erw erw; /* extended report word */
- __u32 zeros[3]; /* 2 fullwords of zeros */
+ __u8 zero0;
+ __u8 lpum;
+ __u16 dcti;
+ struct erw erw;
+ __u32 zeros[3];
} __attribute__ ((packed));
-/*
- * Format 3 Extended Status Word (ESW)
+/**
+ * struct esw3 - Format 3 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @res: reserved
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
*/
struct esw3 {
- __u8 zero0; /* reserved zeros */
- __u8 lpum; /* last path used mask */
- __u16 res; /* reserved */
- struct erw erw; /* extended report word */
- __u32 zeros[3]; /* 2 fullwords of zeros */
+ __u8 zero0;
+ __u8 lpum;
+ __u16 res;
+ struct erw erw;
+ __u32 zeros[3];
} __attribute__ ((packed));
-/*
- * interruption response block
+/**
+ * struct irb - interruption response block
+ * @scsw: subchannel status word
+ * @esw: extened status word, 4 formats
+ * @ecw: extended control word
+ *
+ * The irb that is handed to the device driver when an interrupt occurs. For
+ * solicited interrupts, the common I/O layer already performs checks whether
+ * a field is valid; a field not being valid is always passed as %0.
+ * If a unit check occured, @ecw may contain sense data; this is retrieved
+ * by the common I/O layer itself if the device doesn't support concurrent
+ * sense (so that the device driver never needs to perform basic sene itself).
+ * For unsolicited interrupts, the irb is passed as-is (expect for sense data,
+ * if applicable).
*/
struct irb {
- struct scsw scsw; /* subchannel status word */
- union { /* extended status word, 4 formats */
+ struct scsw scsw;
+ union {
struct esw0 esw0;
struct esw1 esw1;
struct esw2 esw2;
struct esw3 esw3;
} esw;
- __u8 ecw[32]; /* extended control word */
+ __u8 ecw[32];
} __attribute__ ((packed,aligned(4)));
-/*
- * command information word (CIW) layout
+/**
+ * struct ciw - command information word (CIW) layout
+ * @et: entry type
+ * @reserved: reserved bits
+ * @ct: command type
+ * @cmd: command code
+ * @count: command count
*/
struct ciw {
- __u32 et : 2; /* entry type */
- __u32 reserved : 2; /* reserved */
- __u32 ct : 4; /* command type */
- __u32 cmd : 8; /* command */
- __u32 count : 16; /* coun */
+ __u32 et : 2;
+ __u32 reserved : 2;
+ __u32 ct : 4;
+ __u32 cmd : 8;
+ __u32 count : 16;
} __attribute__ ((packed));
#define CIW_TYPE_RCD 0x0 /* read configuration data */
@@ -258,11 +349,32 @@ struct ciw {
/* Sick revalidation of device. */
#define CIO_REVALIDATE 0x0008
+/**
+ * struct ccw_dev_id - unique identifier for ccw devices
+ * @ssid: subchannel set id
+ * @devno: device number
+ *
+ * This structure is not directly based on any hardware structure. The
+ * hardware identifies a device by its device number and its subchannel,
+ * which is in turn identified by its id. In order to get a unique identifier
+ * for ccw devices across subchannel sets, @struct ccw_dev_id has been
+ * introduced.
+ */
struct ccw_dev_id {
u8 ssid;
u16 devno;
};
+/**
+ * ccw_device_id_is_equal() - compare two ccw_dev_ids
+ * @dev_id1: a ccw_dev_id
+ * @dev_id2: another ccw_dev_id
+ * Returns:
+ * %1 if the two structures are equal field-by-field,
+ * %0 if not.
+ * Context:
+ * any
+ */
static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
struct ccw_dev_id *dev_id2)
{
diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h
index 021e7c3223e..50196857d27 100644
--- a/include/asm-s390/cmb.h
+++ b/include/asm-s390/cmb.h
@@ -1,29 +1,29 @@
#ifndef S390_CMB_H
#define S390_CMB_H
/**
- * struct cmbdata -- channel measurement block data for user space
+ * struct cmbdata - channel measurement block data for user space
+ * @size: size of the stored data
+ * @elapsed_time: time since last sampling
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy (ext. format)
+ * @initial_command_response_time: initial command response time (ext. format)
*
- * @size: size of the stored data
- * @ssch_rsch_count: XXX
- * @sample_count:
- * @device_connect_time:
- * @function_pending_time:
- * @device_disconnect_time:
- * @control_unit_queuing_time:
- * @device_active_only_time:
- * @device_busy_time:
- * @initial_command_response_time:
- *
- * all values are stored as 64 bit for simplicity, especially
+ * All values are stored as 64 bit for simplicity, especially
* in 32 bit emulation mode. All time values are normalized to
* nanoseconds.
* Currently, two formats are known, which differ by the size of
* this structure, i.e. the last two members are only set when
* the extended channel measurement facility (first shipped in
* z990 machines) is activated.
- * Potentially, more fields could be added, which results in a
+ * Potentially, more fields could be added, which would result in a
* new ioctl number.
- **/
+ */
struct cmbdata {
__u64 size;
__u64 elapsed_time;
@@ -41,53 +41,18 @@ struct cmbdata {
};
/* enable channel measurement */
-#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER,32)
+#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER, 32)
/* enable channel measurement */
-#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER,33)
+#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER, 33)
/* read channel measurement data */
-#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
+#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
#ifdef __KERNEL__
struct ccw_device;
-/**
- * enable_cmf() - switch on the channel measurement for a specific device
- * @cdev: The ccw device to be enabled
- * returns 0 for success or a negative error value.
- *
- * Context:
- * non-atomic
- **/
extern int enable_cmf(struct ccw_device *cdev);
-
-/**
- * disable_cmf() - switch off the channel measurement for a specific device
- * @cdev: The ccw device to be disabled
- * returns 0 for success or a negative error value.
- *
- * Context:
- * non-atomic
- **/
extern int disable_cmf(struct ccw_device *cdev);
-
-/**
- * cmf_read() - read one value from the current channel measurement block
- * @cmf: the channel to be read
- * @index: the name of the value that is read
- *
- * Context:
- * any
- **/
-
extern u64 cmf_read(struct ccw_device *cdev, int index);
-/**
- * cmf_readall() - read one value from the current channel measurement block
- * @cmf: the channel to be read
- * @data: a pointer to a data block that will be filled
- *
- * Context:
- * any
- **/
-extern int cmf_readall(struct ccw_device *cdev, struct cmbdata*data);
+extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
#endif /* __KERNEL__ */
#endif /* S390_CMB_H */
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index f326451ed6e..ceec3826a67 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -9,11 +9,12 @@
#ifndef _S390_PAGE_H
#define _S390_PAGE_H
+#include <linux/const.h>
#include <asm/types.h>
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_DEFAULT_ACC 0
#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 3208dc6c412..39bb5192dc3 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -107,11 +107,18 @@ extern char empty_zero_page[PAGE_SIZE];
* any out-of-bounds memory accesses will hopefully be caught.
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
+ * vmalloc area starts at 4GB to prevent syscall table entry exchanging
+ * from modules.
*/
extern unsigned long vmalloc_end;
-#define VMALLOC_OFFSET (8*1024*1024)
-#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \
- & ~(VMALLOC_OFFSET-1))
+
+#ifdef CONFIG_64BIT
+#define VMALLOC_ADDR (max(0x100000000UL, (unsigned long) high_memory))
+#else
+#define VMALLOC_ADDR ((unsigned long) high_memory)
+#endif
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START ((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_END vmalloc_end
/*
diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h
index 1e72362cad7..2afc060266a 100644
--- a/include/asm-s390/s390_ext.h
+++ b/include/asm-s390/s390_ext.h
@@ -5,7 +5,7 @@
* include/asm-s390/s390_ext.h
*
* S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 1999,2007
* Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
@@ -14,15 +14,11 @@
typedef void (*ext_int_handler_t)(__u16 code);
-/*
- * Warning: if you change ext_int_info_t you have to change the
- * external interrupt handler in entry.S too.
- */
typedef struct ext_int_info_t {
struct ext_int_info_t *next;
ext_int_handler_t handler;
__u16 code;
-} __attribute__ ((packed)) ext_int_info_t;
+} ext_int_info_t;
extern ext_int_info_t *ext_int_hash[];
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 64a3cd05cae..d866d338555 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -130,6 +130,8 @@ extern void pfault_fini(void);
__ret; \
})
+extern void __xchg_called_with_bad_pointer(void);
+
static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
{
unsigned long addr, old;
@@ -150,8 +152,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
: "=&d" (old), "=m" (*(int *) addr)
: "d" (x << shift), "d" (~(255 << shift)), "a" (addr),
"m" (*(int *) addr) : "memory", "cc", "0");
- x = old >> shift;
- break;
+ return old >> shift;
case 2:
addr = (unsigned long) ptr;
shift = (2 ^ (addr & 2)) << 3;
@@ -166,8 +167,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
: "=&d" (old), "=m" (*(int *) addr)
: "d" (x << shift), "d" (~(65535 << shift)), "a" (addr),
"m" (*(int *) addr) : "memory", "cc", "0");
- x = old >> shift;
- break;
+ return old >> shift;
case 4:
asm volatile(
" l %0,0(%3)\n"
@@ -176,8 +176,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
: "=&d" (old), "=m" (*(int *) ptr)
: "d" (x), "a" (ptr), "m" (*(int *) ptr)
: "memory", "cc");
- x = old;
- break;
+ return old;
#ifdef __s390x__
case 8:
asm volatile(
@@ -187,11 +186,11 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
: "=&d" (old), "=m" (*(long *) ptr)
: "d" (x), "a" (ptr), "m" (*(long *) ptr)
: "memory", "cc");
- x = old;
- break;
+ return old;
#endif /* __s390x__ */
- }
- return x;
+ }
+ __xchg_called_with_bad_pointer();
+ return x;
}
/*
@@ -206,6 +205,8 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
+extern void __cmpxchg_called_with_bad_pointer(void);
+
static inline unsigned long
__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
{
@@ -270,7 +271,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
return prev;
#endif /* __s390x__ */
}
- return old;
+ __cmpxchg_called_with_bad_pointer();
+ return old;
}
/*
diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
index b90e55888a5..a5dada61775 100644
--- a/include/asm-s390/zcrypt.h
+++ b/include/asm-s390/zcrypt.h
@@ -91,7 +91,7 @@ struct ica_rsa_modexpo_crt {
* VUD block
* key block
*/
-struct ica_CPRBX {
+struct CPRBX {
unsigned short cprb_len; /* CPRB length 220 */
unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
unsigned char pad_000[3]; /* Alignment pad bytes */
@@ -130,7 +130,7 @@ struct ica_CPRBX {
unsigned char cntrl_domain[4];/* Control domain */
unsigned char S390enf_mask[4];/* S/390 enforcement mask */
unsigned char pad_004[36]; /* reserved */
-};
+} __attribute__((packed));
/**
* xcRB
diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h
index 07f62ec9ff0..aa558da0847 100644
--- a/include/asm-sh/cacheflush.h
+++ b/include/asm-sh/cacheflush.h
@@ -1,16 +1,47 @@
#ifndef __ASM_SH_CACHEFLUSH_H
#define __ASM_SH_CACHEFLUSH_H
+
#ifdef __KERNEL__
-#include <linux/mm.h>
+#ifdef CONFIG_CACHE_OFF
+/*
+ * Nothing to do when the cache is disabled, initial flush and explicit
+ * disabling is handled at CPU init time.
+ *
+ * See arch/sh/kernel/cpu/init.c:cache_init().
+ */
+#define p3_cache_init() do { } while (0)
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_mm(mm) do { } while (0)
+#define flush_cache_range(vma, start, end) do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
+#define flush_dcache_page(page) do { } while (0)
+#define flush_icache_range(start, end) do { } while (0)
+#define flush_icache_page(vma,pg) do { } while (0)
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+#define flush_cache_sigtramp(vaddr) do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
+#define __flush_wback_region(start, size) do { (void)(start); } while (0)
+#define __flush_purge_region(start, size) do { (void)(start); } while (0)
+#define __flush_invalidate_region(start, size) do { (void)(start); } while (0)
+#else
#include <asm/cpu/cacheflush.h>
+/*
+ * Consistent DMA requires that the __flush_xxx() primitives must be set
+ * for any of the enabled non-coherent caches (most of the UP CPUs),
+ * regardless of PIPT or VIPT cache configurations.
+ */
+
/* Flush (write-back only) a region (smaller than a page) */
extern void __flush_wback_region(void *start, int size);
/* Flush (write-back & invalidate) a region (smaller than a page) */
extern void __flush_purge_region(void *start, int size);
/* Flush (invalidate only) a region (smaller than a page) */
extern void __flush_invalidate_region(void *start, int size);
+#endif
#define flush_cache_vmap(start, end) flush_cache_all()
#define flush_cache_vunmap(start, end) flush_cache_all()
diff --git a/include/asm-sh/cpu-sh3/cache.h b/include/asm-sh/cpu-sh3/cache.h
index ffe08d2813f..255016fc91f 100644
--- a/include/asm-sh/cpu-sh3/cache.h
+++ b/include/asm-sh/cpu-sh3/cache.h
@@ -26,7 +26,9 @@
#define CCR_CACHE_ENABLE CCR_CACHE_CE
#define CCR_CACHE_INVALIDATE CCR_CACHE_CF
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define CCR3 0xa40000b4
#define CCR_CACHE_16KB 0x00010000
#define CCR_CACHE_32KB 0x00020000
diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h
index 3a66dc45802..54bfece328c 100644
--- a/include/asm-sh/cpu-sh3/dma.h
+++ b/include/asm-sh/cpu-sh3/dma.h
@@ -1,7 +1,20 @@
#ifndef __ASM_CPU_SH3_DMA_H
#define __ASM_CPU_SH3_DMA_H
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#define SH_DMAC_BASE 0xa4010020
+
+#define DMTE0_IRQ 48
+#define DMTE1_IRQ 49
+#define DMTE2_IRQ 50
+#define DMTE3_IRQ 51
+#define DMTE4_IRQ 76
+#define DMTE5_IRQ 77
+
+#else
#define SH_DMAC_BASE 0xa4000020
+#endif
/* Definitions for the SuperH DMAC */
#define TM_BURST 0x00000020
diff --git a/include/asm-sh/cpu-sh3/gpio.h b/include/asm-sh/cpu-sh3/gpio.h
new file mode 100644
index 00000000000..48770c1c7bd
--- /dev/null
+++ b/include/asm-sh/cpu-sh3/gpio.h
@@ -0,0 +1,66 @@
+/*
+ * include/asm-sh/cpu-sh3/gpio.h
+ *
+ * Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ * Addresses for the Pin Function Controller
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef _CPU_SH3_GPIO_H
+#define _CPU_SH3_GPIO_H
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+
+/* Control registers */
+#define PORT_PACR 0xA4050100UL
+#define PORT_PBCR 0xA4050102UL
+#define PORT_PCCR 0xA4050104UL
+#define PORT_PDCR 0xA4050106UL
+#define PORT_PECR 0xA4050108UL
+#define PORT_PFCR 0xA405010AUL
+#define PORT_PGCR 0xA405010CUL
+#define PORT_PHCR 0xA405010EUL
+#define PORT_PJCR 0xA4050110UL
+#define PORT_PKCR 0xA4050112UL
+#define PORT_PLCR 0xA4050114UL
+#define PORT_PMCR 0xA4050116UL
+#define PORT_PPCR 0xA4050118UL
+#define PORT_PRCR 0xA405011AUL
+#define PORT_PSCR 0xA405011CUL
+#define PORT_PTCR 0xA405011EUL
+#define PORT_PUCR 0xA4050120UL
+#define PORT_PVCR 0xA4050122UL
+
+/* Data registers */
+#define PORT_PADR 0xA4050140UL
+/* Address of PORT_PBDR is wrong in the datasheet, see errata 2005-09-21 */
+#define PORT_PBDR 0xA4050142UL
+#define PORT_PCDR 0xA4050144UL
+#define PORT_PDDR 0xA4050146UL
+#define PORT_PEDR 0xA4050148UL
+#define PORT_PFDR 0xA405014AUL
+#define PORT_PGDR 0xA405014CUL
+#define PORT_PHDR 0xA405014EUL
+#define PORT_PJDR 0xA4050150UL
+#define PORT_PKDR 0xA4050152UL
+#define PORT_PLDR 0xA4050154UL
+#define PORT_PMDR 0xA4050156UL
+#define PORT_PPDR 0xA4050158UL
+#define PORT_PRDR 0xA405015AUL
+#define PORT_PSDR 0xA405015CUL
+#define PORT_PTDR 0xA405015EUL
+#define PORT_PUDR 0xA4050160UL
+#define PORT_PVDR 0xA4050162UL
+
+/* Pin Select Registers */
+#define PORT_PSELA 0xA4050124UL
+#define PORT_PSELB 0xA4050126UL
+#define PORT_PSELC 0xA4050128UL
+#define PORT_PSELD 0xA405012AUL
+
+#endif
+
+#endif
diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
index b20786d42d0..16c2d63b7e3 100644
--- a/include/asm-sh/cpu-sh3/mmu_context.h
+++ b/include/asm-sh/cpu-sh3/mmu_context.h
@@ -27,12 +27,13 @@
#define TRA 0xffffffd0
#define EXPEVT 0xffffffd4
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
- defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7706) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710) || \
defined(CONFIG_CPU_SUBTYPE_SH7712) || \
- defined(CONFIG_CPU_SUBTYPE_SH7710)
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define INTEVT 0xa4000000 /* INTEVTE2(0xa4000000) */
#else
#define INTEVT 0xffffffd8
diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
index b6c2020a2ad..3880ce047fe 100644
--- a/include/asm-sh/cpu-sh3/timer.h
+++ b/include/asm-sh/cpu-sh3/timer.h
@@ -23,11 +23,13 @@
* ---------------------------------------------------------------------------
*/
-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7727)
#define TMU_TOCR 0xfffffe90 /* Byte access */
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define TMU_012_TSTR 0xa412fe92 /* Byte access */
#define TMU0_TCOR 0xa412fe94 /* Long access */
@@ -56,7 +58,8 @@
#define TMU2_TCOR 0xfffffeac /* Long access */
#define TMU2_TCNT 0xfffffeb0 /* Long access */
#define TMU2_TCR 0xfffffeb4 /* Word access */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7727)
#define TMU2_TCPR2 0xfffffeb8 /* Long access */
#endif
#endif
diff --git a/include/asm-sh/cpu-sh3/ubc.h b/include/asm-sh/cpu-sh3/ubc.h
index 9d308cbe9b2..18467c57453 100644
--- a/include/asm-sh/cpu-sh3/ubc.h
+++ b/include/asm-sh/cpu-sh3/ubc.h
@@ -11,7 +11,8 @@
#ifndef __ASM_CPU_SH3_UBC_H
#define __ASM_CPU_SH3_UBC_H
-#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define UBC_BARA 0xa4ffffb0
#define UBC_BAMRA 0xa4ffffb4
#define UBC_BBRA 0xa4ffffb8
diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
index 36e26a96476..aaf71b018c2 100644
--- a/include/asm-sh/cpu-sh4/dma.h
+++ b/include/asm-sh/cpu-sh4/dma.h
@@ -31,7 +31,7 @@
#define TS_32 0x00000030
#define TS_64 0x00000000
-#define CHCR_TS_MASK 0x30
+#define CHCR_TS_MASK 0x70
#define CHCR_TS_SHIFT 4
#define DMAOR_COD 0x00000008
diff --git a/include/asm-sh/cpu-sh4/mmu_context.h b/include/asm-sh/cpu-sh4/mmu_context.h
index ff4c5fbbfaf..979acddc0f8 100644
--- a/include/asm-sh/cpu-sh4/mmu_context.h
+++ b/include/asm-sh/cpu-sh4/mmu_context.h
@@ -22,13 +22,21 @@
#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
#define MMU_PAGE_ASSOC_BIT 0x80
-#define MMU_NTLB_ENTRIES 64 /* for 7750 */
+#ifdef CONFIG_X2TLB
+#define MMUCR_ME (1 << 7)
+#else
+#define MMUCR_ME (0)
+#endif
+
#ifdef CONFIG_SH_STORE_QUEUES
-#define MMU_CONTROL_INIT 0x05 /* SQMD=0, SV=0, TI=1, AT=1 */
+#define MMUCR_SQMD (1 << 9)
#else
-#define MMU_CONTROL_INIT 0x205 /* SQMD=1, SV=0, TI=1, AT=1 */
+#define MMUCR_SQMD (0)
#endif
+#define MMU_NTLB_ENTRIES 64
+#define MMU_CONTROL_INIT (0x05|MMUCR_SQMD|MMUCR_ME)
+
#define MMU_ITLB_DATA_ARRAY 0xF3000000
#define MMU_UTLB_DATA_ARRAY 0xF7000000
diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h
index 4c75b70b641..a65b02fd186 100644
--- a/include/asm-sh/dma.h
+++ b/include/asm-sh/dma.h
@@ -152,14 +152,9 @@ extern struct dma_info *get_dma_info_by_name(const char *dmac_name);
extern int dma_extend(unsigned int chan, unsigned long op, void *param);
extern int register_chan_caps(const char *dmac, struct dma_chan_caps *capslist);
-#ifdef CONFIG_SYSFS
/* arch/sh/drivers/dma/dma-sysfs.c */
extern int dma_create_sysfs_files(struct dma_channel *, struct dma_info *);
extern void dma_remove_sysfs_files(struct dma_channel *, struct dma_info *);
-#else
-#define dma_create_sysfs_file(channel, info) do { } while (0)
-#define dma_remove_sysfs_file(channel, info) do { } while (0)
-#endif
#ifdef CONFIG_PCI
extern int isa_dma_bridge_buggy;
diff --git a/include/asm-sh/dreamcast/maple.h b/include/asm-sh/dreamcast/maple.h
new file mode 100644
index 00000000000..51f6a87f1f1
--- /dev/null
+++ b/include/asm-sh/dreamcast/maple.h
@@ -0,0 +1,37 @@
+#ifndef __ASM_MAPLE_H
+#define __ASM_MAPLE_H
+
+#define MAPLE_PORTS 4
+#define MAPLE_PNP_INTERVAL HZ
+#define MAPLE_MAXPACKETS 8
+#define MAPLE_DMA_ORDER 14
+#define MAPLE_DMA_SIZE (1 << MAPLE_DMA_ORDER)
+#define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? \
+ MAPLE_DMA_ORDER - PAGE_SHIFT : 0)
+
+/* Maple Bus registers */
+#define MAPLE_BASE 0xa05f6c00
+#define MAPLE_DMAADDR (MAPLE_BASE+0x04)
+#define MAPLE_TRIGTYPE (MAPLE_BASE+0x10)
+#define MAPLE_ENABLE (MAPLE_BASE+0x14)
+#define MAPLE_STATE (MAPLE_BASE+0x18)
+#define MAPLE_SPEED (MAPLE_BASE+0x80)
+#define MAPLE_RESET (MAPLE_BASE+0x8c)
+
+#define MAPLE_MAGIC 0x6155404f
+#define MAPLE_2MBPS 0
+#define MAPLE_TIMEOUT(n) ((n)<<15)
+
+/* Function codes */
+#define MAPLE_FUNC_CONTROLLER 0x001
+#define MAPLE_FUNC_MEMCARD 0x002
+#define MAPLE_FUNC_LCD 0x004
+#define MAPLE_FUNC_CLOCK 0x008
+#define MAPLE_FUNC_MICROPHONE 0x010
+#define MAPLE_FUNC_ARGUN 0x020
+#define MAPLE_FUNC_KEYBOARD 0x040
+#define MAPLE_FUNC_LIGHTGUN 0x080
+#define MAPLE_FUNC_PURUPURU 0x100
+#define MAPLE_FUNC_MOUSE 0x200
+
+#endif /* __ASM_MAPLE_H */
diff --git a/include/asm-sh/gpio.h b/include/asm-sh/gpio.h
new file mode 100644
index 00000000000..9bb27e0f11a
--- /dev/null
+++ b/include/asm-sh/gpio.h
@@ -0,0 +1,19 @@
+/*
+ * include/asm-sh/gpio.h
+ *
+ * Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ * Addresses for the Pin Function Controller
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_SH_GPIO_H
+#define __ASM_SH_GPIO_H
+
+#if defined(CONFIG_CPU_SH3)
+#include <asm/cpu/gpio.h>
+#endif
+
+#endif /* __ASM_SH_GPIO_H */
diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h
index 4dd8592ca01..342ca55a266 100644
--- a/include/asm-sh/hd64461.h
+++ b/include/asm-sh/hd64461.h
@@ -226,6 +226,7 @@
#define HD64461_NIMR (CONFIG_HD64461_IOBASE + 0x5002)
#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
+#define OFFCHIP_IRQ_BASE 64
#define HD64461_IRQ_NUM 16
#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
diff --git a/include/asm-sh/heartbeat.h b/include/asm-sh/heartbeat.h
new file mode 100644
index 00000000000..724a43ed245
--- /dev/null
+++ b/include/asm-sh/heartbeat.h
@@ -0,0 +1,17 @@
+#ifndef __ASM_SH_HEARTBEAT_H
+#define __ASM_SH_HEARTBEAT_H
+
+#include <linux/timer.h>
+
+#define HEARTBEAT_INVERTED (1 << 0)
+
+struct heartbeat_data {
+ void __iomem *base;
+ unsigned char *bit_pos;
+ unsigned int nr_bits;
+ struct timer_list timer;
+ unsigned int regsize;
+ unsigned long flags;
+};
+
+#endif /* __ASM_SH_HEARTBEAT_H */
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
index 20d42959f52..cb0b6c9f702 100644
--- a/include/asm-sh/hw_irq.h
+++ b/include/asm-sh/hw_irq.h
@@ -6,24 +6,6 @@
extern atomic_t irq_err_count;
-struct intc2_data {
- unsigned short irq;
- unsigned char ipr_offset, ipr_shift;
- unsigned char msk_offset, msk_shift;
- unsigned char priority;
-};
-
-struct intc2_desc {
- unsigned long prio_base;
- unsigned long msk_base;
- unsigned long mskclr_base;
- struct intc2_data *intc2_data;
- unsigned int nr_irqs;
- struct irq_chip chip;
-};
-
-void register_intc2_controller(struct intc2_desc *);
-
struct ipr_data {
unsigned char irq;
unsigned char ipr_idx; /* Index for the IPR registered */
@@ -41,11 +23,6 @@ struct ipr_desc {
void register_ipr_controller(struct ipr_desc *);
-/*
- * Enable individual interrupt mode for external IPR IRQs.
- */
-void __init ipr_irq_enable_irlm(void);
-
typedef unsigned char intc_enum;
struct intc_vect {
@@ -54,6 +31,7 @@ struct intc_vect {
};
#define INTC_VECT(enum_id, vect) { enum_id, vect }
+#define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq))
struct intc_prio {
intc_enum enum_id;
@@ -64,19 +42,25 @@ struct intc_prio {
struct intc_group {
intc_enum enum_id;
- intc_enum *enum_ids;
+ intc_enum enum_ids[32];
};
-#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
struct intc_mask_reg {
unsigned long set_reg, clr_reg, reg_width;
intc_enum enum_ids[32];
+#ifdef CONFIG_SMP
+ unsigned long smp;
+#endif
};
struct intc_prio_reg {
- unsigned long reg, reg_width, field_width;
+ unsigned long set_reg, clr_reg, reg_width, field_width;
intc_enum enum_ids[16];
+#ifdef CONFIG_SMP
+ unsigned long smp;
+#endif
};
struct intc_sense_reg {
@@ -84,6 +68,12 @@ struct intc_sense_reg {
intc_enum enum_ids[16];
};
+#ifdef CONFIG_SMP
+#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8)
+#else
+#define INTC_SMP(stride, nr)
+#endif
+
struct intc_desc {
struct intc_vect *vectors;
unsigned int nr_vectors;
@@ -97,25 +87,28 @@ struct intc_desc {
unsigned int nr_prio_regs;
struct intc_sense_reg *sense_regs;
unsigned int nr_sense_regs;
- struct irq_chip chip;
+ char *name;
};
#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups, \
priorities, mask_regs, prio_regs, sense_regs) \
-struct intc_desc symbol = { \
+struct intc_desc symbol __initdata = { \
_INTC_ARRAY(vectors), _INTC_ARRAY(groups), \
_INTC_ARRAY(priorities), \
_INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \
_INTC_ARRAY(sense_regs), \
- .chip.name = chipname, \
+ chipname, \
}
void __init register_intc_controller(struct intc_desc *desc);
+int intc_set_priority(unsigned int irq, unsigned int prio);
void __init plat_irq_setup(void);
-enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRQ7654, IRQ_MODE_IRQ3210,
+ IRQ_MODE_IRL7654_MASK, IRQ_MODE_IRL3210_MASK,
+ IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
void __init plat_irq_setup_pins(int mode);
#endif /* __ASM_SH_HW_IRQ_H */
diff --git a/include/asm-sh/ilsel.h b/include/asm-sh/ilsel.h
new file mode 100644
index 00000000000..e3d304b280f
--- /dev/null
+++ b/include/asm-sh/ilsel.h
@@ -0,0 +1,45 @@
+#ifndef __ASM_SH_ILSEL_H
+#define __ASM_SH_ILSEL_H
+
+typedef enum {
+ ILSEL_NONE,
+ ILSEL_LAN,
+ ILSEL_USBH_I,
+ ILSEL_USBH_S,
+ ILSEL_USBH_V,
+ ILSEL_RTC,
+ ILSEL_USBP_I,
+ ILSEL_USBP_S,
+ ILSEL_USBP_V,
+ ILSEL_KEY,
+
+ /*
+ * ILSEL Aliases - corner cases for interleaved level tables.
+ *
+ * Someone thought this was a good idea and less hassle than
+ * demuxing a shared vector, really.
+ */
+
+ /* ILSEL0 and 2 */
+ ILSEL_FPGA0,
+ ILSEL_FPGA1,
+ ILSEL_EX1,
+ ILSEL_EX2,
+ ILSEL_EX3,
+ ILSEL_EX4,
+
+ /* ILSEL1 and 3 */
+ ILSEL_FPGA2 = ILSEL_FPGA0,
+ ILSEL_FPGA3 = ILSEL_FPGA1,
+ ILSEL_EX5 = ILSEL_EX1,
+ ILSEL_EX6 = ILSEL_EX2,
+ ILSEL_EX7 = ILSEL_EX3,
+ ILSEL_EX8 = ILSEL_EX4,
+} ilsel_source_t;
+
+/* arch/sh/boards/renesas/x3proto/ilsel.c */
+int ilsel_enable(ilsel_source_t set);
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
+void ilsel_disable(unsigned int irq);
+
+#endif /* __ASM_SH_ILSEL_H */
diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h
index e6a1877dcb2..1a336cdc75f 100644
--- a/include/asm-sh/io.h
+++ b/include/asm-sh/io.h
@@ -135,6 +135,32 @@ void __raw_readsl(unsigned long addr, void *data, int longlen);
# define writel(v,a) ({ __raw_writel((v),(a)); mb(); })
#endif
+#define __BUILD_MEMORY_STRING(bwlq, type) \
+ \
+static inline void writes##bwlq(volatile void __iomem *mem, \
+ const void *addr, unsigned int count) \
+{ \
+ const volatile type *__addr = addr; \
+ \
+ while (count--) { \
+ __raw_write##bwlq(*__addr, mem); \
+ __addr++; \
+ } \
+} \
+ \
+static inline void reads##bwlq(volatile void __iomem *mem, void *addr, \
+ unsigned int count) \
+{ \
+ volatile type *__addr = addr; \
+ \
+ while (count--) { \
+ *__addr = __raw_read##bwlq(mem); \
+ __addr++; \
+ } \
+}
+
+__BUILD_MEMORY_STRING(b, u8)
+__BUILD_MEMORY_STRING(w, u16)
#define writesl __raw_writesl
#define readsl __raw_readsl
diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
index 74bd0953e5c..4bc8cb187d1 100644
--- a/include/asm-sh/kgdb.h
+++ b/include/asm-sh/kgdb.h
@@ -17,9 +17,6 @@
#define __KGDB_H
#include <asm/ptrace.h>
-#include <asm/cacheflush.h>
-
-struct console;
/* Same as pt_regs but has vbr in place of syscall_nr */
struct kgdb_regs {
@@ -35,10 +32,7 @@ struct kgdb_regs {
/* State info */
extern char kgdb_in_gdb_mode;
-extern int kgdb_done_init;
-extern int kgdb_enabled;
extern int kgdb_nofault; /* Ignore bus errors (in gdb mem access) */
-extern int kgdb_halt; /* Execute initial breakpoint at startup */
extern char in_nmi; /* Debounce flag to prevent NMI reentry*/
/* SCI */
@@ -59,6 +53,7 @@ extern kgdb_debug_hook_t *kgdb_debug_hook;
extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
/* Console */
+struct console;
void kgdb_console_write(struct console *co, const char *s, unsigned count);
extern int kgdb_console_setup(struct console *, char *);
@@ -69,22 +64,7 @@ extern void longjmp(jmp_buf __jmpb, int __retval);
extern int setjmp(jmp_buf __jmpb);
/* Forced breakpoint */
-#define breakpoint() \
-do { \
- if (kgdb_enabled) \
- __asm__ __volatile__("trapa #0x3c"); \
-} while (0)
-
-/* KGDB should be able to flush all kernel text space */
-#if defined(CONFIG_CPU_SH4)
-#define kgdb_flush_icache_range(start, end) \
-{ \
- __flush_purge_region((void*)(start), (int)(end) - (int)(start));\
- flush_icache_range((start), (end)); \
-}
-#else
-#define kgdb_flush_icache_range(start, end) do { } while (0)
-#endif
+#define breakpoint() __asm__ __volatile__("trapa #0x3c")
/* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef";
diff --git a/include/asm-sh/magicpanelr2.h b/include/asm-sh/magicpanelr2.h
new file mode 100644
index 00000000000..c644a77ee35
--- /dev/null
+++ b/include/asm-sh/magicpanelr2.h
@@ -0,0 +1,67 @@
+/*
+ * include/asm-sh/magicpanelr2.h
+ *
+ * Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ * I/O addresses and bitmasks for Magic Panel Release 2 board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_SH_MAGICPANELR2_H
+#define __ASM_SH_MAGICPANELR2_H
+
+#include <asm/gpio.h>
+
+#define __IO_PREFIX mpr2
+#include <asm/io_generic.h>
+
+
+#define SETBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) | mask, reg)
+#define SETBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) | mask, reg)
+#define SETBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) | mask, reg)
+#define CLRBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) & ~mask, reg)
+#define CLRBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) & ~mask, reg)
+#define CLRBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) & ~mask, reg)
+
+
+#define PA_LED PORT_PADR /* LED */
+
+
+/* BSC */
+#define CMNCR 0xA4FD0000UL
+#define CS0BCR 0xA4FD0004UL
+#define CS2BCR 0xA4FD0008UL
+#define CS3BCR 0xA4FD000CUL
+#define CS4BCR 0xA4FD0010UL
+#define CS5ABCR 0xA4FD0014UL
+#define CS5BBCR 0xA4FD0018UL
+#define CS6ABCR 0xA4FD001CUL
+#define CS6BBCR 0xA4FD0020UL
+#define CS0WCR 0xA4FD0024UL
+#define CS2WCR 0xA4FD0028UL
+#define CS3WCR 0xA4FD002CUL
+#define CS4WCR 0xA4FD0030UL
+#define CS5AWCR 0xA4FD0034UL
+#define CS5BWCR 0xA4FD0038UL
+#define CS6AWCR 0xA4FD003CUL
+#define CS6BWCR 0xA4FD0040UL
+
+
+/* usb */
+
+#define PORT_UTRCTL 0xA405012CUL
+#define PORT_UCLKCR_W 0xA40A0008UL
+
+#define INTC_ICR0 0xA414FEE0UL
+#define INTC_ICR1 0xA4140010UL
+#define INTC_ICR2 0xA4140012UL
+
+/* MTD */
+
+#define MPR2_MTD_BOOTLOADER_SIZE 0x00060000UL
+#define MPR2_MTD_KERNEL_SIZE 0x00200000UL
+
+#endif /* __ASM_SH_MAGICPANELR2_H */
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index 6bc9bba1010..cb3d46c59ea 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -70,14 +70,14 @@ extern void clear_page_nommu(void *to);
extern void copy_page_nommu(void *to, void *from);
#endif
-#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
- defined(CONFIG_SH7705_CACHE_32KB))
+#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+ (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
struct page;
extern void clear_user_page(void *to, unsigned long address, struct page *pg);
extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
extern void __clear_user_page(void *to, void *orig_to);
extern void __copy_user_page(void *to, void *from, void *orig_to);
-#elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU)
+#else
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#endif
@@ -88,6 +88,7 @@ extern void __copy_user_page(void *to, void *from, void *orig_to);
#ifdef CONFIG_X2TLB
typedef struct { unsigned long pte_low, pte_high; } pte_t;
typedef struct { unsigned long long pgprot; } pgprot_t;
+typedef struct { unsigned long long pgd; } pgd_t;
#define pte_val(x) \
((x).pte_low | ((unsigned long long)(x).pte_high << 32))
#define __pte(x) \
@@ -95,12 +96,11 @@ typedef struct { unsigned long long pgprot; } pgprot_t;
#else
typedef struct { unsigned long pte_low; } pte_t;
typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long pgd; } pgd_t;
#define pte_val(x) ((x).pte_low)
#define __pte(x) ((pte_t) { (x) } )
#endif
-typedef struct { unsigned long pgd; } pgd_t;
-
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index e3fae12c0e4..cf0dd2b648c 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -42,13 +42,12 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
/* PGD bits */
#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS)
-#define PGDIR_BITS (32 - PGDIR_SHIFT)
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/* Entries per level */
#define PTRS_PER_PTE (PAGE_SIZE / (1 << PTE_MAGNITUDE))
-#define PTRS_PER_PGD (PAGE_SIZE / 4)
+#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t))
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
@@ -100,17 +99,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */
#define _PAGE_DIRTY 0x004 /* D-bit : page changed */
#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */
-#ifndef CONFIG_X2TLB
-# define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
-# define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
-# define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/
-# define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
-#endif
+#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
+#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
+#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/
+#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
#define _PAGE_PROTNONE 0x200 /* software: if not present */
#define _PAGE_ACCESSED 0x400 /* software: page referenced */
#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
+#define _PAGE_SZ_MASK (_PAGE_SZ0 | _PAGE_SZ1)
+#define _PAGE_PR_MASK (_PAGE_RW | _PAGE_USER)
+
/* Extended mode bits */
#define _PAGE_EXT_ESZ0 0x0010 /* ESZ0-bit: Size of page */
#define _PAGE_EXT_ESZ1 0x0020 /* ESZ1-bit: Size of page */
@@ -126,11 +126,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */
/* Wrapper for extended mode pgprot twiddling */
-#ifdef CONFIG_X2TLB
-# define _PAGE_EXT(x) ((unsigned long long)(x) << 32)
-#else
-# define _PAGE_EXT(x) (0)
-#endif
+#define _PAGE_EXT(x) ((unsigned long long)(x) << 32)
/* software: moves to PTEA.TC (Timing Control) */
#define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */
@@ -146,10 +142,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define _PAGE_PCC_ATR16 0x60000001 /* Attribute Memory space, 6 bit bus */
/* Mask which drops unused bits from the PTEL value */
-#ifdef CONFIG_CPU_SH3
+#if defined(CONFIG_CPU_SH3)
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \
_PAGE_FILE | _PAGE_SZ1 | \
_PAGE_HW_SHARED)
+#elif defined(CONFIG_X2TLB)
+/* Get rid of the legacy PR/SZ bits when using extended mode */
+#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | \
+ _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK)
#else
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
@@ -212,27 +212,36 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
- _PAGE_EXT(_PAGE_EXT_USER_READ | \
+ _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+ _PAGE_EXT_KERN_WRITE | \
+ _PAGE_EXT_USER_READ | \
_PAGE_EXT_USER_WRITE))
#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
- _PAGE_EXT(_PAGE_EXT_USER_EXEC | \
+ _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \
+ _PAGE_EXT_KERN_READ | \
+ _PAGE_EXT_USER_EXEC | \
_PAGE_EXT_USER_READ))
#define PAGE_COPY PAGE_EXECREAD
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
- _PAGE_EXT(_PAGE_EXT_USER_READ))
+ _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+ _PAGE_EXT_USER_READ))
#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
- _PAGE_EXT(_PAGE_EXT_USER_WRITE))
+ _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+ _PAGE_EXT_USER_WRITE))
#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
- _PAGE_EXT(_PAGE_EXT_USER_WRITE | \
+ _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+ _PAGE_EXT_KERN_READ | \
+ _PAGE_EXT_KERN_EXEC | \
+ _PAGE_EXT_USER_WRITE | \
_PAGE_EXT_USER_READ | \
_PAGE_EXT_USER_EXEC))
@@ -373,11 +382,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
-#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#define pte_none(x) (!pte_val(x))
-#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+#define pfn_pte(pfn, prot) \
+ __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot) \
+ __pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+#define pte_none(x) (!pte_val(x))
+#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
+
#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
#define pmd_none(x) (!pmd_val(x))
@@ -392,15 +405,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-#define pte_not_present(pte) (!(pte_val(pte) & _PAGE_PRESENT))
-#define pte_dirty(pte) (pte_val(pte) & _PAGE_DIRTY)
-#define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED)
-#define pte_file(pte) (pte_val(pte) & _PAGE_FILE)
+#define pte_not_present(pte) (!((pte).pte_low & _PAGE_PRESENT))
+#define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY)
+#define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED)
+#define pte_file(pte) ((pte).pte_low & _PAGE_FILE)
#ifdef CONFIG_X2TLB
#define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE)
#else
-#define pte_write(pte) (pte_val(pte) & _PAGE_RW)
+#define pte_write(pte) ((pte).pte_low & _PAGE_RW)
#endif
#define PTE_BIT_FUNC(h,fn,op) \
@@ -429,17 +442,10 @@ PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
/*
* Macro and implementation to make a page protection as uncachable.
*/
-#define pgprot_noncached pgprot_noncached
+#define pgprot_writecombine(prot) \
+ __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
-static inline pgprot_t pgprot_noncached(pgprot_t _prot)
-{
- unsigned long prot = pgprot_val(_prot);
-
- prot &= ~_PAGE_CACHABLE;
- return __pgprot(prot);
-}
-
-#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
+#define pgprot_noncached pgprot_writecombine
/*
* Conversion functions: convert a page and protection to a page entry,
@@ -451,28 +457,33 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
- set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) |
- pgprot_val(newprot)));
+ pte.pte_low &= _PAGE_CHG_MASK;
+ pte.pte_low |= pgprot_val(newprot);
+
+#ifdef CONFIG_X2TLB
+ pte.pte_high |= pgprot_val(newprot) >> 32;
+#endif
+
return pte;
}
-#define pmd_page_vaddr(pmd) pmd_val(pmd)
+#define pmd_page_vaddr(pmd) ((unsigned long)pmd_val(pmd))
#define pmd_page(pmd) (virt_to_page(pmd_val(pmd)))
/* to find an entry in a page-table-directory. */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* Find an entry in the third-level page table.. */
-#define pte_index(address) \
- ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
-#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
+#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
+#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
+
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
@@ -480,13 +491,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_ERROR(e) \
printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \
&(e), (e).pte_high, (e).pte_low)
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
#else
#define pte_ERROR(e) \
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#endif
-
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+#endif
struct vm_area_struct;
extern void update_mmu_cache(struct vm_area_struct * vma,
@@ -563,7 +575,8 @@ struct mm_struct;
extern unsigned int kobjsize(const void *objp);
#endif /* !CONFIG_MMU */
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+ defined(CONFIG_SH7705_CACHE_32KB))
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
#endif
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index 26d52174f4b..4f2922a1979 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -45,7 +45,7 @@ enum cpu_type {
CPU_SH7705, CPU_SH7706, CPU_SH7707,
CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712,
- CPU_SH7729,
+ CPU_SH7720, CPU_SH7729,
/* SH-4 types */
CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R,
@@ -73,15 +73,10 @@ struct sh_cpuinfo {
unsigned long flags;
} __attribute__ ((aligned(SMP_CACHE_BYTES)));
-extern struct sh_cpuinfo boot_cpu_data;
-
-#ifdef CONFIG_SMP
extern struct sh_cpuinfo cpu_data[];
+#define boot_cpu_data cpu_data[0]
#define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
-#define current_cpu_data boot_cpu_data
-#endif
+#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
/*
* User space process size: 2GB.
diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h
index 4083b594992..de37f933aa4 100644
--- a/include/asm-sh/r7780rp.h
+++ b/include/asm-sh/r7780rp.h
@@ -65,24 +65,6 @@
#define PA_PMR (PA_BCR+0x0900) /* */
#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
-
-#define IRQ_PCISLOT1 65 /* PCI Slot #1 IRQ */
-#define IRQ_PCISLOT2 66 /* PCI Slot #2 IRQ */
-#define IRQ_PCISLOT3 67 /* PCI Slot #3 IRQ */
-#define IRQ_PCISLOT4 68 /* PCI Slot #4 IRQ */
-#define IRQ_TP 2 /* Touch Panel IRQ */
-#define IRQ_SCI1 3 /* SCI1 IRQ */
-#define IRQ_SCI0 4 /* SCI0 IRQ */
-#define IRQ_2SERIAL 5 /* Serial IRQ */
-#define IRQ_RTC 6 /* RTC A / B IRQ */
-#define IRQ_EXTENTION6 7 /* EXT6n IRQ */
-#define IRQ_EXTENTION5 8 /* EXT5n IRQ */
-#define IRQ_EXTENTION4 9 /* EXT4n IRQ */
-#define IRQ_EXTENTION2 10 /* EXT2n IRQ */
-#define IRQ_EXTENTION1 11 /* EXT1n IRQ */
-#define IRQ_ONETH 13 /* On board Ethernet IRQ */
-#define IRQ_PSW 14 /* Push Switch IRQ */
-
#define IVDR_CK_ON 8 /* iVDR Clock ON */
#elif defined(CONFIG_SH_R7780RP)
@@ -203,11 +185,24 @@
#define PA_MMSR (PA_BCR+0x0400)
#define IVDR_CK_ON 4 /* iVDR Clock ON */
+#endif
+#define HL_FPGA_IRQ_BASE 200
+#define HL_NR_IRL 15
+
+#define IRQ_AX88796 (HL_FPGA_IRQ_BASE + 0)
+#define IRQ_CF (HL_FPGA_IRQ_BASE + 1)
+#ifndef IRQ_PSW
+#define IRQ_PSW (HL_FPGA_IRQ_BASE + 2)
#endif
+#define IRQ_EXT1 (HL_FPGA_IRQ_BASE + 3)
+#define IRQ_EXT4 (HL_FPGA_IRQ_BASE + 4)
void make_r7780rp_irq(unsigned int irq);
-void highlander_init_irq(void);
+
+unsigned char *highlander_init_irq_r7780mp(void);
+unsigned char *highlander_init_irq_r7780rp(void);
+unsigned char *highlander_init_irq_r7785rp(void);
#define __IO_PREFIX r7780rp
#include <asm/io_generic.h>
diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h
index 91aacc96151..858da99d37e 100644
--- a/include/asm-sh/rtc.h
+++ b/include/asm-sh/rtc.h
@@ -5,4 +5,10 @@ extern void (*board_time_init)(void);
extern void (*rtc_sh_get_time)(struct timespec *);
extern int (*rtc_sh_set_time)(const time_t);
+#define RTC_CAP_4_DIGIT_YEAR (1 << 0)
+
+struct sh_rtc_platform_info {
+ unsigned long capabilities;
+};
+
#endif /* _ASM_RTC_H */
diff --git a/include/asm-sh/rts7751r2d.h b/include/asm-sh/rts7751r2d.h
index 5d7800aa31b..83b9c111f17 100644
--- a/include/asm-sh/rts7751r2d.h
+++ b/include/asm-sh/rts7751r2d.h
@@ -9,7 +9,7 @@
* Renesas Technology Sales RTS7751R2D support
*/
-/* Box specific addresses. */
+/* Board specific addresses. */
#define PA_BCR 0xa4000000 /* FPGA */
#define PA_IRLMON 0xa4000002 /* Interrupt Status control */
@@ -20,19 +20,19 @@
#define PA_RTCCE 0xa400000c /* RTC(9701) Enable control */
#define PA_PCICD 0xa400000e /* PCI Extention detect control */
#define PA_VOYAGERRTS 0xa4000020 /* VOYAGER Reset control */
-#if defined(CONFIG_RTS7751R2D_REV11)
-#define PA_AXRST 0xa4000022 /* AX_LAN Reset control */
-#define PA_CFRST 0xa4000024 /* CF Reset control */
-#define PA_ADMRTS 0xa4000026 /* SD Reset control */
-#define PA_EXTRST 0xa4000028 /* Extention Reset control */
-#define PA_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */
-#else
-#define PA_CFRST 0xa4000022 /* CF Reset control */
-#define PA_ADMRTS 0xa4000024 /* SD Reset control */
-#define PA_EXTRST 0xa4000026 /* Extention Reset control */
-#define PA_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */
-#define PA_KEYCTLCLR 0xa400002a /* Key Interrupt clear */
-#endif
+
+#define PA_R2D1_AXRST 0xa4000022 /* AX_LAN Reset control */
+#define PA_R2D1_CFRST 0xa4000024 /* CF Reset control */
+#define PA_R2D1_ADMRTS 0xa4000026 /* SD Reset control */
+#define PA_R2D1_EXTRST 0xa4000028 /* Extention Reset control */
+#define PA_R2D1_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */
+
+#define PA_R2DPLUS_CFRST 0xa4000022 /* CF Reset control */
+#define PA_R2DPLUS_ADMRTS 0xa4000024 /* SD Reset control */
+#define PA_R2DPLUS_EXTRST 0xa4000026 /* Extention Reset control */
+#define PA_R2DPLUS_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */
+#define PA_R2DPLUS_KEYCTLCLR 0xa400002a /* Key Interrupt clear */
+
#define PA_POWOFF 0xa4000030 /* Board Power OFF control */
#define PA_VERREG 0xa4000032 /* FPGA Version Register */
#define PA_INPORT 0xa4000034 /* KEY Input Port control */
@@ -46,27 +46,22 @@
#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
-#if defined(CONFIG_RTS7751R2D_REV11)
-#define IRQ_PCIETH 0 /* PCI Ethernet IRQ */
-#define IRQ_CFCARD 1 /* CF Card IRQ */
-#define IRQ_CFINST 2 /* CF Card Insert IRQ */
-#define IRQ_PCMCIA 3 /* PCMCIA IRQ */
-#define IRQ_VOYAGER 4 /* VOYAGER IRQ */
-#define IRQ_ONETH 5 /* On board Ethernet IRQ */
-#else
-#define IRQ_KEYIN 0 /* Key Input IRQ */
-#define IRQ_PCIETH 1 /* PCI Ethernet IRQ */
-#define IRQ_CFCARD 2 /* CF Card IRQ */
-#define IRQ_CFINST 3 /* CF Card Insert IRQ */
-#define IRQ_PCMCIA 4 /* PCMCIA IRQ */
-#define IRQ_VOYAGER 5 /* VOYAGER IRQ */
-#endif
-#define IRQ_RTCALM 6 /* RTC Alarm IRQ */
-#define IRQ_RTCTIME 7 /* RTC Timer IRQ */
-#define IRQ_SDCARD 8 /* SD Card IRQ */
-#define IRQ_PCISLOT1 9 /* PCI Slot #1 IRQ */
-#define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */
-#define IRQ_EXTENTION 11 /* EXTn IRQ */
+#define R2D_FPGA_IRQ_BASE 100
+
+#define IRQ_VOYAGER (R2D_FPGA_IRQ_BASE + 0)
+#define IRQ_EXT (R2D_FPGA_IRQ_BASE + 1)
+#define IRQ_TP (R2D_FPGA_IRQ_BASE + 2)
+#define IRQ_RTC_T (R2D_FPGA_IRQ_BASE + 3)
+#define IRQ_RTC_A (R2D_FPGA_IRQ_BASE + 4)
+#define IRQ_SDCARD (R2D_FPGA_IRQ_BASE + 5)
+#define IRQ_CF_CD (R2D_FPGA_IRQ_BASE + 6)
+#define IRQ_CF_IDE (R2D_FPGA_IRQ_BASE + 7)
+#define IRQ_AX88796 (R2D_FPGA_IRQ_BASE + 8)
+#define IRQ_KEY (R2D_FPGA_IRQ_BASE + 9)
+#define IRQ_PCI_INTA (R2D_FPGA_IRQ_BASE + 10)
+#define IRQ_PCI_INTB (R2D_FPGA_IRQ_BASE + 11)
+#define IRQ_PCI_INTC (R2D_FPGA_IRQ_BASE + 12)
+#define IRQ_PCI_INTD (R2D_FPGA_IRQ_BASE + 13)
/* arch/sh/boards/renesas/rts7751r2d/irq.c */
void init_rts7751r2d_IRQ(void);
diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h
index 2a696b8ee4f..bd9cbc967c2 100644
--- a/include/asm-sh/sections.h
+++ b/include/asm-sh/sections.h
@@ -4,6 +4,7 @@
#include <asm-generic/sections.h>
extern long __machvec_start, __machvec_end;
+extern char _ebss[];
#endif /* __ASM_SH_SECTIONS_H */
diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h
index 4ff1eb90030..c39c785bba9 100644
--- a/include/asm-sh/sh03/io.h
+++ b/include/asm-sh/sh03/io.h
@@ -11,22 +11,13 @@
#include <linux/time.h>
-#define INTC_IPRD 0xffd00010UL
-
#define IRL0_IRQ 2
-#define IRL0_IPR_POS 3
#define IRL0_PRIORITY 13
-
#define IRL1_IRQ 5
-#define IRL1_IPR_POS 2
#define IRL1_PRIORITY 10
-
#define IRL2_IRQ 8
-#define IRL2_IPR_POS 1
#define IRL2_PRIORITY 7
-
#define IRL3_IRQ 11
-#define IRL3_IPR_POS 0
#define IRL3_PRIORITY 4
void heartbeat_sh03(void);
diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h
index b99ca786c0c..9c8d34b07eb 100644
--- a/include/asm-sh/smp.h
+++ b/include/asm-sh/smp.h
@@ -1,12 +1,3 @@
-/*
- * include/asm-sh/smp.h
- *
- * Copyright (C) 2002, 2003 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive for
- * more details.
- */
#ifndef __ASM_SH_SMP_H
#define __ASM_SH_SMP_H
@@ -20,6 +11,15 @@
#include <asm/current.h>
#define raw_smp_processor_id() (current_thread_info()->cpu)
+#define hard_smp_processor_id() plat_smp_processor_id()
+
+/* Map from cpu id to sequential logical cpu number. */
+extern int __cpu_number_map[NR_CPUS];
+#define cpu_number_map(cpu) __cpu_number_map[cpu]
+
+/* The reverse map from sequential logical cpu number to cpu id. */
+extern int __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
/* I've no idea what the real meaning of this is */
#define PROC_CHANGE_PENALTY 20
@@ -35,10 +35,22 @@ struct smp_fn_call_struct {
extern struct smp_fn_call_struct smp_fn_call;
-#define SMP_MSG_RESCHEDULE 0x0001
+#define SMP_MSG_FUNCTION 0
+#define SMP_MSG_RESCHEDULE 1
+#define SMP_MSG_NR 2
-#endif /* CONFIG_SMP */
+void plat_smp_setup(void);
+void plat_prepare_cpus(unsigned int max_cpus);
+int plat_smp_processor_id(void);
+void plat_start_cpu(unsigned int cpu, unsigned long entry_point);
+void plat_send_ipi(unsigned int cpu, unsigned int message);
+int plat_register_ipi_handler(unsigned int message,
+ void (*handler)(void *), void *arg);
+
+#else
#define hard_smp_processor_id() (0)
+#endif /* CONFIG_SMP */
+
#endif /* __ASM_SH_SMP_H */
diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h
index 3554e3a74e9..042d95f51c4 100644
--- a/include/asm-sh/snapgear.h
+++ b/include/asm-sh/snapgear.h
@@ -19,20 +19,16 @@
* is the interrupt :-)
*/
-#define IRL0_IRQ 2
-#define IRL0_IPR_POS 3
+#define IRL0_IRQ 2
#define IRL0_PRIORITY 13
-#define IRL1_IRQ 5
-#define IRL1_IPR_POS 2
+#define IRL1_IRQ 5
#define IRL1_PRIORITY 10
-#define IRL2_IRQ 8
-#define IRL2_IPR_POS 1
+#define IRL2_IRQ 8
#define IRL2_PRIORITY 7
-#define IRL3_IRQ 11
-#define IRL3_IPR_POS 0
+#define IRL3_IRQ 11
#define IRL3_PRIORITY 4
#endif
diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h
index 92f6e2008b2..e793181d64d 100644
--- a/include/asm-sh/spinlock.h
+++ b/include/asm-sh/spinlock.h
@@ -2,6 +2,7 @@
* include/asm-sh/spinlock.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2006, 2007 Akio Idehara
*
* 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
@@ -10,17 +11,22 @@
#ifndef __ASM_SH_SPINLOCK_H
#define __ASM_SH_SPINLOCK_H
-#include <asm/atomic.h>
-#include <asm/spinlock_types.h>
+/*
+ * The only locking implemented here uses SH-4A opcodes. For others,
+ * split this out as per atomic-*.h.
+ */
+#ifndef CONFIG_CPU_SH4A
+#error "Need movli.l/movco.l for spinlocks"
+#endif
/*
* Your basic SMP spinlocks, allowing only a single CPU anywhere
*/
-#define __raw_spin_is_locked(x) ((x)->lock != 0)
+#define __raw_spin_is_locked(x) ((x)->lock <= 0)
#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
#define __raw_spin_unlock_wait(x) \
- do { cpu_relax(); } while (__raw_spin_is_locked(x))
+ do { cpu_relax(); } while ((x)->lock)
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
@@ -30,12 +36,19 @@
*/
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
+ unsigned long tmp;
+ unsigned long oldval;
+
__asm__ __volatile__ (
- "1:\n\t"
- "tas.b @%0\n\t"
- "bf/s 1b\n\t"
- "nop\n\t"
- : "=r" (lock->lock)
+ "1: \n\t"
+ "movli.l @%2, %0 ! __raw_spin_lock \n\t"
+ "mov %0, %1 \n\t"
+ "mov #0, %0 \n\t"
+ "movco.l %0, @%2 \n\t"
+ "bf 1b \n\t"
+ "cmp/pl %1 \n\t"
+ "bf 1b \n\t"
+ : "=&z" (tmp), "=&r" (oldval)
: "r" (&lock->lock)
: "t", "memory"
);
@@ -43,12 +56,36 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
- //assert_spin_locked(lock);
+ unsigned long tmp;
- lock->lock = 0;
+ __asm__ __volatile__ (
+ "mov #1, %0 ! __raw_spin_unlock \n\t"
+ "mov.l %0, @%1 \n\t"
+ : "=&z" (tmp)
+ : "r" (&lock->lock)
+ : "t", "memory"
+ );
}
-#define __raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock))
+static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+ unsigned long tmp, oldval;
+
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%2, %0 ! __raw_spin_trylock \n\t"
+ "mov %0, %1 \n\t"
+ "mov #0, %0 \n\t"
+ "movco.l %0, @%2 \n\t"
+ "bf 1b \n\t"
+ "synco \n\t"
+ : "=&z" (tmp), "=&r" (oldval)
+ : "r" (&lock->lock)
+ : "t", "memory"
+ );
+
+ return oldval;
+}
/*
* Read-write spinlocks, allowing multiple readers but only one writer.
@@ -59,58 +96,124 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
* read-locks.
*/
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_read_can_lock(x) ((x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
+
static inline void __raw_read_lock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
-
- atomic_inc(&rw->counter);
+ unsigned long tmp;
- __raw_spin_unlock(&rw->lock);
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%1, %0 ! __raw_read_lock \n\t"
+ "cmp/pl %0 \n\t"
+ "bf 1b \n\t"
+ "add #-1, %0 \n\t"
+ "movco.l %0, @%1 \n\t"
+ "bf 1b \n\t"
+ : "=&z" (tmp)
+ : "r" (&rw->lock)
+ : "t", "memory"
+ );
}
static inline void __raw_read_unlock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
-
- atomic_dec(&rw->counter);
+ unsigned long tmp;
- __raw_spin_unlock(&rw->lock);
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%1, %0 ! __raw_read_unlock \n\t"
+ "add #1, %0 \n\t"
+ "movco.l %0, @%1 \n\t"
+ "bf 1b \n\t"
+ : "=&z" (tmp)
+ : "r" (&rw->lock)
+ : "t", "memory"
+ );
}
static inline void __raw_write_lock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
- atomic_set(&rw->counter, -1);
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%1, %0 ! __raw_write_lock \n\t"
+ "cmp/hs %2, %0 \n\t"
+ "bf 1b \n\t"
+ "sub %2, %0 \n\t"
+ "movco.l %0, @%1 \n\t"
+ "bf 1b \n\t"
+ : "=&z" (tmp)
+ : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+ : "t", "memory"
+ );
}
static inline void __raw_write_unlock(raw_rwlock_t *rw)
{
- atomic_set(&rw->counter, 0);
- __raw_spin_unlock(&rw->lock);
+ __asm__ __volatile__ (
+ "mov.l %1, @%0 ! __raw_write_unlock \n\t"
+ :
+ : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+ : "t", "memory"
+ );
}
-static inline int __raw_write_can_lock(raw_rwlock_t *rw)
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
{
- return (atomic_read(&rw->counter) == RW_LOCK_BIAS);
-}
+ unsigned long tmp, oldval;
-static inline int __raw_read_trylock(raw_rwlock_t *lock)
-{
- atomic_t *count = (atomic_t*)lock;
- if (atomic_dec_return(count) >= 0)
- return 1;
- atomic_inc(count);
- return 0;
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%2, %0 ! __raw_read_trylock \n\t"
+ "mov %0, %1 \n\t"
+ "cmp/pl %0 \n\t"
+ "bf 2f \n\t"
+ "add #-1, %0 \n\t"
+ "movco.l %0, @%2 \n\t"
+ "bf 1b \n\t"
+ "2: \n\t"
+ "synco \n\t"
+ : "=&z" (tmp), "=&r" (oldval)
+ : "r" (&rw->lock)
+ : "t", "memory"
+ );
+
+ return (oldval > 0);
}
static inline int __raw_write_trylock(raw_rwlock_t *rw)
{
- if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter))
- return 1;
-
- atomic_add(RW_LOCK_BIAS, &rw->counter);
+ unsigned long tmp, oldval;
+
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "movli.l @%2, %0 ! __raw_write_trylock \n\t"
+ "mov %0, %1 \n\t"
+ "cmp/hs %3, %0 \n\t"
+ "bf 2f \n\t"
+ "sub %3, %0 \n\t"
+ "2: \n\t"
+ "movco.l %0, @%2 \n\t"
+ "bf 1b \n\t"
+ "synco \n\t"
+ : "=&z" (tmp), "=&r" (oldval)
+ : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+ : "t", "memory"
+ );
- return 0;
+ return (oldval > (RW_LOCK_BIAS - 1));
}
#define _raw_spin_relax(lock) cpu_relax()
diff --git a/include/asm-sh/spinlock_types.h b/include/asm-sh/spinlock_types.h
index 5c58134f2c4..b4d244e7b60 100644
--- a/include/asm-sh/spinlock_types.h
+++ b/include/asm-sh/spinlock_types.h
@@ -6,19 +6,16 @@
#endif
typedef struct {
- volatile unsigned long lock;
+ volatile unsigned int lock;
} raw_spinlock_t;
-#define __RAW_SPIN_LOCK_UNLOCKED { 1 }
-
-#include <asm/atomic.h>
+#define __RAW_SPIN_LOCK_UNLOCKED { 1 }
typedef struct {
- raw_spinlock_t lock;
- atomic_t counter;
+ volatile unsigned int lock;
} raw_rwlock_t;
#define RW_LOCK_BIAS 0x01000000
-#define __RAW_RW_LOCK_UNLOCKED { { 0 }, { RW_LOCK_BIAS } }
+#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS }
#endif
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index 24504253720..9d849e6df26 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -266,6 +266,7 @@ void disable_hlt(void);
void enable_hlt(void);
void default_idle(void);
+void per_cpu_trap_init(void);
asmlinkage void break_point_trap(void);
asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
diff --git a/include/asm-sh/voyagergx.h b/include/asm-sh/voyagergx.h
index 64c936b2271..d825596562d 100644
--- a/include/asm-sh/voyagergx.h
+++ b/include/asm-sh/voyagergx.h
@@ -27,13 +27,35 @@
#define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE)
#define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE)
-#define VOYAGER_IRQ_NUM 32
-#define VOYAGER_IRQ_BASE 50
-#define VOYAGER_USBH_IRQ VOYAGER_IRQ_BASE + 6
-#define VOYAGER_8051_IRQ VOYAGER_IRQ_BASE + 10
-#define VOYAGER_UART0_IRQ VOYAGER_IRQ_BASE + 12
-#define VOYAGER_UART1_IRQ VOYAGER_IRQ_BASE + 13
-#define VOYAGER_AC97_IRQ VOYAGER_IRQ_BASE + 17
+#define VOYAGER_IRQ_NUM 26
+#define VOYAGER_IRQ_BASE 200
+
+#define IRQ_SM501_UP (VOYAGER_IRQ_BASE + 0)
+#define IRQ_SM501_G54 (VOYAGER_IRQ_BASE + 1)
+#define IRQ_SM501_G53 (VOYAGER_IRQ_BASE + 2)
+#define IRQ_SM501_G52 (VOYAGER_IRQ_BASE + 3)
+#define IRQ_SM501_G51 (VOYAGER_IRQ_BASE + 4)
+#define IRQ_SM501_G50 (VOYAGER_IRQ_BASE + 5)
+#define IRQ_SM501_G49 (VOYAGER_IRQ_BASE + 6)
+#define IRQ_SM501_G48 (VOYAGER_IRQ_BASE + 7)
+#define IRQ_SM501_I2C (VOYAGER_IRQ_BASE + 8)
+#define IRQ_SM501_PW (VOYAGER_IRQ_BASE + 9)
+#define IRQ_SM501_DMA (VOYAGER_IRQ_BASE + 10)
+#define IRQ_SM501_PCI (VOYAGER_IRQ_BASE + 11)
+#define IRQ_SM501_I2S (VOYAGER_IRQ_BASE + 12)
+#define IRQ_SM501_AC (VOYAGER_IRQ_BASE + 13)
+#define IRQ_SM501_US (VOYAGER_IRQ_BASE + 14)
+#define IRQ_SM501_U1 (VOYAGER_IRQ_BASE + 15)
+#define IRQ_SM501_U0 (VOYAGER_IRQ_BASE + 16)
+#define IRQ_SM501_CV (VOYAGER_IRQ_BASE + 17)
+#define IRQ_SM501_MC (VOYAGER_IRQ_BASE + 18)
+#define IRQ_SM501_S1 (VOYAGER_IRQ_BASE + 19)
+#define IRQ_SM501_S0 (VOYAGER_IRQ_BASE + 20)
+#define IRQ_SM501_UH (VOYAGER_IRQ_BASE + 21)
+#define IRQ_SM501_2D (VOYAGER_IRQ_BASE + 22)
+#define IRQ_SM501_ZD (VOYAGER_IRQ_BASE + 23)
+#define IRQ_SM501_PV (VOYAGER_IRQ_BASE + 24)
+#define IRQ_SM501_CI (VOYAGER_IRQ_BASE + 25)
/* ----- MISC controle register ------------------------------ */
#define MISC_CTRL (0x000004 + VOYAGER_BASE)
@@ -313,4 +335,7 @@
void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+/* arch/sh/cchips/voyagergx/irq.c */
+void setup_voyagergx_irq(void);
+
#endif /* _VOYAGER_GX_REG_H */
diff --git a/include/asm-sh64/gpio.h b/include/asm-sh64/gpio.h
new file mode 100644
index 00000000000..6bc5a13d841
--- /dev/null
+++ b/include/asm-sh64/gpio.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_SH64_GPIO_H
+#define __ASM_SH64_GPIO_H
+
+/*
+ * This is just a stub, so that every arch using sh-sci has a gpio.h
+ */
+
+#endif /* __ASM_SH64_GPIO_H */
diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h
index 1f37b693192..3de3ad99f45 100644
--- a/include/asm-sh64/io.h
+++ b/include/asm-sh64/io.h
@@ -119,6 +119,13 @@ void insw(unsigned long port, void *addr, unsigned long count);
void outsl(unsigned long port, const void *addr, unsigned long count);
void insl(unsigned long port, void *addr, unsigned long count);
+#define inb_p(addr) inb(addr)
+#define inw_p(addr) inw(addr)
+#define inl_p(addr) inl(addr)
+#define outb_p(x,addr) outb(x,addr)
+#define outw_p(x,addr) outw(x,addr)
+#define outl_p(x,addr) outl(x,addr)
+
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
diff --git a/include/asm-sparc/irqflags.h b/include/asm-sparc/irqflags.h
new file mode 100644
index 00000000000..db398fb3282
--- /dev/null
+++ b/include/asm-sparc/irqflags.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-sparc/irqflags.h
+ *
+ * IRQ flags handling
+ *
+ * This file gets included from lowlevel asm headers too, to provide
+ * wrapped versions of the local_irq_*() APIs, based on the
+ * raw_local_irq_*() functions from the lowlevel headers.
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+extern void raw_local_irq_restore(unsigned long);
+extern unsigned long __raw_local_irq_save(void);
+extern void raw_local_irq_enable(void);
+
+static inline unsigned long getipl(void)
+{
+ unsigned long retval;
+
+ __asm__ __volatile__("rd %%psr, %0" : "=r" (retval));
+ return retval;
+}
+
+#define raw_local_save_flags(flags) ((flags) = getipl())
+#define raw_local_irq_save(flags) ((flags) = __raw_local_irq_save())
+#define raw_local_irq_disable() ((void) __raw_local_irq_save())
+#define raw_irqs_disabled() ((getipl() & PSR_PIL) != 0)
+
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+ return ((flags & PSR_PIL) != 0);
+}
+
+#endif /* (__ASSEMBLY__) */
+
+#endif /* !(_ASM_IRQFLAGS_H) */
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index d1a2572e3f5..8c259de0261 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -15,6 +15,8 @@
#ifndef __ASSEMBLY__
+#include <linux/irqflags.h>
+
/*
* Sparc (general) CPU types
*/
@@ -164,26 +166,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
"o0", "o1", "o2", "o3", "o7"); \
} while(0)
-/*
- * Changing the IRQ level on the Sparc.
- */
-extern void local_irq_restore(unsigned long);
-extern unsigned long __local_irq_save(void);
-extern void local_irq_enable(void);
-
-static inline unsigned long getipl(void)
-{
- unsigned long retval;
-
- __asm__ __volatile__("rd %%psr, %0" : "=r" (retval));
- return retval;
-}
-
-#define local_save_flags(flags) ((flags) = getipl())
-#define local_irq_save(flags) ((flags) = __local_irq_save())
-#define local_irq_disable() ((void) __local_irq_save())
-#define irqs_disabled() ((getipl() & PSR_PIL) != 0)
-
/* XXX Change this if we ever use a PSO mode kernel. */
#define mb() __asm__ __volatile__ ("" : : : "memory")
#define rmb() mb()
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 98a6e609163..542421460a1 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -75,12 +75,11 @@ struct trap_per_cpu {
unsigned long tsb_huge_temp;
/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */
- unsigned int irq_worklist;
+ unsigned long irq_worklist_pa;
unsigned int cpu_mondo_qmask;
unsigned int dev_mondo_qmask;
unsigned int resum_qmask;
unsigned int nonresum_qmask;
- unsigned int __pad2[1];
void *hdesc;
} __attribute__((aligned(64)));
extern struct trap_per_cpu trap_block[NR_CPUS];
@@ -128,11 +127,11 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
#define TRAP_PER_CPU_CPU_LIST_PA 0xc8
#define TRAP_PER_CPU_TSB_HUGE 0xd0
#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8
-#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0
-#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe4
-#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xe8
-#define TRAP_PER_CPU_RESUM_QMASK 0xec
-#define TRAP_PER_CPU_NONRESUM_QMASK 0xf0
+#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0
+#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8
+#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec
+#define TRAP_PER_CPU_RESUM_QMASK 0xf0
+#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4
#define TRAP_BLOCK_SZ_SHIFT 8
@@ -184,9 +183,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
/* Clobbers TMP, loads local processor's IRQ work area into DEST. */
-#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
- add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST;
+ add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
/* Clobbers TMP, loads DEST with current thread info pointer. */
#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
@@ -223,9 +222,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
/* Clobbers TMP, loads local processor's IRQ work area into DEST. */
-#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
- add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST;
+ add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
index c00ad152771..182dba05c70 100644
--- a/include/asm-sparc64/irq.h
+++ b/include/asm-sparc64/irq.h
@@ -51,10 +51,19 @@ extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_devino_start,
unsigned int msi_devino_end);
extern void sun4v_destroy_msi(unsigned int virt_irq);
+extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
+ unsigned int msi_devino_start,
+ unsigned int msi_devino_end,
+ unsigned long imap_base,
+ unsigned long iclr_base);
+extern void sun4u_destroy_msi(unsigned int virt_irq);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
-extern void sparc64_set_msi(unsigned int virt_irq, u32 msi);
-extern u32 sparc64_get_msi(unsigned int virt_irq);
+extern unsigned char virt_irq_alloc(unsigned int dev_handle,
+ unsigned int dev_ino);
+#ifdef CONFIG_PCI_MSI
+extern void virt_irq_free(unsigned int virt_irq);
+#endif
extern void fixup_irqs(void);
diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h
deleted file mode 100644
index d3c2b38a661..00000000000
--- a/include/asm-x86/8253pit.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_X86_32
-# include "8253pit_32.h"
-#else
-# include "8253pit_64.h"
-#endif
diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h
deleted file mode 100644
index 96c7c3592da..00000000000
--- a/include/asm-x86/8253pit_32.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#include <asm/timex.h>
-
-#define PIT_TICK_RATE CLOCK_TICK_RATE
-
-#endif
diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h
deleted file mode 100644
index 285f78488cc..00000000000
--- a/include/asm-x86/8253pit_64.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#define PIT_TICK_RATE 1193182UL
-
-#endif
diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h
index 85125ef3c41..3c8f21eef0b 100644
--- a/include/asm-x86/apic_64.h
+++ b/include/asm-x86/apic_64.h
@@ -19,7 +19,7 @@
extern int apic_verbosity;
extern int apic_runs_main_timer;
extern int ioapic_force;
-extern int apic_mapped;
+extern int disable_apic_timer;
/*
* Define the default level of output to be very little
@@ -79,8 +79,6 @@ extern void smp_local_timer_interrupt (void);
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern int APIC_init_uniprocessor (void);
-extern void disable_APIC_timer(void);
-extern void enable_APIC_timer(void);
extern void setup_apic_routing(void);
extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
@@ -95,10 +93,6 @@ extern int apic_is_clustered_box(void);
#define K8_APIC_EXT_INT_MSG_EXT 0x7
#define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0
-void smp_send_timer_broadcast_ipi(void);
-void switch_APIC_timer_to_ipi(void *cpumask);
-void switch_ipi_to_APIC_timer(void *cpumask);
-
#define ARCH_APICTIMER_STOPS_ON_C3 1
extern unsigned boot_cpu_id;
diff --git a/include/asm-x86/cpufeature_64.h b/include/asm-x86/cpufeature_64.h
index 2983501e8b3..e18496b7b85 100644
--- a/include/asm-x86/cpufeature_64.h
+++ b/include/asm-x86/cpufeature_64.h
@@ -7,7 +7,7 @@
#ifndef __ASM_X8664_CPUFEATURE_H
#define __ASM_X8664_CPUFEATURE_H
-#include <asm/cpufeature_32.h>
+#include "cpufeature_32.h"
#undef cpu_has_vme
#define cpu_has_vme 0
diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h
index 6da4bbbea3d..d94898831ba 100644
--- a/include/asm-x86/geode.h
+++ b/include/asm-x86/geode.h
@@ -156,4 +156,54 @@ static inline int is_geode(void)
return (is_geode_gx() || is_geode_lx());
}
+/* MFGPTs */
+
+#define MFGPT_MAX_TIMERS 8
+#define MFGPT_TIMER_ANY -1
+
+#define MFGPT_DOMAIN_WORKING 1
+#define MFGPT_DOMAIN_STANDBY 2
+#define MFGPT_DOMAIN_ANY (MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY)
+
+#define MFGPT_CMP1 0
+#define MFGPT_CMP2 1
+
+#define MFGPT_EVENT_IRQ 0
+#define MFGPT_EVENT_NMI 1
+#define MFGPT_EVENT_RESET 3
+
+#define MFGPT_REG_CMP1 0
+#define MFGPT_REG_CMP2 2
+#define MFGPT_REG_COUNTER 4
+#define MFGPT_REG_SETUP 6
+
+#define MFGPT_SETUP_CNTEN (1 << 15)
+#define MFGPT_SETUP_CMP2 (1 << 14)
+#define MFGPT_SETUP_CMP1 (1 << 13)
+#define MFGPT_SETUP_SETUP (1 << 12)
+#define MFGPT_SETUP_STOPEN (1 << 11)
+#define MFGPT_SETUP_EXTEN (1 << 10)
+#define MFGPT_SETUP_REVEN (1 << 5)
+#define MFGPT_SETUP_CLKSEL (1 << 4)
+
+static inline void geode_mfgpt_write(int timer, u16 reg, u16 value)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+ outw(value, base + reg + (timer * 8));
+}
+
+static inline u16 geode_mfgpt_read(int timer, u16 reg)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+ return inw(base + reg + (timer * 8));
+}
+
+extern int __init geode_mfgpt_detect(void);
+extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable);
+extern int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable);
+extern int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner);
+
+#define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1)
+#define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0)
+
#endif
diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h
index 0e358dc405f..34649585bb5 100644
--- a/include/asm-x86/hardirq_32.h
+++ b/include/asm-x86/hardirq_32.h
@@ -9,6 +9,7 @@ typedef struct {
unsigned long idle_timestamp;
unsigned int __nmi_count; /* arch dependent */
unsigned int apic_timer_irqs; /* arch dependent */
+ unsigned int irq0_irqs;
} ____cacheline_aligned irq_cpustat_t;
DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index 9eff4860125..d4ab6db050b 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -1,5 +1,93 @@
-#ifdef CONFIG_X86_32
-# include "hpet_32.h"
+#ifndef ASM_X86_HPET_H
+#define ASM_X86_HPET_H
+
+#ifdef CONFIG_HPET_TIMER
+
+/*
+ * Documentation on HPET can be found at:
+ * http://www.intel.com/ial/home/sp/pcmmspec.htm
+ * ftp://download.intel.com/ial/home/sp/mmts098.pdf
+ */
+
+#define HPET_MMAP_SIZE 1024
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+#define HPET_CFG 0x010
+#define HPET_STATUS 0x020
+#define HPET_COUNTER 0x0f0
+#define HPET_T0_CFG 0x100
+#define HPET_T0_CMP 0x108
+#define HPET_T0_ROUTE 0x110
+#define HPET_T1_CFG 0x120
+#define HPET_T1_CMP 0x128
+#define HPET_T1_ROUTE 0x130
+#define HPET_T2_CFG 0x140
+#define HPET_T2_CMP 0x148
+#define HPET_T2_ROUTE 0x150
+
+#define HPET_ID_REV 0x000000ff
+#define HPET_ID_NUMBER 0x00001f00
+#define HPET_ID_64BIT 0x00002000
+#define HPET_ID_LEGSUP 0x00008000
+#define HPET_ID_VENDOR 0xffff0000
+#define HPET_ID_NUMBER_SHIFT 8
+#define HPET_ID_VENDOR_SHIFT 16
+
+#define HPET_ID_VENDOR_8086 0x8086
+
+#define HPET_CFG_ENABLE 0x001
+#define HPET_CFG_LEGACY 0x002
+#define HPET_LEGACY_8254 2
+#define HPET_LEGACY_RTC 8
+
+#define HPET_TN_LEVEL 0x0002
+#define HPET_TN_ENABLE 0x0004
+#define HPET_TN_PERIODIC 0x0008
+#define HPET_TN_PERIODIC_CAP 0x0010
+#define HPET_TN_64BIT_CAP 0x0020
+#define HPET_TN_SETVAL 0x0040
+#define HPET_TN_32BIT 0x0100
+#define HPET_TN_ROUTE 0x3e00
+#define HPET_TN_FSB 0x4000
+#define HPET_TN_FSB_CAP 0x8000
+#define HPET_TN_ROUTE_SHIFT 9
+
+/* Max HPET Period is 10^8 femto sec as in HPET spec */
+#define HPET_MAX_PERIOD 100000000UL
+/*
+ * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
+ * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
+ */
+#define HPET_MIN_PERIOD 100000UL
+
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
+extern unsigned long force_hpet_address;
+extern int is_hpet_enabled(void);
+extern int hpet_enable(void);
+extern unsigned long hpet_readl(unsigned long a);
+extern void force_hpet_resume(void);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
+extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+ unsigned char sec);
+extern int hpet_set_periodic_freq(unsigned long freq);
+extern int hpet_rtc_dropped_irq(void);
+extern int hpet_rtc_timer_init(void);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
+#endif /* CONFIG_HPET_EMULATE_RTC */
+
#else
-# include "hpet_64.h"
-#endif
+
+static inline int hpet_enable(void) { return 0; }
+static inline unsigned long hpet_readl(unsigned long a) { return 0; }
+
+#endif /* CONFIG_HPET_TIMER */
+#endif /* ASM_X86_HPET_H */
diff --git a/include/asm-x86/hpet_32.h b/include/asm-x86/hpet_32.h
deleted file mode 100644
index c82dc7ed96b..00000000000
--- a/include/asm-x86/hpet_32.h
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#ifndef _I386_HPET_H
-#define _I386_HPET_H
-
-#ifdef CONFIG_HPET_TIMER
-
-/*
- * Documentation on HPET can be found at:
- * http://www.intel.com/ial/home/sp/pcmmspec.htm
- * ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE 1024
-
-#define HPET_ID 0x000
-#define HPET_PERIOD 0x004
-#define HPET_CFG 0x010
-#define HPET_STATUS 0x020
-#define HPET_COUNTER 0x0f0
-#define HPET_T0_CFG 0x100
-#define HPET_T0_CMP 0x108
-#define HPET_T0_ROUTE 0x110
-#define HPET_T1_CFG 0x120
-#define HPET_T1_CMP 0x128
-#define HPET_T1_ROUTE 0x130
-#define HPET_T2_CFG 0x140
-#define HPET_T2_CMP 0x148
-#define HPET_T2_ROUTE 0x150
-
-#define HPET_ID_REV 0x000000ff
-#define HPET_ID_NUMBER 0x00001f00
-#define HPET_ID_64BIT 0x00002000
-#define HPET_ID_LEGSUP 0x00008000
-#define HPET_ID_VENDOR 0xffff0000
-#define HPET_ID_NUMBER_SHIFT 8
-#define HPET_ID_VENDOR_SHIFT 16
-
-#define HPET_ID_VENDOR_8086 0x8086
-
-#define HPET_CFG_ENABLE 0x001
-#define HPET_CFG_LEGACY 0x002
-#define HPET_LEGACY_8254 2
-#define HPET_LEGACY_RTC 8
-
-#define HPET_TN_LEVEL 0x0002
-#define HPET_TN_ENABLE 0x0004
-#define HPET_TN_PERIODIC 0x0008
-#define HPET_TN_PERIODIC_CAP 0x0010
-#define HPET_TN_64BIT_CAP 0x0020
-#define HPET_TN_SETVAL 0x0040
-#define HPET_TN_32BIT 0x0100
-#define HPET_TN_ROUTE 0x3e00
-#define HPET_TN_FSB 0x4000
-#define HPET_TN_FSB_CAP 0x8000
-#define HPET_TN_ROUTE_SHIFT 9
-
-/* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD 100000000UL
-/*
- * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
- * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
- */
-#define HPET_MIN_PERIOD 100000UL
-
-/* hpet memory map physical address */
-extern unsigned long hpet_address;
-extern int is_hpet_enabled(void);
-extern int hpet_enable(void);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-
-#include <linux/interrupt.h>
-
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
- unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
-
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
-#else
-
-static inline int hpet_enable(void) { return 0; }
-
-#endif /* CONFIG_HPET_TIMER */
-#endif /* _I386_HPET_H */
diff --git a/include/asm-x86/hpet_64.h b/include/asm-x86/hpet_64.h
deleted file mode 100644
index fd4decac93a..00000000000
--- a/include/asm-x86/hpet_64.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _ASM_X8664_HPET_H
-#define _ASM_X8664_HPET_H 1
-
-#include <asm/hpet_32.h>
-
-#define HPET_TICK_RATE (HZ * 100000UL)
-
-extern int hpet_rtc_timer_init(void);
-extern int hpet_arch_init(void);
-extern int hpet_timer_stop_set_go(unsigned long tick);
-extern int hpet_reenable(void);
-extern unsigned int hpet_calibrate_tsc(void);
-
-extern int hpet_use_timer;
-extern unsigned long hpet_period;
-extern unsigned long hpet_tick;
-
-#endif
diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h
index b2a4f995a33..747548ec5d1 100644
--- a/include/asm-x86/i8253.h
+++ b/include/asm-x86/i8253.h
@@ -1,5 +1,15 @@
-#ifdef CONFIG_X86_32
-# include "i8253_32.h"
-#else
-# include "i8253_64.h"
-#endif
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+/* i8253A PIT registers */
+#define PIT_MODE 0x43
+#define PIT_CH0 0x40
+#define PIT_CH2 0x42
+
+extern spinlock_t i8253_lock;
+
+extern struct clock_event_device *global_clock_event;
+
+extern void setup_pit_timer(void);
+
+#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h
deleted file mode 100644
index 7577d058d86..00000000000
--- a/include/asm-x86/i8253_32.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-#include <linux/clockchips.h>
-
-/* i8253A PIT registers */
-#define PIT_MODE 0x43
-#define PIT_CH0 0x40
-#define PIT_CH2 0x42
-
-extern spinlock_t i8253_lock;
-
-extern struct clock_event_device *global_clock_event;
-
-extern void setup_pit_timer(void);
-
-#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_64.h b/include/asm-x86/i8253_64.h
deleted file mode 100644
index 015d8df0769..00000000000
--- a/include/asm-x86/i8253_64.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-extern spinlock_t i8253_lock;
-
-#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86/io_apic_32.h b/include/asm-x86/io_apic_32.h
index dbe734ddf2a..3f087883ea4 100644
--- a/include/asm-x86/io_apic_32.h
+++ b/include/asm-x86/io_apic_32.h
@@ -11,8 +11,6 @@
* Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
*/
-#ifdef CONFIG_X86_IO_APIC
-
/*
* The structure of the IO-APIC:
*/
@@ -55,12 +53,6 @@ union IO_APIC_reg_03 {
} __attribute__ ((packed)) bits;
};
-/*
- * # of IO-APICs and # of IRQ routing registers
- */
-extern int nr_ioapics;
-extern int nr_ioapic_registers[MAX_IO_APICS];
-
enum ioapic_irq_destination_types {
dest_Fixed = 0,
dest_LowestPrio = 1,
@@ -100,6 +92,14 @@ struct IO_APIC_route_entry {
} __attribute__ ((packed));
+#ifdef CONFIG_X86_IO_APIC
+
+/*
+ * # of IO-APICs and # of IRQ routing registers
+ */
+extern int nr_ioapics;
+extern int nr_ioapic_registers[MAX_IO_APICS];
+
/*
* MP-BIOS irq configuration table structures:
*/
diff --git a/include/asm-x86/irqflags_32.h b/include/asm-x86/irqflags_32.h
index eff8585cb74..d058b04e008 100644
--- a/include/asm-x86/irqflags_32.h
+++ b/include/asm-x86/irqflags_32.h
@@ -160,4 +160,17 @@ static inline int raw_irqs_disabled(void)
# define TRACE_IRQS_OFF
#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define LOCKDEP_SYS_EXIT \
+ pushl %eax; \
+ pushl %ecx; \
+ pushl %edx; \
+ call lockdep_sys_exit; \
+ popl %edx; \
+ popl %ecx; \
+ popl %eax;
+#else
+# define LOCKDEP_SYS_EXIT
+#endif
+
#endif
diff --git a/include/asm-x86/irqflags_64.h b/include/asm-x86/irqflags_64.h
index 86e70fe2365..5341ea1f815 100644
--- a/include/asm-x86/irqflags_64.h
+++ b/include/asm-x86/irqflags_64.h
@@ -137,6 +137,20 @@ static inline void halt(void)
# define TRACE_IRQS_ON
# define TRACE_IRQS_OFF
# endif
+# ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define LOCKDEP_SYS_EXIT call lockdep_sys_exit_thunk
+# define LOCKDEP_SYS_EXIT_IRQ \
+ TRACE_IRQS_ON; \
+ sti; \
+ SAVE_REST; \
+ LOCKDEP_SYS_EXIT; \
+ RESTORE_REST; \
+ cli; \
+ TRACE_IRQS_OFF;
+# else
+# define LOCKDEP_SYS_EXIT
+# define LOCKDEP_SYS_EXIT_IRQ
+# endif
#endif
#endif
diff --git a/include/asm-x86/pci.h b/include/asm-x86/pci.h
index a8cac8c2cde..e8836196634 100644
--- a/include/asm-x86/pci.h
+++ b/include/asm-x86/pci.h
@@ -1,5 +1,95 @@
+#ifndef __x86_PCI_H
+#define __x86_PCI_H
+
+#include <linux/mm.h> /* for struct page */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+
+#ifdef __KERNEL__
+
+struct pci_sysdata {
+ int domain; /* PCI domain */
+ int node; /* NUMA node */
+#ifdef CONFIG_X86_64
+ void* iommu; /* IOMMU private data */
+#endif
+};
+
+/* scan a bus after allocating a pci_sysdata for it */
+extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
+
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+ return pci_domain_nr(bus);
+}
+
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ already-configured bus numbers - to be used for buggy BIOSes
+ or architectures with incomplete PCI setup by the loader */
+
+#ifdef CONFIG_PCI
+extern unsigned int pcibios_assign_all_busses(void);
+#else
+#define pcibios_assign_all_busses() 0
+#endif
+#define pcibios_scan_all_fns(a, b) 0
+
+extern unsigned long pci_mem_start;
+#define PCIBIOS_MIN_IO 0x1000
+#define PCIBIOS_MIN_MEM (pci_mem_start)
+
+#define PCIBIOS_MIN_CARDBUS_IO 0x4000
+
+void pcibios_config_init(void);
+struct pci_bus * pcibios_scan_root(int bus);
+
+void pcibios_set_master(struct pci_dev *dev);
+void pcibios_penalize_isa_irq(int irq, int active);
+struct irq_routing_table *pcibios_get_irq_routing_table(void);
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
+
+
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine);
+
+
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
+
+#endif /* __KERNEL__ */
+
#ifdef CONFIG_X86_32
# include "pci_32.h"
#else
# include "pci_64.h"
#endif
+
+/* implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
+
+/* generic pci stuff */
+#include <asm-generic/pci.h>
+
+
+
+#endif
diff --git a/include/asm-x86/pci_32.h b/include/asm-x86/pci_32.h
index 4fcacc71138..8c4c3a0368e 100644
--- a/include/asm-x86/pci_32.h
+++ b/include/asm-x86/pci_32.h
@@ -4,50 +4,11 @@
#ifdef __KERNEL__
-struct pci_sysdata {
- int node; /* NUMA node */
-};
-
-/* scan a bus after allocating a pci_sysdata for it */
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
-
-#include <linux/mm.h> /* for struct page */
-
-/* Can be used to override the logic in pci_scan_bus for skipping
- already-configured bus numbers - to be used for buggy BIOSes
- or architectures with incomplete PCI setup by the loader */
-
-#ifdef CONFIG_PCI
-extern unsigned int pcibios_assign_all_busses(void);
-#else
-#define pcibios_assign_all_busses() 0
-#endif
-#define pcibios_scan_all_fns(a, b) 0
-
-extern unsigned long pci_mem_start;
-#define PCIBIOS_MIN_IO 0x1000
-#define PCIBIOS_MIN_MEM (pci_mem_start)
-
-#define PCIBIOS_MIN_CARDBUS_IO 0x4000
-
-void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int bus);
-
-void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq, int active);
-struct irq_routing_table *pcibios_get_irq_routing_table(void);
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
/* Dynamic DMA mapping stuff.
* i386 has everything mapped statically.
*/
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/io.h>
-
struct pci_dev;
/* The PCI address space does equal the physical memory
@@ -64,27 +25,8 @@ struct pci_dev;
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-#define HAVE_PCI_MMAP
-extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine);
-
-
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
#endif /* __KERNEL__ */
-/* implement the pci_ DMA API in terms of the generic device dma_ one */
-#include <asm-generic/pci-dma-compat.h>
-
-/* generic pci stuff */
-#include <asm-generic/pci.h>
#endif /* __i386_PCI_H */
diff --git a/include/asm-x86/pci_64.h b/include/asm-x86/pci_64.h
index 5da8cb0c059..9baa46d9f59 100644
--- a/include/asm-x86/pci_64.h
+++ b/include/asm-x86/pci_64.h
@@ -1,16 +1,9 @@
#ifndef __x8664_PCI_H
#define __x8664_PCI_H
-#include <asm/io.h>
#ifdef __KERNEL__
-struct pci_sysdata {
- int node; /* NUMA node */
- void* iommu; /* IOMMU private data */
-};
-
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
#ifdef CONFIG_CALGARY_IOMMU
static inline void* pci_iommu(struct pci_bus *bus)
@@ -26,40 +19,11 @@ static inline void set_pci_iommu(struct pci_bus *bus, void *val)
}
#endif /* CONFIG_CALGARY_IOMMU */
-#include <linux/mm.h> /* for struct page */
-
-/* Can be used to override the logic in pci_scan_bus for skipping
- already-configured bus numbers - to be used for buggy BIOSes
- or architectures with incomplete PCI setup by the loader */
-
-#ifdef CONFIG_PCI
-extern unsigned int pcibios_assign_all_busses(void);
-#else
-#define pcibios_assign_all_busses() 0
-#endif
-#define pcibios_scan_all_fns(a, b) 0
-
-extern unsigned long pci_mem_start;
-#define PCIBIOS_MIN_IO 0x1000
-#define PCIBIOS_MIN_MEM (pci_mem_start)
-
-#define PCIBIOS_MIN_CARDBUS_IO 0x4000
-void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int bus);
extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
-void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq, int active);
-struct irq_routing_table *pcibios_get_irq_routing_table(void);
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/page.h>
extern void pci_iommu_alloc(void);
extern int iommu_setup(char *opt);
@@ -100,27 +64,7 @@ extern int iommu_setup(char *opt);
#endif
-#include <asm-generic/pci-dma-compat.h>
-
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
-#define HAVE_PCI_MMAP
-extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine);
-
#endif /* __KERNEL__ */
-/* generic pci stuff */
-#ifdef CONFIG_PCI
-#include <asm-generic/pci.h>
-#endif
#endif /* __x8664_PCI_H */
diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h
index 5642634843c..fb49f80eb94 100644
--- a/include/asm-x86/pda.h
+++ b/include/asm-x86/pda.h
@@ -29,6 +29,7 @@ struct x8664_pda {
short isidle;
struct mm_struct *active_mm;
unsigned apic_timer_irqs;
+ unsigned irq0_irqs;
} ____cacheline_aligned_in_smp;
extern struct x8664_pda *_cpu_pda[];
diff --git a/include/asm-x86/processor-flags.h b/include/asm-x86/processor-flags.h
index 5404e90edd5..199cab107d8 100644
--- a/include/asm-x86/processor-flags.h
+++ b/include/asm-x86/processor-flags.h
@@ -63,7 +63,7 @@
/*
* x86-64 Task Priority Register, CR8
*/
-#define X86_CR8_TPR 0x00000007 /* task priority register */
+#define X86_CR8_TPR 0x0000000F /* task priority register */
/*
* AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h>
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h
index 31f20ad6587..c44a3a93b5a 100644
--- a/include/asm-x86/proto.h
+++ b/include/asm-x86/proto.h
@@ -51,9 +51,6 @@ extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
extern void load_gs_index(unsigned gs);
-extern void stop_timer_interrupt(void);
-extern void main_timer_handler(void);
-
extern unsigned long end_pfn_map;
extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
@@ -90,14 +87,10 @@ extern int timer_over_8254;
extern int gsi_irq_sharing(int gsi);
-extern void smp_local_timer_interrupt(void);
-
extern int force_mwait;
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
-void i8254_timer_resume(void);
-
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define round_down(x,y) ((x) & ~((y)-1))
diff --git a/include/asm-x86/system_32.h b/include/asm-x86/system_32.h
index d69ba937e09..e7e5d426fef 100644
--- a/include/asm-x86/system_32.h
+++ b/include/asm-x86/system_32.h
@@ -216,6 +216,7 @@ static inline unsigned long get_limit(unsigned long segment)
#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
+#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
/**
* read_barrier_depends - Flush all pending reads that subsequents reads
@@ -271,18 +272,18 @@ static inline unsigned long get_limit(unsigned long segment)
#define read_barrier_depends() do { } while(0)
+#ifdef CONFIG_SMP
+#define smp_mb() mb()
+#ifdef CONFIG_X86_PPRO_FENCE
+# define smp_rmb() rmb()
+#else
+# define smp_rmb() barrier()
+#endif
#ifdef CONFIG_X86_OOSTORE
-/* Actually there are no OOO store capable CPUs for now that do SSE,
- but make it already an possibility. */
-#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
+# define smp_wmb() wmb()
#else
-#define wmb() __asm__ __volatile__ ("": : :"memory")
+# define smp_wmb() barrier()
#endif
-
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
#else
diff --git a/include/asm-x86/system_64.h b/include/asm-x86/system_64.h
index 02175aa1d16..5022aecc333 100644
--- a/include/asm-x86/system_64.h
+++ b/include/asm-x86/system_64.h
@@ -141,8 +141,8 @@ static inline void write_cr8(unsigned long val)
#ifdef CONFIG_SMP
#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
#define smp_read_barrier_depends() do {} while(0)
#else
#define smp_mb() barrier()
@@ -159,12 +159,8 @@ static inline void write_cr8(unsigned long val)
*/
#define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory")
-
-#ifdef CONFIG_UNORDERED_IO
#define wmb() asm volatile("sfence" ::: "memory")
-#else
-#define wmb() asm volatile("" ::: "memory")
-#endif
+
#define read_barrier_depends() do {} while(0)
#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h
index d01c18cfcce..39a21ab030f 100644
--- a/include/asm-x86/timex.h
+++ b/include/asm-x86/timex.h
@@ -1,5 +1,18 @@
-#ifdef CONFIG_X86_32
-# include "timex_32.h"
+/* x86 architecture timex specifications */
+#ifndef _ASM_X86_TIMEX_H
+#define _ASM_X86_TIMEX_H
+
+#include <asm/processor.h>
+#include <asm/tsc.h>
+
+#ifdef CONFIG_X86_ELAN
+# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */
#else
-# include "timex_64.h"
+# define PIT_TICK_RATE 1193182 /* Underlying HZ */
+#endif
+#define CLOCK_TICK_RATE PIT_TICK_RATE
+
+extern int read_current_timer(unsigned long *timer_value);
+#define ARCH_HAS_READ_CURRENT_TIMER 1
+
#endif
diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h
deleted file mode 100644
index 3666044409f..00000000000
--- a/include/asm-x86/timex_32.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/include/asm-i386/timex.h
- *
- * i386 architecture timex specifications
- */
-#ifndef _ASMi386_TIMEX_H
-#define _ASMi386_TIMEX_H
-
-#include <asm/processor.h>
-#include <asm/tsc.h>
-
-#ifdef CONFIG_X86_ELAN
-# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
-#else
-# define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
-#endif
-
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER 1
-
-#endif
diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h
deleted file mode 100644
index 6ed21f44d30..00000000000
--- a/include/asm-x86/timex_64.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/include/asm-x86_64/timex.h
- *
- * x86-64 architecture timex specifications
- */
-#ifndef _ASMx8664_TIMEX_H
-#define _ASMx8664_TIMEX_H
-
-#include <asm/8253pit.h>
-#include <asm/msr.h>
-#include <asm/vsyscall.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/tsc.h>
-#include <linux/compiler.h>
-
-#define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER 1
-
-#define USEC_PER_TICK (USEC_PER_SEC / HZ)
-#define NSEC_PER_TICK (NSEC_PER_SEC / HZ)
-#define FSEC_PER_TICK (FSEC_PER_SEC / HZ)
-
-#define NS_SCALE 10 /* 2^10, carefully chosen */
-#define US_SCALE 32 /* 2^32, arbitralrily chosen */
-
-extern void mark_tsc_unstable(char *msg);
-extern void set_cyc2ns_scale(unsigned long khz);
-#endif
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h
index a4d806610b7..6baab30dc2c 100644
--- a/include/asm-x86/tsc.h
+++ b/include/asm-x86/tsc.h
@@ -1,13 +1,14 @@
/*
- * linux/include/asm-i386/tsc.h
- *
- * i386 TSC related functions
+ * x86 TSC related functions
*/
-#ifndef _ASM_i386_TSC_H
-#define _ASM_i386_TSC_H
+#ifndef _ASM_X86_TSC_H
+#define _ASM_X86_TSC_H
#include <asm/processor.h>
+#define NS_SCALE 10 /* 2^10, carefully chosen */
+#define US_SCALE 32 /* 2^32, arbitralrily chosen */
+
/*
* Standard way to access the cycle counter.
*/
@@ -72,4 +73,8 @@ int check_tsc_unstable(void);
extern void check_tsc_sync_source(int cpu);
extern void check_tsc_sync_target(void);
+#ifdef CONFIG_X86_64
+extern void tsc_calibrate(void);
+#endif
+
#endif
diff --git a/include/asm-x86/vsyscall.h b/include/asm-x86/vsyscall.h
index 3b8ceb4af2c..f01c49f5d10 100644
--- a/include/asm-x86/vsyscall.h
+++ b/include/asm-x86/vsyscall.h
@@ -29,9 +29,6 @@ enum vsyscall_num {
#define VGETCPU_RDTSCP 1
#define VGETCPU_LSL 2
-#define hpet_readl(a) readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-#define hpet_writel(d,a) writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-
extern int __vgetcpu_mode;
extern volatile unsigned long __jiffies;
diff --git a/include/linux/agpgart.h b/include/linux/agpgart.h
index bfb8ec791b7..09fbf7e5a6c 100644
--- a/include/linux/agpgart.h
+++ b/include/linux/agpgart.h
@@ -197,7 +197,7 @@ struct agp_file_private {
struct agp_file_private *next;
struct agp_file_private *prev;
pid_t my_pid;
- long access_flags; /* long req'd for set_bit --RR */
+ unsigned long access_flags; /* long req'd for set_bit --RR */
};
struct agp_front_data {
diff --git a/include/linux/ata.h b/include/linux/ata.h
index c043c1ccf1c..a4f373f8b79 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -230,6 +230,12 @@ enum {
SETFEATURES_SPINUP = 0x07, /* Spin-up drive */
+ SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */
+ SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */
+
+ /* SETFEATURE Sector counts for SATA features */
+ SATA_AN = 0x05, /* Asynchronous Notification */
+
/* ATAPI stuff */
ATAPI_PKT_DMA = (1 << 0),
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
@@ -281,6 +287,15 @@ enum {
SERR_PROTOCOL = (1 << 10), /* protocol violation */
SERR_INTERNAL = (1 << 11), /* host internal error */
SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */
+ SERR_PHY_INT_ERR = (1 << 17), /* PHY internal error */
+ SERR_COMM_WAKE = (1 << 18), /* Comm wake */
+ SERR_10B_8B_ERR = (1 << 19), /* 10b to 8b decode error */
+ SERR_DISPARITY = (1 << 20), /* Disparity */
+ SERR_CRC = (1 << 21), /* CRC error */
+ SERR_HANDSHAKE = (1 << 22), /* Handshake error */
+ SERR_LINK_SEQ_ERR = (1 << 23), /* Link sequence error */
+ SERR_TRANS_ST_ERROR = (1 << 24), /* Transport state trans. error */
+ SERR_UNRECOG_FIS = (1 << 25), /* Unrecognized FIS */
SERR_DEV_XCHG = (1 << 26), /* device exchanged */
/* struct ata_taskfile flags */
@@ -341,24 +356,17 @@ struct ata_taskfile {
};
#define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0)
-#define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
-#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
-#define ata_id_hpa_enabled(id) ((id)[85] & (1 << 10))
-#define ata_id_has_fua(id) ((id)[84] & (1 << 6))
-#define ata_id_has_flush(id) ((id)[83] & (1 << 12))
-#define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13))
-#define ata_id_has_lba48(id) ((id)[83] & (1 << 10))
-#define ata_id_has_hpa(id) ((id)[82] & (1 << 10))
-#define ata_id_has_wcache(id) ((id)[82] & (1 << 5))
-#define ata_id_has_pm(id) ((id)[82] & (1 << 3))
#define ata_id_has_lba(id) ((id)[49] & (1 << 9))
#define ata_id_has_dma(id) ((id)[49] & (1 << 8))
#define ata_id_has_ncq(id) ((id)[76] & (1 << 8))
#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
#define ata_id_removeable(id) ((id)[0] & (1 << 7))
-#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0))
+#define ata_id_has_dword_io(id) ((id)[48] & (1 << 0))
+#define ata_id_has_atapi_AN(id) \
+ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
+ ((id)[78] & (1 << 5)) )
#define ata_id_iordy_disable(id) ((id)[49] & (1 << 10))
-#define ata_id_has_iordy(id) ((id)[49] & (1 << 9))
+#define ata_id_has_iordy(id) ((id)[49] & (1 << 11))
#define ata_id_u32(id,n) \
(((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
#define ata_id_u64(id,n) \
@@ -369,6 +377,90 @@ struct ata_taskfile {
#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+static inline int ata_id_has_fua(const u16 *id)
+{
+ if ((id[84] & 0xC000) != 0x4000)
+ return 0;
+ return id[84] & (1 << 6);
+}
+
+static inline int ata_id_has_flush(const u16 *id)
+{
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ return id[83] & (1 << 12);
+}
+
+static inline int ata_id_has_flush_ext(const u16 *id)
+{
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ return id[83] & (1 << 13);
+}
+
+static inline int ata_id_has_lba48(const u16 *id)
+{
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ return id[83] & (1 << 10);
+}
+
+static inline int ata_id_hpa_enabled(const u16 *id)
+{
+ /* Yes children, word 83 valid bits cover word 82 data */
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ /* And 87 covers 85-87 */
+ if ((id[87] & 0xC000) != 0x4000)
+ return 0;
+ /* Check command sets enabled as well as supported */
+ if ((id[85] & ( 1 << 10)) == 0)
+ return 0;
+ return id[82] & (1 << 10);
+}
+
+static inline int ata_id_has_wcache(const u16 *id)
+{
+ /* Yes children, word 83 valid bits cover word 82 data */
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ return id[82] & (1 << 5);
+}
+
+static inline int ata_id_has_pm(const u16 *id)
+{
+ if ((id[83] & 0xC000) != 0x4000)
+ return 0;
+ return id[82] & (1 << 3);
+}
+
+static inline int ata_id_rahead_enabled(const u16 *id)
+{
+ if ((id[87] & 0xC000) != 0x4000)
+ return 0;
+ return id[85] & (1 << 6);
+}
+
+static inline int ata_id_wcache_enabled(const u16 *id)
+{
+ if ((id[87] & 0xC000) != 0x4000)
+ return 0;
+ return id[85] & (1 << 5);
+}
+
+/**
+ * ata_id_major_version - get ATA level of drive
+ * @id: Identify data
+ *
+ * Caveats:
+ * ATA-1 considers identify optional
+ * ATA-2 introduces mandatory identify
+ * ATA-3 introduces word 80 and accurate reporting
+ *
+ * The practical impact of this is that ata_id_major_version cannot
+ * reliably report on drives below ATA3.
+ */
+
static inline unsigned int ata_id_major_version(const u16 *id)
{
unsigned int mver;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 95be0ac57e7..5ed888b04b2 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -20,20 +20,6 @@
#include <asm/scatterlist.h>
-#ifdef CONFIG_LBD
-# include <asm/div64.h>
-# define sector_div(a, b) do_div(a, b)
-#else
-# define sector_div(n, b)( \
-{ \
- int _res; \
- _res = (n) % (b); \
- (n) /= (b); \
- _res; \
-} \
-)
-#endif
-
struct scsi_ioctl_command;
struct request_queue;
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 2e105a12fe2..7e11d23ac36 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -290,12 +290,7 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
#define blk_add_trace_generic(q, rq, rw, what) do { } while (0)
#define blk_add_trace_pdu_int(q, what, bio, pdu) do { } while (0)
#define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0)
-static inline int do_blk_trace_setup(struct request_queue *q,
- struct block_device *bdev,
- struct blk_user_trace_setup *buts)
-{
- return 0;
-}
+#define do_blk_trace_setup(q, bdev, buts) (-ENOTTY)
#endif /* CONFIG_BLK_DEV_IO_TRACE */
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index def5a659b8a..c33b0dc28e4 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -8,7 +8,7 @@
#ifndef _LINUX_CLOCKCHIPS_H
#define _LINUX_CLOCKCHIPS_H
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
#include <linux/clocksource.h>
#include <linux/cpumask.h>
@@ -31,6 +31,7 @@ enum clock_event_nofitiers {
CLOCK_EVT_NOTIFY_ADD,
CLOCK_EVT_NOTIFY_BROADCAST_ON,
CLOCK_EVT_NOTIFY_BROADCAST_OFF,
+ CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
CLOCK_EVT_NOTIFY_SUSPEND,
@@ -126,11 +127,14 @@ extern int clockevents_register_notifier(struct notifier_block *nb);
extern int clockevents_program_event(struct clock_event_device *dev,
ktime_t expires, ktime_t now);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void clockevents_notify(unsigned long reason, void *arg);
-
#else
+# define clockevents_notify(reason, arg) do { } while (0)
+#endif
+
+#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
-static inline void clockevents_resume_events(void) { }
#define clockevents_notify(reason, arg) do { } while (0)
#endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3ec6e7ff5fb..23932d7741a 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -32,12 +32,24 @@
* CPUFREQ NOTIFIER INTERFACE *
*********************************************************************/
-int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
-int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
-
#define CPUFREQ_TRANSITION_NOTIFIER (0)
#define CPUFREQ_POLICY_NOTIFIER (1)
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+#else /* CONFIG_CPU_FREQ */
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+{
+ return 0;
+}
+static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
+ unsigned int list)
+{
+ return 0;
+}
+#endif /* CONFIG_CPU_FREQ */
/* if (cpufreq_driver->target) exists, the ->governor decides what frequency
* within the limits is used. If (cpufreq_driver->setpolicy> exists, these
@@ -155,6 +167,9 @@ struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN];
int (*governor) (struct cpufreq_policy *policy,
unsigned int event);
+ unsigned int max_transition_latency; /* HW must be able to switch to
+ next freq faster than this value in nano secs or we
+ will fallback to performance governor */
struct list_head governor_list;
struct module *owner;
};
@@ -279,12 +294,24 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu)
*********************************************************************/
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+/*
+ Performance governor is fallback governor if any other gov failed to
+ auto load due latency restrictions
+*/
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
extern struct cpufreq_governor cpufreq_gov_performance;
-#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_performance
+#endif
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance)
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE)
extern struct cpufreq_governor cpufreq_gov_userspace;
-#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_userspace
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND)
+extern struct cpufreq_governor cpufreq_gov_ondemand;
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
+extern struct cpufreq_governor cpufreq_gov_conservative;
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative)
#endif
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 104e51e20e1..f592d6de3b9 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -49,6 +49,12 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
struct dentry *parent, u32 *value);
struct dentry *debugfs_create_u64(const char *name, mode_t mode,
struct dentry *parent, u64 *value);
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+ struct dentry *parent, u8 *value);
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+ struct dentry *parent, u16 *value);
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+ struct dentry *parent, u32 *value);
struct dentry *debugfs_create_bool(const char *name, mode_t mode,
struct dentry *parent, u32 *value);
@@ -122,6 +128,27 @@ static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
return ERR_PTR(-ENODEV);
}
+static inline struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+ struct dentry *parent,
+ u8 *value)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+ struct dentry *parent,
+ u16 *value)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+ struct dentry *parent,
+ u32 *value)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
struct dentry *parent,
u32 *value)
diff --git a/include/linux/device.h b/include/linux/device.h
index 3a38d1f70cb..2e15822fe40 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -64,12 +64,9 @@ struct bus_type {
struct bus_attribute * bus_attrs;
struct device_attribute * dev_attrs;
struct driver_attribute * drv_attrs;
- struct bus_attribute drivers_autoprobe_attr;
- struct bus_attribute drivers_probe_attr;
int (*match)(struct device * dev, struct device_driver * drv);
- int (*uevent)(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
+ int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device * dev);
int (*remove)(struct device * dev);
void (*shutdown)(struct device * dev);
@@ -189,10 +186,8 @@ struct class {
struct class_device_attribute * class_dev_attrs;
struct device_attribute * dev_attrs;
- int (*uevent)(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
- int (*dev_uevent)(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+ int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+ int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
void (*release)(struct class_device *dev);
void (*class_release)(struct class *class);
@@ -268,8 +263,7 @@ struct class_device {
struct attribute_group ** groups; /* optional groups */
void (*release)(struct class_device *dev);
- int (*uevent)(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
+ int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
char class_id[BUS_ID_SIZE]; /* unique to this class */
};
@@ -337,8 +331,7 @@ extern void class_device_destroy(struct class *cls, dev_t devt);
struct device_type {
const char *name;
struct attribute_group **groups;
- int (*uevent)(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+ int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
void (*release)(struct device *dev);
int (*suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 16421f662a7..4a6a21077ba 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
+extern struct seq_operations locks_seq_operations;
struct fasync_struct {
int magic;
@@ -1302,8 +1303,14 @@ struct file_system_type {
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
+
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
+
+ struct lock_class_key i_lock_key;
+ struct lock_class_key i_mutex_key;
+ struct lock_class_key i_mutex_dir_key;
+ struct lock_class_key i_alloc_sem_key;
};
extern int get_sb_bdev(struct file_system_type *fs_type,
@@ -1369,12 +1376,25 @@ extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size
* Candidates for mandatory locking have the setgid bit set
* but no group execute bit - an otherwise meaningless combination.
*/
-#define MANDATORY_LOCK(inode) \
- (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+
+static inline int __mandatory_lock(struct inode *ino)
+{
+ return (ino->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID;
+}
+
+/*
+ * ... and these candidates should be on MS_MANDLOCK mounted fs,
+ * otherwise these will be advisory locks
+ */
+
+static inline int mandatory_lock(struct inode *ino)
+{
+ return IS_MANDLOCK(ino) && __mandatory_lock(ino);
+}
static inline int locks_verify_locked(struct inode *inode)
{
- if (MANDATORY_LOCK(inode))
+ if (mandatory_lock(inode))
return locks_mandatory_locked(inode);
return 0;
}
@@ -1385,7 +1405,7 @@ static inline int locks_verify_truncate(struct inode *inode,
struct file *filp,
loff_t size)
{
- if (inode->i_flock && MANDATORY_LOCK(inode))
+ if (inode->i_flock && mandatory_lock(inode))
return locks_mandatory_area(
FLOCK_VERIFY_WRITE, inode, filp,
size < inode->i_size ? size : inode->i_size,
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index a44a6a078f0..c3c19f926e6 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -170,6 +170,33 @@ struct gfs2_rgrp {
};
/*
+ * quota linked list: user quotas and group quotas form two separate
+ * singly linked lists. ll_next stores uids or gids of next quotas in the
+ * linked list.
+
+Given the uid/gid, how to calculate the quota file offsets for the corresponding
+gfs2_quota structures on disk:
+
+for user quotas, given uid,
+offset = uid * sizeof(struct gfs2_quota);
+
+for group quotas, given gid,
+offset = (gid * sizeof(struct gfs2_quota)) + sizeof(struct gfs2_quota);
+
+
+ uid:0 gid:0 uid:12 gid:12 uid:17 gid:17 uid:5142 gid:5142
++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+
+| valid | valid | :: | valid | valid | :: | valid | inval | :: | inval | valid |
++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+
+next:12 next:12 next:17 next:5142 next:NULL next:NULL
+ | | | | |<-- user quota list |
+ \______|___________/ \______|___________/ group quota list -->|
+ | | |
+ \__________________/ \_______________________________________/
+
+*/
+
+/*
* quota structure
*/
@@ -177,7 +204,8 @@ struct gfs2_quota {
__be64 qu_limit;
__be64 qu_warn;
__be64 qu_value;
- __u8 qu_reserved[64];
+ __be32 qu_ll_next; /* location of next quota in list */
+ __u8 qu_reserved[60];
};
/*
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 265d17830a0..c6d3a9de563 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -8,6 +8,7 @@ struct gpio_keys_button {
int active_low;
char *desc;
int type; /* input event type (EV_KEY, EV_SW) */
+ int wakeup; /* configure the button as a wake-up source */
};
struct gpio_keys_platform_data {
diff --git a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h
index 4f6ee3b267f..bf6302f6b5f 100644
--- a/include/linux/hdlcdrv.h
+++ b/include/linux/hdlcdrv.h
@@ -200,7 +200,7 @@ struct hdlcdrv_state {
struct hdlcdrv_hdlcrx {
struct hdlcdrv_hdlcbuffer hbuf;
- long in_hdlc_rx;
+ unsigned long in_hdlc_rx;
/* 0 = sync hunt, != 0 receiving */
int rx_state;
unsigned int bitstream;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 898103b401f..edb8024d744 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -29,13 +29,6 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-
/*
* USB HID (Human Interface Device) interface class code
*/
@@ -69,6 +62,17 @@
#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02)
#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
+#define HID_MAX_DESCRIPTOR_SIZE 4096
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
/*
* We parse each description item into this structure. Short items data
* values are expanded to 32-bit signed int, long items contain a pointer
@@ -276,6 +280,7 @@ struct hid_item {
#define HID_QUIRK_HIDINPUT 0x00200000
#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000
#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000
+#define HID_QUIRK_IGNORE_HIDINPUT 0x01000000
/*
* Separate quirks for runtime report descriptor fixup
@@ -285,6 +290,7 @@ struct hid_item {
#define HID_QUIRK_RDESC_LOGITECH 0x00000002
#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004
#define HID_QUIRK_RDESC_PETALYNX 0x00000008
+#define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010
/*
* This is the global environment of the parser. This information is
@@ -309,7 +315,6 @@ struct hid_global {
* This is the local environment. It is persistent up the next main-item.
*/
-#define HID_MAX_DESCRIPTOR_SIZE 4096
#define HID_MAX_USAGES 8192
#define HID_DEFAULT_NUM_COLLECTIONS 16
@@ -403,6 +408,7 @@ struct hid_control_fifo {
#define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 2
+#define HID_CLAIMED_HIDRAW 4
#define HID_CTRL_RUNNING 1
#define HID_OUT_RUNNING 2
@@ -438,6 +444,7 @@ struct hid_device { /* device report descriptor */
struct list_head inputs; /* The list of inputs */
void *hiddev; /* The hiddev structure */
+ void *hidraw;
int minor; /* Hiddev minor number */
wait_queue_head_t wait; /* For sleeping */
@@ -458,6 +465,9 @@ struct hid_device { /* device report descriptor */
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
+
+ /* handler for raw output data, used by hidraw */
+ int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
@@ -553,4 +563,5 @@ static inline int hid_ff_init(struct hid_device *hid) { return -1; }
#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
__FILE__ , ## arg)
#endif
+#endif
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
new file mode 100644
index 00000000000..0536f299f7f
--- /dev/null
+++ b/include/linux/hidraw.h
@@ -0,0 +1,86 @@
+#ifndef _HIDRAW_H
+#define _HIDRAW_H
+
+/*
+ * Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/hid.h>
+
+struct hidraw_report_descriptor {
+ __u32 size;
+ __u8 value[HID_MAX_DESCRIPTOR_SIZE];
+};
+
+struct hidraw_devinfo {
+ __u32 bustype;
+ __s16 vendor;
+ __s16 product;
+};
+
+/* ioctl interface */
+#define HIDIOCGRDESCSIZE _IOR('H', 0x01, int)
+#define HIDIOCGRDESC _IOR('H', 0x02, struct hidraw_report_descriptor)
+#define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo)
+
+#define HIDRAW_FIRST_MINOR 0
+#define HIDRAW_MAX_DEVICES 64
+/* number of reports to buffer */
+#define HIDRAW_BUFFER_SIZE 64
+
+
+/* kernel-only API declarations */
+#ifdef __KERNEL__
+
+struct hidraw {
+ unsigned int minor;
+ int exist;
+ int open;
+ wait_queue_head_t wait;
+ struct hid_device *hid;
+ struct device *dev;
+ struct list_head list;
+};
+
+struct hidraw_report {
+ __u8 *value;
+ int len;
+};
+
+struct hidraw_list {
+ struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];
+ int head;
+ int tail;
+ struct fasync_struct *fasync;
+ struct hidraw *hidraw;
+ struct list_head node;
+ struct mutex read_mutex;
+};
+
+#ifdef CONFIG_HIDRAW
+int hidraw_init(void);
+void hidraw_exit(void);
+void hidraw_report_event(struct hid_device *, u8 *, int);
+int hidraw_connect(struct hid_device *);
+void hidraw_disconnect(struct hid_device *);
+#else
+static inline int hidraw_init(void) { return 0; }
+static inline void hidraw_exit(void) { }
+static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
+static inline int hidraw_connect(struct hid_device *hid) { return -1; }
+static inline void hidraw_disconnect(struct hid_device *hid) { }
+#endif
+
+#endif
+
+#endif
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
index 0efd994c37f..6b6ee702b00 100644
--- a/include/linux/hwmon.h
+++ b/include/linux/hwmon.h
@@ -16,9 +16,9 @@
#include <linux/device.h>
-struct class_device *hwmon_device_register(struct device *dev);
+struct device *hwmon_device_register(struct device *dev);
-void hwmon_device_unregister(struct class_device *cdev);
+void hwmon_device_unregister(struct device *dev);
/* Scale user input to sensible values */
static inline int SENSORS_LIMIT(long value, long low, long high)
diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
index 81c229a0fbc..311315b56b6 100644
--- a/include/linux/i2c-dev.h
+++ b/include/linux/i2c-dev.h
@@ -25,8 +25,31 @@
#include <linux/types.h>
#include <linux/compiler.h>
-/* Some IOCTL commands are defined in <linux/i2c.h> */
-/* Note: 10-bit addresses are NOT supported! */
+/* /dev/i2c-X ioctl commands. The ioctl's parameter is always an
+ * unsigned long, except for:
+ * - I2C_FUNCS, takes pointer to an unsigned long
+ * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data
+ * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data
+ */
+#define I2C_RETRIES 0x0701 /* number of times a device address should
+ be polled when not acknowledging */
+#define I2C_TIMEOUT 0x0702 /* set timeout in jiffies - call with int */
+
+/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
+ * are NOT supported! (due to code brokenness)
+ */
+#define I2C_SLAVE 0x0703 /* Use this slave address */
+#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it
+ is already in use by a driver! */
+#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
+
+#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */
+
+#define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */
+
+#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */
+#define I2C_SMBUS 0x0720 /* SMBus transfer */
+
/* This is the structure as used in the I2C_SMBUS ioctl call */
struct i2c_smbus_ioctl_data {
@@ -44,4 +67,8 @@ struct i2c_rdwr_ioctl_data {
#define I2C_RDRW_IOCTL_MAX_MSGS 42
+#ifdef __KERNEL__
+#define I2C_MAJOR 89 /* Device major number */
+#endif
+
#endif /* _LINUX_I2C_DEV_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 2a32f2fd940..8033e6b3327 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -35,8 +35,6 @@
#include <linux/sched.h> /* for completion */
#include <linux/mutex.h>
-extern struct bus_type i2c_bus_type;
-
/* --- General options ------------------------------------------------ */
struct i2c_msg;
@@ -292,9 +290,6 @@ struct i2c_algorithm {
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data);
- /* --- ioctl like call to set div. parameters. */
- int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
-
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
};
@@ -342,9 +337,10 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
}
/*flags for the client struct: */
-#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
-#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
- /* Must equal I2C_M_TEN below */
+#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
+#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
+ /* Must equal I2C_M_TEN below */
+#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
/* i2c adapter classes (bitmask) */
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
@@ -417,10 +413,6 @@ extern int i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int));
-/* An ioctl like call to set div. parameters of the adapter.
- */
-extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-
extern struct i2c_adapter* i2c_get_adapter(int id);
extern void i2c_put_adapter(struct i2c_adapter *adap);
@@ -444,19 +436,52 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
}
#endif /* __KERNEL__ */
-/*
- * I2C Message - used for pure i2c transaction, also from /dev interface
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ * @addr: Slave address, either seven or ten bits. When this is a ten
+ * bit address, I2C_M_TEN must be set in @flags and the adapter
+ * must support I2C_FUNC_10BIT_ADDR.
+ * @flags: I2C_M_RD is handled by all adapters. No other flags may be
+ * provided unless the adapter exported the relevant I2C_FUNC_*
+ * flags through i2c_check_functionality().
+ * @len: Number of data bytes in @buf being read from or written to the
+ * I2C slave address. For read transactions where I2C_M_RECV_LEN
+ * is set, the caller guarantees that this buffer can hold up to
+ * 32 bytes in addition to the initial length byte sent by the
+ * slave (plus, if used, the SMBus PEC); and this value will be
+ * incremented by the number of block data bytes received.
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction. It is visible to drivers in the @i2c_transfer() procedure,
+ * to userspace from i2c-dev, and to I2C adapter drivers through the
+ * @i2c_adapter.@master_xfer() method.
+ *
+ * Except when I2C "protocol mangling" is used, all I2C adapters implement
+ * the standard rules for I2C transactions. Each transaction begins with a
+ * START. That is followed by the slave address, and a bit encoding read
+ * versus write. Then follow all the data bytes, possibly including a byte
+ * with SMBus PEC. The transfer terminates with a NAK, or when all those
+ * bytes have been transferred and ACKed. If this is the last message in a
+ * group, it is followed by a STOP. Otherwise it is followed by the next
+ * @i2c_msg transaction segment, beginning with a (repeated) START.
+ *
+ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
+ * passing certain @flags may have changed those standard protocol behaviors.
+ * Those flags are only for use with broken/nonconforming slaves, and with
+ * adapters which are known to support the specific mangling options they
+ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
*/
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
-#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
-#define I2C_M_RD 0x01
-#define I2C_M_NOSTART 0x4000
-#define I2C_M_REV_DIR_ADDR 0x2000
-#define I2C_M_IGNORE_NAK 0x1000
-#define I2C_M_NO_RD_ACK 0x0800
-#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
+#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
+#define I2C_M_RD 0x0001 /* read data, from slave to master */
+#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
@@ -466,7 +491,7 @@ struct i2c_msg {
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
-#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
@@ -502,7 +527,8 @@ struct i2c_msg {
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_PROC_CALL | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
- I2C_FUNC_SMBUS_I2C_BLOCK)
+ I2C_FUNC_SMBUS_I2C_BLOCK | \
+ I2C_FUNC_SMBUS_PEC)
/*
* Data for SMBus Messages
@@ -532,38 +558,8 @@ union i2c_smbus_data {
#define I2C_SMBUS_I2C_BLOCK_DATA 8
-/* ----- commands for the ioctl like i2c_command call:
- * note that additional calls are defined in the algorithm and hw
- * dependent layers - these can be listed here, or see the
- * corresponding header files.
- */
- /* -> bit-adapter specific ioctls */
-#define I2C_RETRIES 0x0701 /* number of times a device address */
- /* should be polled when not */
- /* acknowledging */
-#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
-
-
-/* this is for i2c-dev.c */
-#define I2C_SLAVE 0x0703 /* Change slave address */
- /* Attn.: Slave address is 7 or 10 bits */
-#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
- /* Attn.: Slave address is 7 or 10 bits */
- /* This changes the address, even if it */
- /* is already taken! */
-#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
-
-#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
-#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
-#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
-
-#define I2C_SMBUS 0x0720 /* SMBus-level access */
-
-/* ----- I2C-DEV: char device interface stuff ------------------------- */
#ifdef __KERNEL__
-#define I2C_MAJOR 89 /* Device major number */
-
/* These defines are used for probing i2c client addresses */
/* The length of the option lists */
#define I2C_CLIENT_MAX_OPTS 48
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 85d448b4abe..02a27e8cbad 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -681,7 +681,7 @@ typedef struct hwif_s {
u8 straight8; /* Alan's straight 8 check */
u8 bus_state; /* power state of the IDE bus */
- u8 host_flags;
+ u16 host_flags;
u8 pio_mask;
@@ -702,10 +702,10 @@ typedef struct hwif_s {
#if 0
ide_hwif_ops_t *hwifops;
#else
- /* routine to set PIO mode for drives */
+ /* routine to program host for PIO mode */
void (*set_pio_mode)(ide_drive_t *, const u8);
- /* routine to retune DMA modes for drives */
- int (*speedproc)(ide_drive_t *, const u8);
+ /* routine to program host for DMA mode */
+ void (*set_dma_mode)(ide_drive_t *, const u8);
/* tweaks hardware to select drive */
void (*selectproc)(ide_drive_t *);
/* chipset polling based on hba specifics */
@@ -1079,16 +1079,7 @@ extern void ide_fix_driveid(struct hd_driveid *);
*/
extern void ide_fixstring(u8 *, const int, const int);
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0. All other
- * cases return 1 after doing "*startstop = ide_error()", and the
- * caller should return the updated value of "startstop" in this case.
- * "startstop" is unchanged when the function returns 0;
- * (startstop, drive, good, bad, timeout)
- */
-extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
+int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
/*
* Start a reset operation for an IDE interface.
@@ -1162,7 +1153,6 @@ extern void SELECT_MASK(ide_drive_t *, int);
extern void QUIRK_LIST(ide_drive_t *);
extern int drive_is_ready(ide_drive_t *);
-extern int wait_for_ready(ide_drive_t *, int /* timeout */);
/*
* taskfile io for disks for now...and builds request from ide_ioctl
@@ -1262,6 +1252,15 @@ enum {
IDE_HFLAG_ABUSE_FAST_DEVSEL = (1 << 5),
/* use 100-102 and 200-202 PIO values to set DMA modes */
IDE_HFLAG_ABUSE_DMA_MODES = (1 << 6),
+ /*
+ * keep DMA setting when programming PIO mode, may be used only
+ * for hosts which have separate PIO and DMA timings (ie. PMAC)
+ */
+ IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = (1 << 7),
+ /* program host for the transfer mode after programming device */
+ IDE_HFLAG_POST_SET_MODE = (1 << 8),
+ /* don't program host/device for the transfer mode ("smart" hosts) */
+ IDE_HFLAG_NO_SET_MODE = (1 << 9),
};
typedef struct ide_pci_device_s {
@@ -1278,7 +1277,7 @@ typedef struct ide_pci_device_s {
u8 bootable;
unsigned int extra;
struct ide_pci_device_s *next;
- u8 host_flags;
+ u16 host_flags;
u8 pio_mask;
u8 udma_mask;
} ide_pci_device_t;
@@ -1301,7 +1300,6 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *);
#ifdef CONFIG_BLK_DEV_IDEDMA
int __ide_dma_bad_drive(ide_drive_t *);
-int __ide_dma_good_drive(ide_drive_t *);
u8 ide_find_dma_mode(ide_drive_t *, u8);
@@ -1420,6 +1418,9 @@ unsigned int ide_pio_cycle_time(ide_drive_t *, u8);
u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8);
extern const ide_pio_timings_t ide_pio_timings[6];
+int ide_set_pio_mode(ide_drive_t *, u8);
+int ide_set_dma_mode(ide_drive_t *, u8);
+
void ide_set_pio(ide_drive_t *, u8);
static inline void ide_set_max_pio(ide_drive_t *drive)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 99e3a1a0009..58e43e56645 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -107,7 +107,7 @@ struct __fdb_entry
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
struct sk_buff *skb);
-extern int (*br_should_route_hook)(struct sk_buff **pskb);
+extern int (*br_should_route_hook)(struct sk_buff *skb);
#endif
diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h
index e1fc1d16d3c..1246d46abbc 100644
--- a/include/linux/inet_lro.h
+++ b/include/linux/inet_lro.h
@@ -52,14 +52,14 @@ struct net_lro_desc {
struct tcphdr *tcph;
struct vlan_group *vgrp;
__wsum data_csum;
- u32 tcp_rcv_tsecr;
- u32 tcp_rcv_tsval;
- u32 tcp_ack;
+ __be32 tcp_rcv_tsecr;
+ __be32 tcp_rcv_tsval;
+ __be32 tcp_ack;
u32 tcp_next_seq;
u32 skb_tot_frags_len;
u16 ip_tot_len;
u16 tcp_saw_tstamp; /* timestamps enabled */
- u16 tcp_window;
+ __be16 tcp_window;
u16 vlan_tag;
int pkt_aggr_cnt; /* counts aggregated packets */
int vlan_packet;
diff --git a/include/linux/input.h b/include/linux/input.h
index 6eb3aead7f1..f30da6fc08e 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -523,6 +523,8 @@ struct input_absinfo {
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
+#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
+#define KEY_LOGOFF 0x1b1 /* AL Logoff */
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
@@ -854,7 +856,7 @@ struct ff_rumble_effect {
* defining effect parameters
*
* This structure is sent through ioctl from the application to the driver.
- * To create a new effect aplication should set its @id to -1; the kernel
+ * To create a new effect application should set its @id to -1; the kernel
* will return assigned @id which can later be used to update or delete
* this effect.
*
@@ -934,9 +936,82 @@ struct ff_effect {
#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
#define LONG(x) ((x)/BITS_PER_LONG)
+/**
+ * struct input_dev - represents an input device
+ * @name: name of the device
+ * @phys: physical path to the device in the system hierarchy
+ * @uniq: unique identification code for the device (if device has it)
+ * @id: id of the device (struct input_id)
+ * @evbit: bitmap of types of events supported by the device (EV_KEY,
+ * EV_REL, etc.)
+ * @keybit: bitmap of keys/buttons this device has
+ * @relbit: bitmap of relative axes for the device
+ * @absbit: bitmap of absolute axes for the device
+ * @mscbit: bitmap of miscellaneous events supported by the device
+ * @ledbit: bitmap of leds present on the device
+ * @sndbit: bitmap of sound effects supported by the device
+ * @ffbit: bitmap of force feedback effects supported by the device
+ * @swbit: bitmap of switches present on the device
+ * @keycodemax: size of keycode table
+ * @keycodesize: size of elements in keycode table
+ * @keycode: map of scancodes to keycodes for this device
+ * @setkeycode: optional method to alter current keymap, used to implement
+ * sparse keymaps. If not supplied default mechanism will be used
+ * @getkeycode: optional method to retrieve current keymap. If not supplied
+ * default mechanism will be used
+ * @ff: force feedback structure associated with the device if device
+ * supports force feedback effects
+ * @repeat_key: stores key code of the last key pressed; used to implement
+ * software autorepeat
+ * @timer: timer for software autorepeat
+ * @sync: set to 1 when there were no new events since last EV_SYNC
+ * @abs: current values for reports from absolute axes
+ * @rep: current values for autorepeat parameters (delay, rate)
+ * @key: reflects current state of device's keys/buttons
+ * @led: reflects current state of device's LEDs
+ * @snd: reflects current state of sound effects
+ * @sw: reflects current state of device's switches
+ * @absmax: maximum values for events coming from absolute axes
+ * @absmin: minimum values for events coming from absolute axes
+ * @absfuzz: describes noisiness for axes
+ * @absflat: size of the center flat position (used by joydev)
+ * @open: this method is called when the very first user calls
+ * input_open_device(). The driver must prepare the device
+ * to start generating events (start polling thread,
+ * request an IRQ, submit URB, etc.)
+ * @close: this method is called when the very last user calls
+ * input_close_device().
+ * @flush: purges the device. Most commonly used to get rid of force
+ * feedback effects loaded into the device when disconnecting
+ * from it
+ * @event: event handler for events sent _to_ the device, like EV_LED
+ * or EV_SND. The device is expected to carry out the requested
+ * action (turn on a LED, play sound, etc.) The call is protected
+ * by @event_lock and must not sleep
+ * @grab: input handle that currently has the device grabbed (via
+ * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
+ * recipient for all input events coming from the device
+ * @event_lock: this spinlock is is taken when input core receives
+ * and processes a new event for the device (in input_event()).
+ * Code that accesses and/or modifies parameters of a device
+ * (such as keymap or absmin, absmax, absfuzz, etc.) after device
+ * has been registered with input core must take this lock.
+ * @mutex: serializes calls to open(), close() and flush() methods
+ * @users: stores number of users (input handlers) that opened this
+ * device. It is used by input_open_device() and input_close_device()
+ * to make sure that dev->open() is only called when the first
+ * user opens device and dev->close() is called when the very
+ * last user closes the device
+ * @going_away: marks devices that are in a middle of unregistering and
+ * causes input_open_device*() fail with -ENODEV.
+ * @dev: driver model's view of this device
+ * @h_list: list of input handles associated with the device. When
+ * accessing the list dev->mutex must be held
+ * @node: used to place the device onto input_dev_list
+ */
struct input_dev {
- void *private;
+ void *private; /* do not use */
const char *name;
const char *phys;
@@ -964,8 +1039,6 @@ struct input_dev {
unsigned int repeat_key;
struct timer_list timer;
- int state;
-
int sync;
int abs[ABS_MAX + 1];
@@ -988,8 +1061,11 @@ struct input_dev {
struct input_handle *grab;
- struct mutex mutex; /* serializes open and close operations */
+ spinlock_t event_lock;
+ struct mutex mutex;
+
unsigned int users;
+ int going_away;
struct device dev;
union { /* temporarily so while we switching to struct device */
@@ -1055,7 +1131,9 @@ struct input_handle;
/**
* struct input_handler - implements one of interfaces for input devices
* @private: driver-specific data
- * @event: event handler
+ * @event: event handler. This method is being called by input core with
+ * interrupts disabled and dev->event_lock spinlock held and so
+ * it may not sleep
* @connect: called when attaching a handler to an input device
* @disconnect: disconnects a handler from input device
* @start: starts handler for given handle. This function is called by
@@ -1067,10 +1145,18 @@ struct input_handle;
* @name: name of the handler, to be shown in /proc/bus/input/handlers
* @id_table: pointer to a table of input_device_ids this driver can
* handle
- * @blacklist: prointer to a table of input_device_ids this driver should
+ * @blacklist: pointer to a table of input_device_ids this driver should
* ignore even if they match @id_table
* @h_list: list of input handles associated with the handler
* @node: for placing the driver onto input_handler_list
+ *
+ * Input handlers attach to input devices and create input handles. There
+ * are likely several handlers attached to any given input device at the
+ * same time. All of them will get their copy of input event generated by
+ * the device.
+ *
+ * Note that input core serializes calls to connect() and disconnect()
+ * methods.
*/
struct input_handler {
@@ -1092,6 +1178,18 @@ struct input_handler {
struct list_head node;
};
+/**
+ * struct input_handle - links input device with an input handler
+ * @private: handler-specific data
+ * @open: counter showing whether the handle is 'open', i.e. should deliver
+ * events from its device
+ * @name: name given to the handle by handler that created it
+ * @dev: input device the handle is attached to
+ * @handler: handler that works with the device through this handle
+ * @d_node: used to put the handle on device's list of attached handles
+ * @h_node: used to put the handle on handler's list of handles from which
+ * it gets events
+ */
struct input_handle {
void *private;
@@ -1134,10 +1232,10 @@ static inline void input_set_drvdata(struct input_dev *dev, void *data)
dev->private = data;
}
-int input_register_device(struct input_dev *);
+int __must_check input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
-int input_register_handler(struct input_handler *);
+int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
int input_register_handle(struct input_handle *);
@@ -1214,7 +1312,7 @@ extern struct class input_class;
* @max_effects: maximum number of effects supported by device
* @effects: pointer to an array of effects currently loaded into device
* @effect_owners: array of effect owners; when file handle owning
- * an effect gets closed the effcet is automatically erased
+ * an effect gets closed the effect is automatically erased
*
* Every force-feedback device must implement upload() and playback()
* methods; erase() is optional. set_gain() and set_autocenter() need
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index ad09506554a..d5dda4b643a 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -286,7 +286,6 @@ typedef struct {
/* Local interface-data */
typedef struct isdn_net_local_s {
ulong magic;
- char name[10]; /* Name of device */
struct net_device_stats stats; /* Ethernet Statistics */
int isdn_device; /* Index to isdn-device */
int isdn_channel; /* Index to isdn-channel */
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 45273755126..700a93b7918 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -30,6 +30,7 @@
#include <linux/bit_spinlock.h>
#include <linux/mutex.h>
#include <linux/timer.h>
+#include <linux/lockdep.h>
#include <asm/semaphore.h>
#endif
@@ -396,6 +397,10 @@ struct handle_s
unsigned int h_sync: 1; /* sync-on-close */
unsigned int h_jdata: 1; /* force data journaling */
unsigned int h_aborted: 1; /* fatal error on handle */
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lockdep_map h_lockdep_map;
+#endif
};
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index 840631fa5ff..6b563cae23d 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -46,6 +46,7 @@
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
+#define JFFS2_COMPR_LZO 0x07
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index c080f61fb02..e757a74b9d1 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -36,8 +36,6 @@
/* LATCH is used in the interval timer and ftape setup. */
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
-#define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ)
-
/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
* improve accuracy by shifting LSH bits, hence calculating:
* (NOM << LSH) / DEN
@@ -53,13 +51,9 @@
/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
-#define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8))
-
/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
-#define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8))
-
/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
@@ -115,6 +109,10 @@ static inline u64 get_jiffies_64(void)
((long)(a) - (long)(b) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a)
+#define time_in_range(a,b,c) \
+ (time_after_eq(a,b) && \
+ time_before_eq(a,c))
+
/* Same as above, but does so with platform independent 64bit types.
* These must be used when utilizing jiffies_64 (i.e. return value of
* get_jiffies_64() */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 47160fe378c..d9725a28a26 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -42,6 +42,20 @@ extern const char linux_proc_banner[];
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#ifdef CONFIG_LBD
+# include <asm/div64.h>
+# define sector_div(a, b) do_div(a, b)
+#else
+# define sector_div(n, b)( \
+{ \
+ int _res; \
+ _res = (n) % (b); \
+ (n) /= (b); \
+ _res; \
+} \
+)
+#endif
+
/**
* upper_32_bits - return bits 32-63 of a number
* @n: the number we're accessing
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 43e895f1cab..12bf44f083f 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -23,6 +23,7 @@ struct cpu_usage_stat {
cputime64_t idle;
cputime64_t iowait;
cputime64_t steal;
+ cputime64_t guest;
};
struct kernel_stat {
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 7ddbc30aa8e..33b5c2e325b 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -416,6 +416,7 @@ extern unsigned short plain_map[NR_KEYS];
#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
+#define K_CAPSSHIFTLOCK K(KT_LOCK,KG_CAPSSHIFT)
#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
@@ -425,8 +426,9 @@ extern unsigned short plain_map[NR_KEYS];
#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
+#define K_CAPSSHIFT_SLOCK K(KT_SLOCK,KG_CAPSSHIFT)
-#define NR_LOCK 8
+#define NR_LOCK 9
#define K_BRL_BLANK K(KT_BRL, 0)
#define K_BRL_DOT1 K(KT_BRL, 1)
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 949706c3362..4a0d27f475d 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -1,8 +1,10 @@
/*
* kobject.h - generic kernel object infrastructure.
*
- * Copyright (c) 2002-2003 Patrick Mochel
- * Copyright (c) 2002-2003 Open Source Development Labs
+ * Copyright (c) 2002-2003 Patrick Mochel
+ * Copyright (c) 2002-2003 Open Source Development Labs
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
*
* This file is released under the GPLv2.
*
@@ -29,6 +31,8 @@
#define KOBJ_NAME_LEN 20
#define UEVENT_HELPER_PATH_LEN 256
+#define UEVENT_NUM_ENVP 32 /* number of env pointers */
+#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
/* path to the userspace helper executed on an event */
extern char uevent_helper[];
@@ -56,19 +60,14 @@ enum kobject_action {
KOBJ_MAX
};
-/* The list of strings defining the valid kobject actions as specified above */
-extern const char *kobject_actions[];
-
struct kobject {
const char * k_name;
- char name[KOBJ_NAME_LEN];
struct kref kref;
struct list_head entry;
struct kobject * parent;
struct kset * kset;
struct kobj_type * ktype;
struct sysfs_dirent * sd;
- wait_queue_head_t poll;
};
extern int kobject_set_name(struct kobject *, const char *, ...)
@@ -83,14 +82,9 @@ extern void kobject_init(struct kobject *);
extern void kobject_cleanup(struct kobject *);
extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
- struct sysfs_dirent *shadow_parent);
extern void kobject_del(struct kobject *);
extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
- struct sysfs_dirent *new_parent,
- const char *new_name);
extern int __must_check kobject_move(struct kobject *, struct kobject *);
extern int __must_check kobject_register(struct kobject *);
@@ -111,36 +105,44 @@ struct kobj_type {
struct attribute ** default_attrs;
};
+struct kobj_uevent_env {
+ char *envp[UEVENT_NUM_ENVP];
+ int envp_idx;
+ char buf[UEVENT_BUFFER_SIZE];
+ int buflen;
+};
+
struct kset_uevent_ops {
int (*filter)(struct kset *kset, struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj);
- int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size);
+ int (*uevent)(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env);
};
-/*
- * struct kset - a set of kobjects of a specific type, belonging
- * to a specific subsystem.
- *
- * All kobjects of a kset should be embedded in an identical
- * type. This type may have a descriptor, which the kset points
- * to. This allows there to exist sets of objects of the same
- * type in different subsystems.
+/**
+ * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
*
- * A subsystem does not have to be a list of only one type
- * of object; multiple ksets can belong to one subsystem. All
- * ksets of a subsystem share the subsystem's lock.
+ * A kset defines a group of kobjects. They can be individually
+ * different "types" but overall these kobjects all want to be grouped
+ * together and operated on in the same manner. ksets are used to
+ * define the attribute callbacks and other common events that happen to
+ * a kobject.
*
- * Each kset can support specific event variables; it can
- * supress the event generation or add subsystem specific
- * variables carried with the event.
+ * @ktype: the struct kobj_type for this specific kset
+ * @list: the list of all kobjects for this kset
+ * @list_lock: a lock for iterating over the kobjects
+ * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
+ * @uevent_ops: the set of uevent operations for this kset. These are
+ * called whenever a kobject has something happen to it so that the kset
+ * can add new environment variables, or filter out the uevents if so
+ * desired.
*/
struct kset {
- struct kobj_type * ktype;
+ struct kobj_type *ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
- struct kset_uevent_ops * uevent_ops;
+ struct kset_uevent_ops *uevent_ops;
};
@@ -179,18 +181,18 @@ extern struct kobject * kset_find_obj(struct kset *, const char *);
* Use this when initializing an embedded kset with no other
* fields to initialize.
*/
-#define set_kset_name(str) .kset = { .kobj = { .name = str } }
+#define set_kset_name(str) .kset = { .kobj = { .k_name = str } }
#define decl_subsys(_name,_type,_uevent_ops) \
struct kset _name##_subsys = { \
- .kobj = { .name = __stringify(_name) }, \
+ .kobj = { .k_name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
}
#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
struct kset _varname##_subsys = { \
- .kobj = { .name = __stringify(_name) }, \
+ .kobj = { .k_name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
}
@@ -218,49 +220,9 @@ extern struct kset hypervisor_subsys;
#define kobj_set_kset_s(obj,subsys) \
(obj)->kobj.kset = &(subsys)
-/**
- * kset_set_kset_s(obj,subsys) - set kset for embedded kset.
- * @obj: ptr to some object type.
- * @subsys: a subsystem object (not a ptr).
- *
- * Can be used for any object type with an embedded ->kset.
- * Sets the kset of @obj's embedded kobject (via its embedded
- * kset) to @subsys.kset. This makes @obj a member of that
- * kset.
- */
-
-#define kset_set_kset_s(obj,subsys) \
- (obj)->kset.kobj.kset = &(subsys)
-
-/**
- * subsys_set_kset(obj,subsys) - set kset for subsystem
- * @obj: ptr to some object type.
- * @_subsys: a subsystem object (not a ptr).
- *
- * Can be used for any object type with an embedded ->subsys.
- * Sets the kset of @obj's kobject to @subsys.kset. This makes
- * the object a member of that kset.
- */
-
-#define subsys_set_kset(obj,_subsys) \
- (obj)->subsys.kobj.kset = &(_subsys)
-
-extern void subsystem_init(struct kset *);
extern int __must_check subsystem_register(struct kset *);
extern void subsystem_unregister(struct kset *);
-static inline struct kset *subsys_get(struct kset *s)
-{
- if (s)
- return kset_get(s);
- return NULL;
-}
-
-static inline void subsys_put(struct kset *s)
-{
- kset_put(s);
-}
-
struct subsys_attribute {
struct attribute attr;
ssize_t (*show)(struct kset *, char *);
@@ -275,10 +237,11 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp[]);
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
- const char *format, ...)
- __attribute__((format (printf, 7, 8)));
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
+ __attribute__((format (printf, 2, 3)));
+
+int kobject_action_type(const char *buf, size_t count,
+ enum kobject_action *type);
#else
static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{ return 0; }
@@ -287,10 +250,12 @@ static inline int kobject_uevent_env(struct kobject *kobj,
char *envp[])
{ return 0; }
-static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
- const char *format, ...)
+static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
{ return 0; }
+
+static inline int kobject_action_type(const char *buf, size_t count,
+ enum kobject_action *type)
+{ return -EINVAL; }
#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index e6edca81ab8..057a7f34ee3 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -4,8 +4,7 @@
/*
* Userspace interface for /dev/kvm - kernel based virtual machine
*
- * Note: this interface is considered experimental and may change without
- * notice.
+ * Note: you must update KVM_API_VERSION if you change this interface.
*/
#include <asm/types.h>
@@ -13,14 +12,8 @@
#define KVM_API_VERSION 12
-/*
- * Architectural interrupt line count, and the size of the bitmap needed
- * to hold them.
- */
+/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
-#define KVM_IRQ_BITMAP_SIZE_BYTES ((KVM_NR_INTERRUPTS + 7) / 8)
-#define KVM_IRQ_BITMAP_SIZE(type) (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type))
-
/* for KVM_CREATE_MEMORY_REGION */
struct kvm_memory_region {
@@ -41,20 +34,89 @@ struct kvm_memory_alias {
__u64 target_phys_addr;
};
-enum kvm_exit_reason {
- KVM_EXIT_UNKNOWN = 0,
- KVM_EXIT_EXCEPTION = 1,
- KVM_EXIT_IO = 2,
- KVM_EXIT_HYPERCALL = 3,
- KVM_EXIT_DEBUG = 4,
- KVM_EXIT_HLT = 5,
- KVM_EXIT_MMIO = 6,
- KVM_EXIT_IRQ_WINDOW_OPEN = 7,
- KVM_EXIT_SHUTDOWN = 8,
- KVM_EXIT_FAIL_ENTRY = 9,
- KVM_EXIT_INTR = 10,
+/* for KVM_IRQ_LINE */
+struct kvm_irq_level {
+ /*
+ * ACPI gsi notion of irq.
+ * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
+ * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+ */
+ __u32 irq;
+ __u32 level;
+};
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+ __u8 last_irr; /* edge detection */
+ __u8 irr; /* interrupt request register */
+ __u8 imr; /* interrupt mask register */
+ __u8 isr; /* interrupt service register */
+ __u8 priority_add; /* highest irq priority */
+ __u8 irq_base;
+ __u8 read_reg_select;
+ __u8 poll;
+ __u8 special_mask;
+ __u8 init_state;
+ __u8 auto_eoi;
+ __u8 rotate_on_auto_eoi;
+ __u8 special_fully_nested_mode;
+ __u8 init4; /* true if 4 byte init */
+ __u8 elcr; /* PIIX edge/trigger selection */
+ __u8 elcr_mask;
+};
+
+#define KVM_IOAPIC_NUM_PINS 24
+struct kvm_ioapic_state {
+ __u64 base_address;
+ __u32 ioregsel;
+ __u32 id;
+ __u32 irr;
+ __u32 pad;
+ union {
+ __u64 bits;
+ struct {
+ __u8 vector;
+ __u8 delivery_mode:3;
+ __u8 dest_mode:1;
+ __u8 delivery_status:1;
+ __u8 polarity:1;
+ __u8 remote_irr:1;
+ __u8 trig_mode:1;
+ __u8 mask:1;
+ __u8 reserve:7;
+ __u8 reserved[4];
+ __u8 dest_id;
+ } fields;
+ } redirtbl[KVM_IOAPIC_NUM_PINS];
};
+#define KVM_IRQCHIP_PIC_MASTER 0
+#define KVM_IRQCHIP_PIC_SLAVE 1
+#define KVM_IRQCHIP_IOAPIC 2
+
+struct kvm_irqchip {
+ __u32 chip_id;
+ __u32 pad;
+ union {
+ char dummy[512]; /* reserving space */
+ struct kvm_pic_state pic;
+ struct kvm_ioapic_state ioapic;
+ } chip;
+};
+
+#define KVM_EXIT_UNKNOWN 0
+#define KVM_EXIT_EXCEPTION 1
+#define KVM_EXIT_IO 2
+#define KVM_EXIT_HYPERCALL 3
+#define KVM_EXIT_DEBUG 4
+#define KVM_EXIT_HLT 5
+#define KVM_EXIT_MMIO 6
+#define KVM_EXIT_IRQ_WINDOW_OPEN 7
+#define KVM_EXIT_SHUTDOWN 8
+#define KVM_EXIT_FAIL_ENTRY 9
+#define KVM_EXIT_INTR 10
+#define KVM_EXIT_SET_TPR 11
+
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
@@ -106,11 +168,14 @@ struct kvm_run {
} mmio;
/* KVM_EXIT_HYPERCALL */
struct {
+ __u64 nr;
__u64 args[6];
__u64 ret;
__u32 longmode;
__u32 pad;
} hypercall;
+ /* Fix the size of the union. */
+ char padding[256];
};
};
@@ -139,6 +204,12 @@ struct kvm_fpu {
__u32 pad2;
};
+/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+ char regs[KVM_APIC_REG_SIZE];
+};
+
struct kvm_segment {
__u64 base;
__u32 limit;
@@ -164,7 +235,7 @@ struct kvm_sregs {
__u64 cr0, cr2, cr3, cr4, cr8;
__u64 efer;
__u64 apic_base;
- __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)];
+ __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};
struct kvm_msr_entry {
@@ -272,6 +343,12 @@ struct kvm_signal_mask {
#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
/*
+ * Extension capability list.
+ */
+#define KVM_CAP_IRQCHIP 0
+#define KVM_CAP_HLT 1
+
+/*
* ioctls for VM fds
*/
#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region)
@@ -282,6 +359,11 @@ struct kvm_signal_mask {
#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
+/* Device model IOC */
+#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
+#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
/*
* ioctls for vcpu fds
@@ -300,5 +382,7 @@ struct kvm_signal_mask {
#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
+#define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state)
+#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state)
#endif
diff --git a/include/linux/libata.h b/include/linux/libata.h
index a67bb9075e9..229a9ff9f92 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -28,7 +28,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <asm/scatterlist.h>
#include <linux/io.h>
@@ -107,12 +106,6 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits)
/* defines only for the constants which don't work well as enums */
#define ATA_TAG_POISON 0xfafbfcfdU
-/* move to PCI layer? */
-static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
-{
- return &pdev->dev;
-}
-
enum {
/* various global constants */
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
@@ -139,11 +132,12 @@ enum {
ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
- ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
+ ATA_DFLAG_AN = (1 << 7), /* AN configured */
+ ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
- ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
- ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */
- ATA_DFLAG_SPUNDOWN = (1 << 10), /* XXX: for spindown_compat */
+ ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
+ ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */
+ ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16),
@@ -154,7 +148,22 @@ enum {
ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */
ATA_DEV_ATAPI = 3, /* ATAPI device */
ATA_DEV_ATAPI_UNSUP = 4, /* ATAPI device (unsupported) */
- ATA_DEV_NONE = 5, /* no device */
+ ATA_DEV_PMP = 5, /* SATA port multiplier */
+ ATA_DEV_PMP_UNSUP = 6, /* SATA port multiplier (unsupported) */
+ ATA_DEV_SEMB = 7, /* SEMB */
+ ATA_DEV_SEMB_UNSUP = 8, /* SEMB (unsupported) */
+ ATA_DEV_NONE = 9, /* no device */
+
+ /* struct ata_link flags */
+ ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */
+ ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H
+ * Register FIS clearing BSY */
+ ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */
+ ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */
+ ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */
+ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
+ ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */
+ ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */
/* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
@@ -170,13 +179,12 @@ enum {
ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD
* doesn't handle PIO interrupts */
ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */
- ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
- ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
- * Register FIS clearing BSY */
ATA_FLAG_DEBUGMSG = (1 << 13),
ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
+ ATA_FLAG_AN = (1 << 18), /* controller supports AN */
+ ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
@@ -195,6 +203,7 @@ enum {
ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */
+ ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
@@ -207,6 +216,7 @@ enum {
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
+ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
@@ -263,6 +273,10 @@ enum {
/* ering size */
ATA_ERING_SIZE = 32,
+ /* return values for ->qc_defer */
+ ATA_DEFER_LINK = 1,
+ ATA_DEFER_PORT = 2,
+
/* desc_len for ata_eh_info and context */
ATA_EH_DESC_LEN = 80,
@@ -270,6 +284,7 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_ENABLE_LINK = (1 << 3),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
@@ -289,12 +304,16 @@ enum {
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 */
- ATA_EH_MAX_REPEAT = 5,
+ /* max tries if error condition is still set after ->error_handler */
+ ATA_EH_MAX_TRIES = 5,
/* how hard are we gonna try to probe/recover devices */
ATA_PROBE_MAX_TRIES = 3,
ATA_EH_DEV_TRIES = 3,
+ ATA_EH_PMP_TRIES = 5,
+ ATA_EH_PMP_LINK_TRIES = 3,
+
+ SATA_PMP_SCR_TIMEOUT = 250,
/* Horkage types. May be set by libata or controller on drives
(some horkage may be drive/controller pair dependant */
@@ -304,6 +323,14 @@ enum {
ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */
ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */
ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
+ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */
+ ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */
+
+ /* DMA mask for user DMA control: User visible values; DO NOT
+ renumber */
+ ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */
+ ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */
+ ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */
};
enum hsm_task_states {
@@ -333,14 +360,15 @@ enum ata_completion_errors {
struct scsi_device;
struct ata_port_operations;
struct ata_port;
+struct ata_link;
struct ata_queued_cmd;
/* typedefs */
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline);
-typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes,
+typedef int (*ata_prereset_fn_t)(struct ata_link *link, unsigned long deadline);
+typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes,
unsigned long deadline);
-typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
struct ata_ioports {
void __iomem *cmd_addr;
@@ -363,8 +391,6 @@ struct ata_ioports {
struct ata_host {
spinlock_t lock;
struct device *dev;
- unsigned long irq;
- unsigned long irq2;
void __iomem * const *iomap;
unsigned int n_ports;
void *private_data;
@@ -436,7 +462,7 @@ struct ata_ering {
};
struct ata_device {
- struct ata_port *ap;
+ struct ata_link *link;
unsigned int devno; /* 0 or 1 */
unsigned long flags; /* ATA_DFLAG_xxx */
unsigned int horkage; /* List of broken features */
@@ -447,7 +473,12 @@ struct ata_device {
/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */
- u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+
+ union {
+ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
+ };
+
u8 pio_mode;
u8 dma_mode;
u8 xfer_mode;
@@ -510,6 +541,27 @@ struct ata_acpi_gtm {
u32 flags;
} __packed;
+struct ata_link {
+ struct ata_port *ap;
+ int pmp; /* port multiplier port # */
+
+ unsigned int active_tag; /* active tag on this link */
+ u32 sactive; /* active NCQ commands */
+
+ unsigned int flags; /* ATA_LFLAG_xxx */
+
+ unsigned int hw_sata_spd_limit;
+ unsigned int sata_spd_limit;
+ unsigned int sata_spd; /* current SATA PHY speed */
+
+ /* record runtime error info, protected by host_set lock */
+ struct ata_eh_info eh_info;
+ /* EH context */
+ struct ata_eh_context eh_context;
+
+ struct ata_device device[ATA_MAX_DEVICES];
+};
+
struct ata_port {
struct Scsi_Host *scsi_host; /* our co-allocated scsi host */
const struct ata_port_operations *ops;
@@ -533,23 +585,17 @@ struct ata_port {
unsigned int mwdma_mask;
unsigned int udma_mask;
unsigned int cbl; /* cable type; ATA_CBL_xxx */
- unsigned int hw_sata_spd_limit;
- unsigned int sata_spd_limit; /* SATA PHY speed limit */
- unsigned int sata_spd; /* current SATA PHY speed */
-
- /* record runtime error info, protected by host lock */
- struct ata_eh_info eh_info;
- /* EH context owned by EH */
- struct ata_eh_context eh_context;
-
- struct ata_device device[ATA_MAX_DEVICES];
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
unsigned long qc_allocated;
unsigned int qc_active;
+ int nr_active_links; /* #links with active qcs */
+
+ struct ata_link link; /* host default link */
- unsigned int active_tag;
- u32 sactive;
+ int nr_pmp_links; /* nr of available PMP links */
+ struct ata_link *pmp_link; /* array of PMP links */
+ struct ata_link *excl_link; /* for PMP qc exclusion */
struct ata_port_stats stats;
struct ata_host *host;
@@ -565,6 +611,7 @@ struct ata_port {
u32 msg_enable;
struct list_head eh_done_q;
wait_queue_head_t eh_wait_q;
+ int eh_tries;
pm_message_t pm_mesg;
int *pm_result;
@@ -582,8 +629,6 @@ struct ata_port {
};
struct ata_port_operations {
- void (*port_disable) (struct ata_port *);
-
void (*dev_config) (struct ata_device *);
void (*set_piomode) (struct ata_port *, struct ata_device *);
@@ -599,7 +644,7 @@ struct ata_port_operations {
void (*dev_select)(struct ata_port *ap, unsigned int device);
void (*phy_reset) (struct ata_port *ap); /* obsolete */
- int (*set_mode) (struct ata_port *ap, struct ata_device **r_failed_dev);
+ int (*set_mode) (struct ata_link *link, struct ata_device **r_failed_dev);
int (*cable_detect) (struct ata_port *ap);
@@ -610,9 +655,14 @@ struct ata_port_operations {
void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+ int (*qc_defer) (struct ata_queued_cmd *qc);
void (*qc_prep) (struct ata_queued_cmd *qc);
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
+ /* port multiplier */
+ void (*pmp_attach) (struct ata_port *ap);
+ void (*pmp_detach) (struct ata_port *ap);
+
/* Error handlers. ->error_handler overrides ->eng_timeout and
* indicates that new-style EH is in place.
*/
@@ -626,7 +676,6 @@ struct ata_port_operations {
irq_handler_t irq_handler;
void (*irq_clear) (struct ata_port *);
u8 (*irq_on) (struct ata_port *);
- u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -646,6 +695,7 @@ struct ata_port_operations {
struct ata_port_info {
struct scsi_host_template *sht;
unsigned long flags;
+ unsigned long link_flags;
unsigned long pio_mask;
unsigned long mwdma_mask;
unsigned long udma_mask;
@@ -689,38 +739,27 @@ 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 sata_print_link_status(struct ata_link *link);
extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
extern void sata_phy_reset(struct ata_port *ap);
extern void ata_bus_reset(struct ata_port *ap);
-extern int sata_set_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param,
- unsigned long deadline);
-extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param,
- unsigned long deadline);
-extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline);
-extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+extern int sata_set_spd(struct ata_link *link);
+extern int sata_link_debounce(struct ata_link *link,
+ const unsigned long *params, unsigned long deadline);
+extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline);
+extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int ata_std_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline);
-extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
- unsigned long deadline);
-extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+extern int sata_link_hardreset(struct ata_link *link,
+ const unsigned long *timing, unsigned long deadline);
+extern int sata_std_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
-extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
extern void ata_port_disable(struct ata_port *);
extern void ata_std_ports(struct ata_ioports *ioaddr);
-#ifdef CONFIG_PCI
-extern int ata_pci_init_one (struct pci_dev *pdev,
- const struct ata_port_info * const * ppi);
-extern void ata_pci_remove_one (struct pci_dev *pdev);
-#ifdef CONFIG_PM
-extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
-extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev);
-extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
-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 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);
@@ -746,12 +785,12 @@ extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
struct ata_port *ap);
extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
-extern int sata_scr_valid(struct ata_port *ap);
-extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
-extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
-extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
-extern int ata_port_online(struct ata_port *ap);
-extern int ata_port_offline(struct ata_port *ap);
+extern int sata_scr_valid(struct ata_link *link);
+extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
+extern int ata_link_online(struct ata_link *link);
+extern int ata_link_offline(struct ata_link *link);
#ifdef CONFIG_PM
extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
extern void ata_host_resume(struct ata_host *host);
@@ -765,7 +804,8 @@ extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn,
extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
unsigned long interval_msec,
unsigned long timeout_msec);
-extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
+extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+ u8 *r_err);
/*
* Default driver ops implementations
@@ -787,6 +827,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
+extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc);
extern void ata_qc_prep(struct ata_queued_cmd *qc);
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
@@ -830,11 +871,8 @@ 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 int ata_do_set_mode(struct ata_link *link, 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);
@@ -869,8 +907,29 @@ enum {
ATA_TIMING_CYCLE | ATA_TIMING_UDMA,
};
+/* libata-acpi.c */
+#ifdef CONFIG_ATA_ACPI
+extern int ata_acpi_cbl_80wire(struct ata_port *ap);
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm);
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *stm);
+#else
+static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; }
+#endif
#ifdef CONFIG_PCI
+struct pci_dev;
+
+extern int ata_pci_init_one (struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi);
+extern void ata_pci_remove_one (struct pci_dev *pdev);
+#ifdef CONFIG_PM
+extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
+extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev);
+extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+extern int ata_pci_device_resume(struct pci_dev *pdev);
+#endif
+extern int ata_pci_clear_simplex(struct pci_dev *pdev);
+
struct pci_bits {
unsigned int reg; /* PCI config register to read */
unsigned int width; /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */
@@ -888,13 +947,29 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
#endif /* CONFIG_PCI */
/*
+ * PMP
+ */
+extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc);
+extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class);
+extern void sata_pmp_do_eh(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset);
+
+/*
* EH
*/
extern void ata_eng_timeout(struct ata_port *ap);
extern void ata_port_schedule_eh(struct ata_port *ap);
+extern int ata_link_abort(struct ata_link *link);
extern int ata_port_abort(struct ata_port *ap);
extern int ata_port_freeze(struct ata_port *ap);
+extern int sata_async_notification(struct ata_port *ap);
extern void ata_eh_freeze_port(struct ata_port *ap);
extern void ata_eh_thaw_port(struct ata_port *ap);
@@ -912,14 +987,25 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
#define ata_port_printk(ap, lv, fmt, args...) \
printk(lv"ata%u: "fmt, (ap)->print_id , ##args)
+#define ata_link_printk(link, lv, fmt, args...) do { \
+ if ((link)->ap->nr_pmp_links) \
+ printk(lv"ata%u.%02u: "fmt, (link)->ap->print_id, \
+ (link)->pmp , ##args); \
+ else \
+ printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args); \
+ } while(0)
+
#define ata_dev_printk(dev, lv, fmt, args...) \
- printk(lv"ata%u.%02u: "fmt, (dev)->ap->print_id, (dev)->devno , ##args)
+ printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, \
+ (dev)->link->pmp + (dev)->devno , ##args)
/*
* ata_eh_info helpers
*/
-extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
-extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
@@ -933,10 +1019,21 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
ata_ehi_schedule_probe(ehi);
ehi->flags |= ATA_EHI_HOTPLUGGED;
+ ehi->action |= ATA_EH_ENABLE_LINK;
ehi->err_mask |= AC_ERR_ATA_BUS;
}
/*
+ * port description helpers
+ */
+extern void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#ifdef CONFIG_PCI
+extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+ const char *name);
+#endif
+
+/*
* qc helpers
*/
static inline int
@@ -991,12 +1088,14 @@ static inline unsigned int ata_tag_internal(unsigned int tag)
*/
static inline unsigned int ata_class_enabled(unsigned int class)
{
- return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
+ return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI ||
+ class == ATA_DEV_PMP || class == ATA_DEV_SEMB;
}
static inline unsigned int ata_class_disabled(unsigned int class)
{
- return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP;
+ return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP ||
+ class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP;
}
static inline unsigned int ata_class_absent(unsigned int class)
@@ -1020,15 +1119,62 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
}
/*
- * port helpers
+ * link helpers
*/
-static inline int ata_port_max_devices(const struct ata_port *ap)
+static inline int ata_is_host_link(const struct ata_link *link)
+{
+ return link == &link->ap->link;
+}
+
+static inline int ata_link_max_devices(const struct ata_link *link)
{
- if (ap->flags & ATA_FLAG_SLAVE_POSS)
+ if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS)
return 2;
return 1;
}
+static inline int ata_link_active(struct ata_link *link)
+{
+ return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
+static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
+{
+ if (ap->nr_pmp_links)
+ return ap->pmp_link;
+ return &ap->link;
+}
+
+static inline struct ata_link *ata_port_next_link(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+
+ if (link == &ap->link) {
+ if (!ap->nr_pmp_links)
+ return NULL;
+ return ap->pmp_link;
+ }
+
+ if (++link - ap->pmp_link < ap->nr_pmp_links)
+ return link;
+ return NULL;
+}
+
+#define __ata_port_for_each_link(lk, ap) \
+ for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk))
+
+#define ata_port_for_each_link(link, ap) \
+ for ((link) = ata_port_first_link(ap); (link); \
+ (link) = ata_port_next_link(link))
+
+#define ata_link_for_each_dev(dev, link) \
+ for ((dev) = (link)->device; \
+ (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \
+ (dev)++)
+
+#define ata_link_for_each_dev_reverse(dev, link) \
+ for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \
+ (dev) >= (link)->device || ((dev) = NULL); (dev)--)
static inline u8 ata_chk_status(struct ata_port *ap)
{
@@ -1110,9 +1256,11 @@ static inline u8 ata_wait_idle(struct ata_port *ap)
{
u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+#ifdef ATA_DEBUG
if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ)))
- DPRINTK("ATA: abnormal status 0x%X on port 0x%p\n",
- status, ap->ioaddr.status_addr);
+ ata_port_printk(ap, KERN_DEBUG, "abnormal Status 0x%X\n",
+ status);
+#endif
return status;
}
@@ -1149,7 +1297,7 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
{
memset(tf, 0, sizeof(*tf));
- tf->ctl = dev->ap->ctl;
+ tf->ctl = dev->link->ap->ctl;
if (dev->devno == 0)
tf->device = ATA_DEVICE_OBS;
else
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 0e843bf6587..f6279f68a82 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -238,6 +238,7 @@ extern void lockdep_info(void);
extern void lockdep_reset(void);
extern void lockdep_reset_lock(struct lockdep_map *lock);
extern void lockdep_free_key_range(void *start, unsigned long size);
+extern void lockdep_sys_exit(void);
extern void lockdep_off(void);
extern void lockdep_on(void);
@@ -252,6 +253,13 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass);
/*
+ * To initialize a lockdep_map statically use this macro.
+ * Note that _name must not be NULL.
+ */
+#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
+ { .name = (_name), .key = (void *)(_key), }
+
+/*
* Reinitialize a lock key - for cases where there is special locking or
* special initialization of locks so that the validator gets the scope
* of dependencies wrong: they are either too broad (they need a class-split)
@@ -317,6 +325,7 @@ static inline void lockdep_on(void)
# define INIT_LOCKDEP
# define lockdep_reset() do { debug_locks = 1; } while (0)
# define lockdep_free_key_range(start, size) do { } while (0)
+# define lockdep_sys_exit() do { } while (0)
/*
* The class key takes no space if lockdep is disabled:
*/
diff --git a/include/linux/maple.h b/include/linux/maple.h
new file mode 100644
index 00000000000..bad9a7b319d
--- /dev/null
+++ b/include/linux/maple.h
@@ -0,0 +1,80 @@
+#ifndef __LINUX_MAPLE_H
+#define __LINUX_MAPLE_H
+
+#include <linux/device.h>
+
+extern struct bus_type maple_bus_type;
+
+/* Maple Bus command and response codes */
+enum maple_code {
+ MAPLE_RESPONSE_FILEERR = -5,
+ MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */
+ MAPLE_RESPONSE_BADCMD = -3,
+ MAPLE_RESPONSE_BADFUNC = -2,
+ MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */
+ MAPLE_COMMAND_DEVINFO = 1,
+ MAPLE_COMMAND_ALLINFO = 2,
+ MAPLE_COMMAND_RESET = 3,
+ MAPLE_COMMAND_KILL = 4,
+ MAPLE_RESPONSE_DEVINFO = 5,
+ MAPLE_RESPONSE_ALLINFO = 6,
+ MAPLE_RESPONSE_OK = 7,
+ MAPLE_RESPONSE_DATATRF = 8,
+ MAPLE_COMMAND_GETCOND = 9,
+ MAPLE_COMMAND_GETMINFO = 10,
+ MAPLE_COMMAND_BREAD = 11,
+ MAPLE_COMMAND_BWRITE = 12,
+ MAPLE_COMMAND_SETCOND = 14
+};
+
+struct mapleq {
+ struct list_head list;
+ struct maple_device *dev;
+ void *sendbuf, *recvbuf, *recvbufdcsp;
+ unsigned char length;
+ enum maple_code command;
+};
+
+struct maple_devinfo {
+ unsigned long function;
+ unsigned long function_data[3];
+ unsigned char area_code;
+ unsigned char connector_directon;
+ char product_name[31];
+ char product_licence[61];
+ unsigned short standby_power;
+ unsigned short max_power;
+};
+
+struct maple_device {
+ struct maple_driver *driver;
+ struct mapleq *mq;
+ void *private_data;
+ void (*callback) (struct mapleq * mq);
+ unsigned long when, interval, function;
+ struct maple_devinfo devinfo;
+ unsigned char port, unit;
+ char product_name[32];
+ char product_licence[64];
+ int registered;
+ struct device dev;
+};
+
+struct maple_driver {
+ unsigned long function;
+ int (*connect) (struct maple_device * dev);
+ void (*disconnect) (struct maple_device * dev);
+ struct device_driver drv;
+};
+
+void maple_getcond_callback(struct maple_device *dev,
+ void (*callback) (struct mapleq * mq),
+ unsigned long interval,
+ unsigned long function);
+int maple_driver_register(struct device_driver *drv);
+void maple_add_packet(struct mapleq *mq);
+
+#define to_maple_dev(n) container_of(n, struct maple_device, dev)
+#define to_maple_driver(n) container_of(n, struct maple_driver, drv)
+
+#endif /* __LINUX_MAPLE_H */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 74523d999f7..522b0dd836c 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -262,11 +262,6 @@ struct pcmcia_device_id {
#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200
#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400
-/* I2C */
-struct i2c_device_id {
- __u16 id;
-};
-
/* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f
#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 123948b1454..e17c5343cf5 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -57,6 +57,15 @@
#define cfi_interleave_is_8(cfi) (0)
#endif
+#ifndef cfi_interleave
+#warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work.
+static inline int cfi_interleave(void *cfi)
+{
+ BUG();
+ return 0;
+}
+#endif
+
static inline int cfi_interleave_supported(int i)
{
switch (i) {
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
index a293a3b78e0..39e7d2a1be9 100644
--- a/include/linux/mtd/flashchip.h
+++ b/include/linux/mtd/flashchip.h
@@ -40,6 +40,7 @@ typedef enum {
FL_POINT,
FL_XIP_WHILE_ERASING,
FL_XIP_WHILE_WRITING,
+ FL_SHUTDOWN,
FL_UNKNOWN
} flstate_t;
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 81f3a314dd7..a9fae032ba8 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -125,7 +125,15 @@
#endif
#ifndef map_bankwidth
-#error "No bus width supported. What's the point?"
+#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
+static inline int map_bankwidth(void *map)
+{
+ BUG();
+ return 0;
+}
+#define map_bankwidth_is_large(map) (0)
+#define map_words(map) (0)
+#define MAX_MAP_BANKWIDTH 1
#endif
static inline int map_bankwidth_supported(int w)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index fd64ccfbce0..783fc983417 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -133,6 +133,13 @@ struct mtd_info {
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
+ /*
+ * Erase is an asynchronous operation. Device drivers are supposed
+ * to call instr->callback() whenever the operation completes, even
+ * if it completes with a failure.
+ * Callers are supposed to pass a callback function and wait for it
+ * to be called before writing to the block.
+ */
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index d2365c8dcac..c42bc7f533a 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -432,6 +432,7 @@ struct nand_chip {
#define NAND_MFR_STMICRO 0x20
#define NAND_MFR_HYNIX 0xad
#define NAND_MFR_MICRON 0x2c
+#define NAND_MFR_AMD 0x01
/**
* struct nand_flash_dev - NAND Flash Device ID Structure
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index a56d24ada50..fd0a260e070 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -60,6 +60,7 @@ struct onenand_bufferram {
* @erase_shift: [INTERN] number of address bits in a block
* @page_shift: [INTERN] number of address bits in a page
* @page_mask: [INTERN] a page per block mask
+ * @writesize: [INTERN] a real page size
* @bufferram_index: [INTERN] BufferRAM index
* @bufferram: [INTERN] BufferRAM info
* @readw: [REPLACEABLE] hardware specific function for read short
@@ -100,6 +101,7 @@ struct onenand_chip {
unsigned int erase_shift;
unsigned int page_shift;
unsigned int page_mask;
+ unsigned int writesize;
unsigned int bufferram_index;
struct onenand_bufferram bufferram[MAX_BUFFERRAM];
@@ -140,6 +142,8 @@ struct onenand_chip {
#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1)
#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)
#define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1)
+#define ONENAND_SET_BUFFERRAM0(this) (this->bufferram_index = 0)
+#define ONENAND_SET_BUFFERRAM1(this) (this->bufferram_index = 1)
#define ONENAND_GET_SYS_CFG1(this) \
(this->read_word(this->base + ONENAND_REG_SYS_CFG1))
@@ -149,6 +153,13 @@ struct onenand_chip {
#define ONENAND_IS_DDP(this) \
(this->device_id & ONENAND_DEVICE_IS_DDP)
+#ifdef CONFIG_MTD_ONENAND_2X_PROGRAM
+#define ONENAND_IS_2PLANE(this) \
+ (this->options & ONENAND_HAS_2PLANE)
+#else
+#define ONENAND_IS_2PLANE(this) (0)
+#endif
+
/* Check byte access in OneNAND */
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
@@ -157,6 +168,7 @@ struct onenand_chip {
*/
#define ONENAND_HAS_CONT_LOCK (0x0001)
#define ONENAND_HAS_UNLOCK_ALL (0x0002)
+#define ONENAND_HAS_2PLANE (0x0004)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000)
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index af94719890e..c46161f4eee 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -74,6 +74,8 @@
#define ONENAND_DEVICE_DENSITY_512Mb (0x002)
#define ONENAND_DEVICE_DENSITY_1Gb (0x003)
+#define ONENAND_DEVICE_DENSITY_2Gb (0x004)
+#define ONENAND_DEVICE_DENSITY_4Gb (0x005)
/*
* Version ID Register F002h (R)
@@ -111,6 +113,8 @@
#define ONENAND_CMD_READOOB (0x13)
#define ONENAND_CMD_PROG (0x80)
#define ONENAND_CMD_PROGOOB (0x1A)
+#define ONENAND_CMD_2X_PROG (0x7D)
+#define ONENAND_CMD_2X_CACHE_PROG (0x7F)
#define ONENAND_CMD_UNLOCK (0x23)
#define ONENAND_CMD_LOCK (0x2A)
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 0d50ea3df68..6a735c72f23 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -120,14 +120,17 @@ static inline int fastcall mutex_is_locked(struct mutex *lock)
* See kernel/mutex.c for detailed documentation of these APIs.
* Also see Documentation/mutex-design.txt.
*/
-extern void fastcall mutex_lock(struct mutex *lock);
-extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
-
#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
unsigned int subclass);
+
+#define mutex_lock(lock) mutex_lock_nested(lock, 0)
+#define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
#else
+extern void fastcall mutex_lock(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
+
# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5a11f889e56..39dd83b183a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1294,6 +1294,7 @@ static inline void netif_rx_complete(struct net_device *dev,
/**
* netif_tx_lock - grab network device transmit lock
* @dev: network device
+ * @cpu: cpu number of lock owner
*
* Get network device transmit lock
*/
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 1dd075eda59..16adac688af 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -51,7 +51,7 @@ struct sk_buff;
struct net_device;
typedef unsigned int nf_hookfn(unsigned int hooknum,
- struct sk_buff **skb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
@@ -183,7 +183,7 @@ void nf_log_packet(int pf,
struct nf_loginfo *li,
const char *fmt, ...);
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh);
@@ -195,7 +195,7 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
* value indicates the packet has been consumed by the hook.
*/
static inline int nf_hook_thresh(int pf, unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
@@ -207,14 +207,14 @@ static inline int nf_hook_thresh(int pf, unsigned int hook,
if (list_empty(&nf_hooks[pf][hook]))
return 1;
#endif
- return nf_hook_slow(pf, hook, pskb, indev, outdev, okfn, thresh);
+ return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
}
-static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb,
+static inline int nf_hook(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
- return nf_hook_thresh(pf, hook, pskb, indev, outdev, okfn, INT_MIN, 1);
+ return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN, 1);
}
/* Activate hook; either okfn or kfree_skb called, unless a hook
@@ -241,13 +241,13 @@ static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb,
#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
({int __ret; \
-if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh, 1)) == 1)\
+if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\
__ret = (okfn)(skb); \
__ret;})
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
({int __ret; \
-if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\
+if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\
__ret = (okfn)(skb); \
__ret;})
@@ -287,7 +287,7 @@ extern void nf_invalidate_cache(int pf);
/* Call this before modifying an existing packet: ensures it is
modifiable and linear to the point you care about (writable_len).
Returns true or false. */
-extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
+extern int skb_make_writable(struct sk_buff *skb, unsigned int writable_len);
static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
{
@@ -317,7 +317,7 @@ struct nf_afinfo {
unsigned int dataoff, u_int8_t protocol);
void (*saveroute)(const struct sk_buff *skb,
struct nf_info *info);
- int (*reroute)(struct sk_buff **skb,
+ int (*reroute)(struct sk_buff *skb,
const struct nf_info *info);
int route_key_size;
};
@@ -371,15 +371,15 @@ extern struct proc_dir_entry *proc_net_netfilter;
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
static inline int nf_hook_thresh(int pf, unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
int cond)
{
- return okfn(*pskb);
+ return okfn(skb);
}
-static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb,
+static inline int nf_hook(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
diff --git a/include/linux/netfilter/nf_conntrack_amanda.h b/include/linux/netfilter/nf_conntrack_amanda.h
index 26c223544ae..0bb5a6976bf 100644
--- a/include/linux/netfilter/nf_conntrack_amanda.h
+++ b/include/linux/netfilter/nf_conntrack_amanda.h
@@ -2,7 +2,7 @@
#define _NF_CONNTRACK_AMANDA_H
/* AMANDA tracking. */
-extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h
index b7c360ffd0d..47727d7546e 100644
--- a/include/linux/netfilter/nf_conntrack_ftp.h
+++ b/include/linux/netfilter/nf_conntrack_ftp.h
@@ -32,7 +32,7 @@ struct nf_conntrack_expect;
/* For NAT to hook in when we find a packet which describes what other
* connection we should expect. */
-extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
enum nf_ct_ftp_type type,
unsigned int matchoff,
diff --git a/include/linux/netfilter/nf_conntrack_h323.h b/include/linux/netfilter/nf_conntrack_h323.h
index 08e2f4977c2..aabd24ac763 100644
--- a/include/linux/netfilter/nf_conntrack_h323.h
+++ b/include/linux/netfilter/nf_conntrack_h323.h
@@ -36,27 +36,27 @@ extern void nf_conntrack_h245_expect(struct nf_conn *new,
struct nf_conntrack_expect *this);
extern void nf_conntrack_q931_expect(struct nf_conn *new,
struct nf_conntrack_expect *this);
-extern int (*set_h245_addr_hook) (struct sk_buff **pskb,
+extern int (*set_h245_addr_hook) (struct sk_buff *skb,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
union nf_conntrack_address *addr,
__be16 port);
-extern int (*set_h225_addr_hook) (struct sk_buff **pskb,
+extern int (*set_h225_addr_hook) (struct sk_buff *skb,
unsigned char **data, int dataoff,
TransportAddress *taddr,
union nf_conntrack_address *addr,
__be16 port);
-extern int (*set_sig_addr_hook) (struct sk_buff **pskb,
+extern int (*set_sig_addr_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count);
-extern int (*set_ras_addr_hook) (struct sk_buff **pskb,
+extern int (*set_ras_addr_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count);
-extern int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb,
+extern int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -64,24 +64,24 @@ extern int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb,
__be16 port, __be16 rtp_port,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp);
-extern int (*nat_t120_hook) (struct sk_buff **pskb, struct nf_conn *ct,
+extern int (*nat_t120_hook) (struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp);
-extern int (*nat_h245_hook) (struct sk_buff **pskb, struct nf_conn *ct,
+extern int (*nat_h245_hook) (struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp);
-extern int (*nat_callforwarding_hook) (struct sk_buff **pskb,
+extern int (*nat_callforwarding_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr,
__be16 port,
struct nf_conntrack_expect *exp);
-extern int (*nat_q931_hook) (struct sk_buff **pskb, struct nf_conn *ct,
+extern int (*nat_q931_hook) (struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, TransportAddress *taddr,
int idx, __be16 port,
diff --git a/include/linux/netfilter/nf_conntrack_irc.h b/include/linux/netfilter/nf_conntrack_irc.h
index 2ab6b825591..36282bf71b6 100644
--- a/include/linux/netfilter/nf_conntrack_irc.h
+++ b/include/linux/netfilter/nf_conntrack_irc.h
@@ -5,7 +5,7 @@
#define IRC_PORT 6667
-extern unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h
index c93061f3314..23435496d24 100644
--- a/include/linux/netfilter/nf_conntrack_pptp.h
+++ b/include/linux/netfilter/nf_conntrack_pptp.h
@@ -301,13 +301,13 @@ struct nf_conn;
struct nf_conntrack_expect;
extern int
-(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb,
+(*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq);
extern int
-(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb,
+(*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq);
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index bb7f2041db7..9fff19779bd 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -21,11 +21,11 @@ enum sip_header_pos {
POS_SDP_HEADER,
};
-extern unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char **dptr);
-extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
const char *dptr);
diff --git a/include/linux/netfilter/nf_conntrack_tftp.h b/include/linux/netfilter/nf_conntrack_tftp.h
index 0d79b7ae051..c78d38fdb05 100644
--- a/include/linux/netfilter/nf_conntrack_tftp.h
+++ b/include/linux/netfilter/nf_conntrack_tftp.h
@@ -13,7 +13,7 @@ struct tftphdr {
#define TFTP_OPCODE_ACK 4
#define TFTP_OPCODE_ERROR 5
-extern unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb,
+extern unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp);
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 64f425a855b..03e6ce979ea 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -191,7 +191,7 @@ struct xt_target
/* Returns verdict. Argument order changed since 2.6.9, as this
must now handle non-linear skbs, using skb_copy_bits and
skb_ip_make_writable. */
- unsigned int (*target)(struct sk_buff **pskb,
+ unsigned int (*target)(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 584cd1b18f1..2fc73fa8e37 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -287,7 +287,7 @@ struct arpt_error
extern int arpt_register_table(struct arpt_table *table,
const struct arpt_replace *repl);
extern void arpt_unregister_table(struct arpt_table *table);
-extern unsigned int arpt_do_table(struct sk_buff **pskb,
+extern unsigned int arpt_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index 94e0a7dc0cb..892f5b7771c 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -237,7 +237,7 @@ struct ebt_target
struct list_head list;
const char name[EBT_FUNCTION_MAXNAMELEN];
/* returns one of the standard verdicts */
- int (*target)(struct sk_buff **pskb, unsigned int hooknr,
+ int (*target)(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *targetdata, unsigned int datalen);
/* 0 == let it in */
@@ -294,7 +294,7 @@ extern int ebt_register_watcher(struct ebt_watcher *watcher);
extern void ebt_unregister_watcher(struct ebt_watcher *watcher);
extern int ebt_register_target(struct ebt_target *target);
extern void ebt_unregister_target(struct ebt_target *target);
-extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff **pskb,
+extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
struct ebt_table *table);
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index ceae87a4c89..1a63adf5c4c 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -75,8 +75,8 @@ enum nf_ip_hook_priorities {
#define SO_ORIGINAL_DST 80
#ifdef __KERNEL__
-extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type);
-extern int ip_xfrm_me_harder(struct sk_buff **pskb);
+extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type);
+extern int ip_xfrm_me_harder(struct sk_buff *skb);
extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol);
#endif /*__KERNEL__*/
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index e992cd6b28f..d79ed69cbc1 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -337,7 +337,7 @@ struct ipt_error
.target.errorname = "ERROR", \
}
-extern unsigned int ipt_do_table(struct sk_buff **pskb,
+extern unsigned int ipt_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 9a720f05888..7dc481ce7cb 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -336,7 +336,7 @@ extern void ip6t_init(void) __init;
extern int ip6t_register_table(struct xt_table *table,
const struct ip6t_replace *repl);
extern void ip6t_unregister_table(struct xt_table *table);
-extern unsigned int ip6t_do_table(struct sk_buff **pskb,
+extern unsigned int ip6t_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 7250eeadd7b..c5164c257f7 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -47,10 +47,8 @@
#include <linux/nfs3.h>
#include <linux/nfs4.h>
#include <linux/nfs_xdr.h>
-
#include <linux/nfs_fs_sb.h>
-#include <linux/rwsem.h>
#include <linux/mempool.h>
/*
@@ -77,6 +75,9 @@ struct nfs_open_context {
struct nfs4_state *state;
fl_owner_t lockowner;
int mode;
+
+ unsigned long flags;
+#define NFS_CONTEXT_ERROR_WRITE (0)
int error;
struct list_head list;
@@ -133,11 +134,6 @@ struct nfs_inode {
* server.
*/
unsigned long cache_change_attribute;
- /*
- * Counter indicating the number of outstanding requests that
- * will cause a file data update.
- */
- atomic_t data_updates;
struct rb_root access_cache;
struct list_head access_cache_entry_lru;
@@ -205,27 +201,18 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
#define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops)
#define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
-#define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
-#define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr)
-#define NFS_ATTRTIMEO(inode) (NFS_I(inode)->attrtimeo)
#define NFS_MINATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
: NFS_SERVER(inode)->acregmin)
#define NFS_MAXATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
: NFS_SERVER(inode)->acregmax)
-#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp)
#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode)))
#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
-static inline int nfs_caches_unstable(struct inode *inode)
-{
- return atomic_read(&NFS_I(inode)->data_updates) != 0;
-}
-
static inline void nfs_mark_for_revalidate(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
@@ -237,12 +224,6 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
spin_unlock(&inode->i_lock);
}
-static inline void NFS_CACHEINV(struct inode *inode)
-{
- if (!nfs_caches_unstable(inode))
- nfs_mark_for_revalidate(inode);
-}
-
static inline int nfs_server_capable(struct inode *inode, int cap)
{
return NFS_SERVER(inode)->caps & cap;
@@ -253,28 +234,33 @@ static inline int NFS_USE_READDIRPLUS(struct inode *inode)
return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
}
+static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
+{
+ dentry->d_time = verf;
+}
+
/**
* nfs_save_change_attribute - Returns the inode attribute change cookie
- * @inode - pointer to inode
+ * @dir - pointer to parent directory inode
* The "change attribute" is updated every time we finish an operation
* that will result in a metadata change on the server.
*/
-static inline long nfs_save_change_attribute(struct inode *inode)
+static inline unsigned long nfs_save_change_attribute(struct inode *dir)
{
- return NFS_I(inode)->cache_change_attribute;
+ return NFS_I(dir)->cache_change_attribute;
}
/**
- * nfs_verify_change_attribute - Detects NFS inode cache updates
- * @inode - pointer to inode
+ * nfs_verify_change_attribute - Detects NFS remote directory changes
+ * @dir - pointer to parent directory inode
* @chattr - previously saved change attribute
- * Return "false" if metadata has been updated (or is in the process of
- * being updated) since the change attribute was saved.
+ * Return "false" if the verifiers doesn't match the change attribute.
+ * This would usually indicate that the directory contents have changed on
+ * the server, and that any dentries need revalidating.
*/
-static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+static inline int nfs_verify_change_attribute(struct inode *dir, unsigned long chattr)
{
- return !nfs_caches_unstable(inode)
- && time_after_eq(chattr, NFS_I(inode)->cache_change_attribute);
+ return chattr == NFS_I(dir)->cache_change_attribute;
}
/*
@@ -283,15 +269,14 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long
extern int nfs_sync_mapping(struct address_space *mapping);
extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
extern void nfs_zap_caches(struct inode *);
+extern void nfs_invalidate_atime(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
-extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
-extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
-extern void nfs_access_zap_cache(struct inode *inode);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode);
@@ -301,13 +286,10 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
-extern void nfs_begin_attr_update(struct inode *);
-extern void nfs_end_attr_update(struct inode *);
-extern void nfs_begin_data_update(struct inode *);
-extern void nfs_end_data_update(struct inode *);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
+extern u64 nfs_compat_user_ino64(u64 fileid);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern __be32 root_nfs_parse_addr(char *name); /*__init*/
@@ -328,14 +310,15 @@ extern const struct inode_operations nfs3_file_inode_operations;
extern const struct file_operations nfs_file_operations;
extern const struct address_space_operations nfs_file_aops;
-static inline struct rpc_cred *nfs_file_cred(struct file *file)
+static inline struct nfs_open_context *nfs_file_open_context(struct file *filp)
{
- if (file != NULL) {
- struct nfs_open_context *ctx;
+ return filp->private_data;
+}
- ctx = (struct nfs_open_context*)file->private_data;
- return ctx->cred;
- }
+static inline struct rpc_cred *nfs_file_cred(struct file *file)
+{
+ if (file != NULL)
+ return nfs_file_open_context(file)->cred;
return NULL;
}
@@ -378,6 +361,8 @@ extern const struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations;
extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
+extern void nfs_access_zap_cache(struct inode *inode);
/*
* linux/fs/nfs/symlink.c
@@ -420,15 +405,14 @@ extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
extern void nfs_writedata_release(void *);
-extern int nfs_set_page_dirty(struct page *);
/*
* Try to write back everything synchronously (but check the
* return value!)
*/
extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_control *, int);
-extern int nfs_sync_mapping_range(struct address_space *, loff_t, loff_t, int);
extern int nfs_wb_all(struct inode *inode);
+extern int nfs_wb_nocommit(struct inode *inode);
extern int nfs_wb_page(struct inode *inode, struct page* page);
extern int nfs_wb_page_priority(struct inode *inode, struct page* page, int how);
extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 78e60798d10..30dbcc185e6 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -30,7 +30,6 @@
#define PG_BUSY 0
#define PG_NEED_COMMIT 1
#define PG_NEED_RESCHED 2
-#define PG_NEED_FLUSH 3
struct nfs_inode;
struct nfs_page {
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index cf74a4db84a..daab252f2e5 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -62,7 +62,8 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
-#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */
+#define NFS_ATTR_WCC_V4 0x0010 /* pre-op change attribute */
+#define NFS_ATTR_FATTR_V4_REFERRAL 0x0020 /* NFSv4 referral */
/*
* Info on the file system
@@ -538,10 +539,13 @@ typedef u64 clientid4;
struct nfs4_accessargs {
const struct nfs_fh * fh;
+ const u32 * bitmask;
u32 access;
};
struct nfs4_accessres {
+ const struct nfs_server * server;
+ struct nfs_fattr * fattr;
u32 supported;
u32 access;
};
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index e452256d3f7..604a0d786bc 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -153,19 +153,21 @@ extern int nfsd_max_blksize;
*/
#ifdef CONFIG_NFSD_V4
extern unsigned int max_delegations;
-void nfs4_state_init(void);
-int nfs4_state_start(void);
+int nfs4_state_init(void);
+void nfsd4_free_slabs(void);
+void nfs4_state_start(void);
void nfs4_state_shutdown(void);
time_t nfs4_lease_time(void);
void nfs4_reset_lease(time_t leasetime);
int nfs4_reset_recoverydir(char *recdir);
#else
-static inline void nfs4_state_init(void){};
-static inline int nfs4_state_start(void){return 0;}
-static inline void nfs4_state_shutdown(void){}
-static inline time_t nfs4_lease_time(void){return 0;}
-static inline void nfs4_reset_lease(time_t leasetime){}
-static inline int nfs4_reset_recoverydir(char *recdir) {return 0;}
+static inline int nfs4_state_init(void) { return 0; }
+static inline void nfsd4_free_slabs(void) { }
+static inline void nfs4_state_start(void) { }
+static inline void nfs4_state_shutdown(void) { }
+static inline time_t nfs4_lease_time(void) { return 0; }
+static inline void nfs4_reset_lease(time_t leasetime) { }
+static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
#endif
/*
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index 11e568ee0ee..d1941cb965e 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -150,17 +150,7 @@ typedef struct svc_fh {
struct timespec fh_pre_ctime; /* ctime before oper */
/* Post-op attributes saved in fh_unlock */
- umode_t fh_post_mode; /* i_mode */
- nlink_t fh_post_nlink; /* i_nlink */
- uid_t fh_post_uid; /* i_uid */
- gid_t fh_post_gid; /* i_gid */
- __u64 fh_post_size; /* i_size */
- unsigned long fh_post_blocks; /* i_blocks */
- unsigned long fh_post_blksize;/* i_blksize */
- __be32 fh_post_rdev[2];/* i_rdev */
- struct timespec fh_post_atime; /* i_atime */
- struct timespec fh_post_mtime; /* i_mtime */
- struct timespec fh_post_ctime; /* i_ctime */
+ struct kstat fh_post_attr; /* full attrs after operation */
#endif /* CONFIG_NFSD_V3 */
} svc_fh;
@@ -297,36 +287,12 @@ fill_pre_wcc(struct svc_fh *fhp)
if (!fhp->fh_pre_saved) {
fhp->fh_pre_mtime = inode->i_mtime;
fhp->fh_pre_ctime = inode->i_ctime;
- fhp->fh_pre_size = inode->i_size;
- fhp->fh_pre_saved = 1;
+ fhp->fh_pre_size = inode->i_size;
+ fhp->fh_pre_saved = 1;
}
}
-/*
- * Fill in the post_op attr for the wcc data
- */
-static inline void
-fill_post_wcc(struct svc_fh *fhp)
-{
- struct inode *inode = fhp->fh_dentry->d_inode;
-
- if (fhp->fh_post_saved)
- printk("nfsd: inode locked twice during operation.\n");
-
- fhp->fh_post_mode = inode->i_mode;
- fhp->fh_post_nlink = inode->i_nlink;
- fhp->fh_post_uid = inode->i_uid;
- fhp->fh_post_gid = inode->i_gid;
- fhp->fh_post_size = inode->i_size;
- fhp->fh_post_blksize = BLOCK_SIZE;
- fhp->fh_post_blocks = inode->i_blocks;
- fhp->fh_post_rdev[0] = htonl((u32)imajor(inode));
- fhp->fh_post_rdev[1] = htonl((u32)iminor(inode));
- fhp->fh_post_atime = inode->i_atime;
- fhp->fh_post_mtime = inode->i_mtime;
- fhp->fh_post_ctime = inode->i_ctime;
- fhp->fh_post_saved = 1;
-}
+extern void fill_post_wcc(struct svc_fh *);
#else
#define fill_pre_wcc(ignored)
#define fill_post_wcc(notused)
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 1b653267133..b0ddfb41c79 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -428,8 +428,8 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
cinfo->atomic = 1;
cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
- cinfo->after_ctime_sec = fhp->fh_post_ctime.tv_sec;
- cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
+ cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
+ cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
}
int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 038a0dc7273..768b93359f9 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -685,13 +685,16 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
* a PCI domain is defined to be a set of PCI busses which share
* configuration space.
*/
-#ifndef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS
+extern int pci_domains_supported;
+#else
+enum { pci_domains_supported = 0 };
static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
static inline int pci_proc_domain(struct pci_bus *bus)
{
return 0;
}
-#endif
+#endif /* CONFIG_PCI_DOMAINS */
#else /* CONFIG_PCI is not enabled */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 2bcb02d555e..2c49561f9b4 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -829,6 +829,9 @@
#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
#define PCI_DEVICE_ID_UMC_UM8886A 0x886a
+#define PCI_VENDOR_ID_PICOPOWER 0x1066
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002
#define PCI_VENDOR_ID_MYLEX 0x1069
#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001
@@ -1464,6 +1467,8 @@
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
+#define PCI_VENDOR_ID_ATTO 0x117c
+
#define PCI_VENDOR_ID_RICOH 0x1180
#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
@@ -2073,6 +2078,9 @@
#define PCI_DEVICE_ID_ARECA_1130 0x1130
#define PCI_DEVICE_ID_ARECA_1160 0x1160
#define PCI_DEVICE_ID_ARECA_1170 0x1170
+#define PCI_DEVICE_ID_ARECA_1200 0x1200
+#define PCI_DEVICE_ID_ARECA_1201 0x1201
+#define PCI_DEVICE_ID_ARECA_1202 0x1202
#define PCI_DEVICE_ID_ARECA_1210 0x1210
#define PCI_DEVICE_ID_ARECA_1220 0x1220
#define PCI_DEVICE_ID_ARECA_1230 0x1230
@@ -2243,6 +2251,7 @@
#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5
#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6
#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc
#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1
#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 423d592c55d..c1914a8b94a 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -147,7 +147,7 @@
#define PCI_BRIDGE_CONTROL 0x3e
#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
-#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
+#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */
#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
@@ -202,8 +202,12 @@
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
-#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */
+#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
+#define PCI_CAP_ID_DBG 0x0A /* Debug port */
+#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
+#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
+#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 8bbd459eafd..e80804316cd 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -15,7 +15,7 @@
struct platform_device {
const char * name;
- u32 id;
+ int id;
struct device dev;
u32 num_resources;
struct resource * resource;
@@ -35,9 +35,10 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u
extern int platform_get_irq_byname(struct platform_device *, char *);
extern int platform_add_devices(struct platform_device **, int);
-extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int);
+extern struct platform_device *platform_device_register_simple(char *, int id,
+ struct resource *, unsigned int);
-extern struct platform_device *platform_device_alloc(const char *name, unsigned int id);
+extern struct platform_device *platform_device_alloc(const char *name, int id);
extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num);
extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
extern int platform_device_add(struct platform_device *pdev);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index fe17d7d750c..76c1a530edc 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -41,6 +41,7 @@
#include <linux/percpu.h>
#include <linux/cpumask.h>
#include <linux/seqlock.h>
+#include <linux/lockdep.h>
/**
* struct rcu_head - callback structure for use with RCU
@@ -133,6 +134,15 @@ static inline void rcu_bh_qsctr_inc(int cpu)
extern int rcu_pending(int cpu);
extern int rcu_needs_cpu(int cpu);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern struct lockdep_map rcu_lock_map;
+# define rcu_read_acquire() lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_)
+# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_)
+#else
+# define rcu_read_acquire() do { } while (0)
+# define rcu_read_release() do { } while (0)
+#endif
+
/**
* rcu_read_lock - mark the beginning of an RCU read-side critical section.
*
@@ -166,6 +176,7 @@ extern int rcu_needs_cpu(int cpu);
do { \
preempt_disable(); \
__acquire(RCU); \
+ rcu_read_acquire(); \
} while(0)
/**
@@ -175,6 +186,7 @@ extern int rcu_needs_cpu(int cpu);
*/
#define rcu_read_unlock() \
do { \
+ rcu_read_release(); \
__release(RCU); \
preempt_enable(); \
} while(0)
@@ -204,6 +216,7 @@ extern int rcu_needs_cpu(int cpu);
do { \
local_bh_disable(); \
__acquire(RCU_BH); \
+ rcu_read_acquire(); \
} while(0)
/*
@@ -213,6 +226,7 @@ extern int rcu_needs_cpu(int cpu);
*/
#define rcu_read_unlock_bh() \
do { \
+ rcu_read_release(); \
__release(RCU_BH); \
local_bh_enable(); \
} while(0)
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 1e5488ede03..ff9e9234f8b 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -120,7 +120,7 @@ struct reiserfs_journal_cnode {
struct buffer_head *bh; /* real buffer head */
struct super_block *sb; /* dev of real buffer head */
__u32 blocknr; /* block number of real buffer head, == 0 when buffer on disk */
- long state;
+ unsigned long state;
struct reiserfs_journal_list *jlist; /* journal list this cnode lives in */
struct reiserfs_journal_cnode *next; /* next in transaction list */
struct reiserfs_journal_cnode *prev; /* prev in transaction list */
@@ -181,7 +181,7 @@ struct reiserfs_journal {
struct block_device *j_dev_bd;
int j_1st_reserved_block; /* first block on s_dev of reserved area journal */
- long j_state;
+ unsigned long j_state;
unsigned long j_trans_id;
unsigned long j_mount_id;
unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 833f7dc2b8d..228e0a8ce24 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -87,6 +87,7 @@ struct sched_param {
#include <linux/timer.h>
#include <linux/hrtimer.h>
#include <linux/task_io_accounting.h>
+#include <linux/kobject.h>
#include <asm/processor.h>
@@ -136,6 +137,7 @@ extern unsigned long weighted_cpuload(const int cpu);
struct seq_file;
struct cfs_rq;
+struct task_group;
#ifdef CONFIG_SCHED_DEBUG
extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
extern void proc_sched_set_task(struct task_struct *p);
@@ -174,8 +176,7 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
/* in tsk->state again */
-#define TASK_NONINTERACTIVE 64
-#define TASK_DEAD 128
+#define TASK_DEAD 64
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
@@ -516,6 +517,8 @@ struct signal_struct {
* in __exit_signal, except for the group leader.
*/
cputime_t utime, stime, cutime, cstime;
+ cputime_t gtime;
+ cputime_t cgtime;
unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
unsigned long inblock, oublock, cinblock, coublock;
@@ -596,8 +599,21 @@ struct user_struct {
/* Hash table maintenance information */
struct hlist_node uidhash_node;
uid_t uid;
+
+#ifdef CONFIG_FAIR_USER_SCHED
+ struct task_group *tg;
+ struct kset kset;
+ struct subsys_attribute user_attr;
+ struct work_struct work;
+#endif
};
+#ifdef CONFIG_FAIR_USER_SCHED
+extern int uids_kobject_init(void);
+#else
+static inline int uids_kobject_init(void) { return 0; }
+#endif
+
extern struct user_struct *find_user(uid_t);
extern struct user_struct root_user;
@@ -609,13 +625,17 @@ struct reclaim_state;
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info {
/* cumulative counters */
- unsigned long pcnt; /* # of times run on this cpu */
+ unsigned long pcount; /* # of times run on this cpu */
unsigned long long cpu_time, /* time spent on the cpu */
run_delay; /* time spent waiting on a runqueue */
/* timestamps */
unsigned long long last_arrival,/* when we last ran on a cpu */
last_queued; /* when we were last queued to run */
+#ifdef CONFIG_SCHEDSTATS
+ /* BKL stats */
+ unsigned long bkl_count;
+#endif
};
#endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */
@@ -750,7 +770,7 @@ struct sched_domain {
#ifdef CONFIG_SCHEDSTATS
/* load_balance() stats */
- unsigned long lb_cnt[CPU_MAX_IDLE_TYPES];
+ unsigned long lb_count[CPU_MAX_IDLE_TYPES];
unsigned long lb_failed[CPU_MAX_IDLE_TYPES];
unsigned long lb_balanced[CPU_MAX_IDLE_TYPES];
unsigned long lb_imbalance[CPU_MAX_IDLE_TYPES];
@@ -760,17 +780,17 @@ struct sched_domain {
unsigned long lb_nobusyq[CPU_MAX_IDLE_TYPES];
/* Active load balancing */
- unsigned long alb_cnt;
+ unsigned long alb_count;
unsigned long alb_failed;
unsigned long alb_pushed;
/* SD_BALANCE_EXEC stats */
- unsigned long sbe_cnt;
+ unsigned long sbe_count;
unsigned long sbe_balanced;
unsigned long sbe_pushed;
/* SD_BALANCE_FORK stats */
- unsigned long sbf_cnt;
+ unsigned long sbf_count;
unsigned long sbf_balanced;
unsigned long sbf_pushed;
@@ -854,11 +874,11 @@ struct rq;
struct sched_domain;
struct sched_class {
- struct sched_class *next;
+ const struct sched_class *next;
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
- void (*yield_task) (struct rq *rq, struct task_struct *p);
+ void (*yield_task) (struct rq *rq);
void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
@@ -888,31 +908,22 @@ struct load_weight {
* 4 se->block_start
* 4 se->run_node
* 4 se->sleep_start
- * 4 se->sleep_start_fair
* 6 se->load.weight
- * 7 se->delta_fair
- * 15 se->wait_runtime
*/
struct sched_entity {
- long wait_runtime;
- unsigned long delta_fair_run;
- unsigned long delta_fair_sleep;
- unsigned long delta_exec;
- s64 fair_key;
struct load_weight load; /* for load-balancing */
struct rb_node run_node;
unsigned int on_rq;
+ int peer_preempt;
u64 exec_start;
u64 sum_exec_runtime;
+ u64 vruntime;
u64 prev_sum_exec_runtime;
- u64 wait_start_fair;
- u64 sleep_start_fair;
#ifdef CONFIG_SCHEDSTATS
u64 wait_start;
u64 wait_max;
- s64 sum_wait_runtime;
u64 sleep_start;
u64 sleep_max;
@@ -921,9 +932,25 @@ struct sched_entity {
u64 block_start;
u64 block_max;
u64 exec_max;
-
- unsigned long wait_runtime_overruns;
- unsigned long wait_runtime_underruns;
+ u64 slice_max;
+
+ u64 nr_migrations;
+ u64 nr_migrations_cold;
+ u64 nr_failed_migrations_affine;
+ u64 nr_failed_migrations_running;
+ u64 nr_failed_migrations_hot;
+ u64 nr_forced_migrations;
+ u64 nr_forced2_migrations;
+
+ u64 nr_wakeups;
+ u64 nr_wakeups_sync;
+ u64 nr_wakeups_migrate;
+ u64 nr_wakeups_local;
+ u64 nr_wakeups_remote;
+ u64 nr_wakeups_affine;
+ u64 nr_wakeups_affine_attempts;
+ u64 nr_wakeups_passive;
+ u64 nr_wakeups_idle;
#endif
#ifdef CONFIG_FAIR_GROUP_SCHED
@@ -952,7 +979,7 @@ struct task_struct {
int prio, static_prio, normal_prio;
struct list_head run_list;
- struct sched_class *sched_class;
+ const struct sched_class *sched_class;
struct sched_entity se;
#ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -1023,6 +1050,7 @@ struct task_struct {
unsigned int rt_priority;
cputime_t utime, stime;
+ cputime_t gtime;
unsigned long nvcsw, nivcsw; /* context switch counts */
struct timespec start_time; /* monotonic time */
struct timespec real_start_time; /* boot based time */
@@ -1314,6 +1342,7 @@ static inline void put_task_struct(struct task_struct *t)
#define PF_STARTING 0x00000002 /* being created */
#define PF_EXITING 0x00000004 /* getting shut down */
#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */
+#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* dumped core */
@@ -1401,15 +1430,17 @@ static inline void idle_task_exit(void) {}
extern void sched_idle_next(void);
+#ifdef CONFIG_SCHED_DEBUG
extern unsigned int sysctl_sched_latency;
-extern unsigned int sysctl_sched_min_granularity;
+extern unsigned int sysctl_sched_nr_latency;
extern unsigned int sysctl_sched_wakeup_granularity;
extern unsigned int sysctl_sched_batch_wakeup_granularity;
-extern unsigned int sysctl_sched_stat_granularity;
-extern unsigned int sysctl_sched_runtime_limit;
-extern unsigned int sysctl_sched_compat_yield;
extern unsigned int sysctl_sched_child_runs_first;
extern unsigned int sysctl_sched_features;
+extern unsigned int sysctl_sched_migration_cost;
+#endif
+
+extern unsigned int sysctl_sched_compat_yield;
#ifdef CONFIG_RT_MUTEXES
extern int rt_mutex_getprio(struct task_struct *p);
@@ -1843,6 +1874,18 @@ extern int sched_mc_power_savings, sched_smt_power_savings;
extern void normalize_rt_tasks(void);
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+extern struct task_group init_task_group;
+
+extern struct task_group *sched_create_group(void);
+extern void sched_destroy_group(struct task_group *tg);
+extern void sched_move_task(struct task_struct *tsk);
+extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
+extern unsigned long sched_group_shares(struct task_group *tg);
+
+#endif
+
#ifdef CONFIG_TASK_XACCT
static inline void add_rchar(struct task_struct *tsk, ssize_t amt)
{
diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h
index d2b058130eb..ece4e553e9a 100644
--- a/include/linux/scx200_gpio.h
+++ b/include/linux/scx200_gpio.h
@@ -1,7 +1,7 @@
u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
extern unsigned scx200_gpio_base;
-extern long scx200_gpio_shadow[2];
+extern unsigned long scx200_gpio_shadow[2];
extern struct nsc_gpio_ops scx200_gpio_ops;
#define scx200_gpio_present() (scx200_gpio_base!=0)
@@ -9,7 +9,7 @@ extern struct nsc_gpio_ops scx200_gpio_ops;
/* Definitions to make sure I do the same thing in all functions */
#define __SCx200_GPIO_BANK unsigned bank = index>>5
#define __SCx200_GPIO_IOADDR unsigned short ioaddr = scx200_gpio_base+0x10*bank
-#define __SCx200_GPIO_SHADOW long *shadow = scx200_gpio_shadow+bank
+#define __SCx200_GPIO_SHADOW unsigned long *shadow = scx200_gpio_shadow+bank
#define __SCx200_GPIO_INDEX index &= 31
#define __SCx200_GPIO_OUT __asm__ __volatile__("outsl":"=mS" (shadow):"d" (ioaddr), "0" (shadow))
@@ -42,7 +42,7 @@ static inline void scx200_gpio_set_high(unsigned index) {
__SCx200_GPIO_IOADDR;
__SCx200_GPIO_SHADOW;
__SCx200_GPIO_INDEX;
- set_bit(index, shadow);
+ set_bit(index, shadow); /* __set_bit()? */
__SCx200_GPIO_OUT;
}
@@ -53,7 +53,7 @@ static inline void scx200_gpio_set_low(unsigned index) {
__SCx200_GPIO_IOADDR;
__SCx200_GPIO_SHADOW;
__SCx200_GPIO_INDEX;
- clear_bit(index, shadow);
+ clear_bit(index, shadow); /* __clear_bit()? */
__SCx200_GPIO_OUT;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a656cecd373..f93f22b3d2f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -357,6 +357,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
}
extern void kfree_skbmem(struct sk_buff *skb);
+extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
extern struct sk_buff *skb_clone(struct sk_buff *skb,
gfp_t priority);
extern struct sk_buff *skb_copy(const struct sk_buff *skb,
@@ -1781,6 +1782,11 @@ static inline int skb_is_gso(const struct sk_buff *skb)
return skb_shinfo(skb)->gso_size;
}
+static inline int skb_is_gso_v6(const struct sk_buff *skb)
+{
+ return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
+}
+
static inline void skb_forward_csum(struct sk_buff *skb)
{
/* Unfortunately we don't support this one. Any brave souls? */
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
index 4a0a329beaf..94b4a10b912 100644
--- a/include/linux/stallion.h
+++ b/include/linux/stallion.h
@@ -75,7 +75,7 @@ struct stlport {
int ioaddr;
int uartaddr;
unsigned int pagenr;
- long istate;
+ unsigned long istate;
int flags;
int baud_base;
int custom_divisor;
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 3699dff7db8..bd7a6b0a87a 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -136,16 +136,6 @@ sunrpc_cache_update(struct cache_detail *detail,
struct cache_head *new, struct cache_head *old, int hash);
-#define cache_for_each(pos, detail, index, member) \
- for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ; \
- ({if (index==0)read_unlock(&(detail)->hash_lock); index--;}); \
- ) \
- for (pos = container_of((detail)->hash_table[index], typeof(*pos), member); \
- &pos->member; \
- pos = container_of(pos->member.next, typeof(*pos), member))
-
-
-
extern void cache_clean_deferred(void *owner);
static inline struct cache_head *cache_get(struct cache_head *h)
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index c0d9d14983b..d9d5c5ad826 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -117,7 +117,7 @@ struct rpc_create_args {
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
- struct rpc_program *, int);
+ struct rpc_program *, u32);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index 3912cf16361..3347c72b848 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -88,6 +88,11 @@ enum {
CTL_SLOTTABLE_TCP,
CTL_MIN_RESVPORT,
CTL_MAX_RESVPORT,
+ CTL_SLOTTABLE_RDMA,
+ CTL_RDMA_MAXINLINEREAD,
+ CTL_RDMA_MAXINLINEWRITE,
+ CTL_RDMA_WRITEPADDING,
+ CTL_RDMA_MEMREG,
};
#endif /* _LINUX_SUNRPC_DEBUG_H_ */
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 784d4c3ef65..c4beb577511 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -138,6 +138,19 @@ typedef __be32 rpc_fraghdr;
#define RPC_MAX_HEADER_WITH_AUTH \
(RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
+/*
+ * RFC1833/RFC3530 rpcbind (v3+) well-known netid's.
+ */
+#define RPCBIND_NETID_UDP "udp"
+#define RPCBIND_NETID_TCP "tcp"
+#define RPCBIND_NETID_UDP6 "udp6"
+#define RPCBIND_NETID_TCP6 "tcp6"
+
+/*
+ * Note that RFC 1833 does not put any size restrictions on the
+ * netid string, but all currently defined netid's fit in 4 bytes.
+ */
+#define RPCBIND_MAXNETIDLEN (4u)
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff --git a/include/linux/sunrpc/rpc_rdma.h b/include/linux/sunrpc/rpc_rdma.h
new file mode 100644
index 00000000000..0013a0d8dc6
--- /dev/null
+++ b/include/linux/sunrpc/rpc_rdma.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_RPC_RDMA_H
+#define _LINUX_SUNRPC_RPC_RDMA_H
+
+struct rpcrdma_segment {
+ uint32_t rs_handle; /* Registered memory handle */
+ uint32_t rs_length; /* Length of the chunk in bytes */
+ uint64_t rs_offset; /* Chunk virtual address or offset */
+};
+
+/*
+ * read chunk(s), encoded as a linked list.
+ */
+struct rpcrdma_read_chunk {
+ uint32_t rc_discrim; /* 1 indicates presence */
+ uint32_t rc_position; /* Position in XDR stream */
+ struct rpcrdma_segment rc_target;
+};
+
+/*
+ * write chunk, and reply chunk.
+ */
+struct rpcrdma_write_chunk {
+ struct rpcrdma_segment wc_target;
+};
+
+/*
+ * write chunk(s), encoded as a counted array.
+ */
+struct rpcrdma_write_array {
+ uint32_t wc_discrim; /* 1 indicates presence */
+ uint32_t wc_nchunks; /* Array count */
+ struct rpcrdma_write_chunk wc_array[0];
+};
+
+struct rpcrdma_msg {
+ uint32_t rm_xid; /* Mirrors the RPC header xid */
+ uint32_t rm_vers; /* Version of this protocol */
+ uint32_t rm_credit; /* Buffers requested/granted */
+ uint32_t rm_type; /* Type of message (enum rpcrdma_proc) */
+ union {
+
+ struct { /* no chunks */
+ uint32_t rm_empty[3]; /* 3 empty chunk lists */
+ } rm_nochunks;
+
+ struct { /* no chunks and padded */
+ uint32_t rm_align; /* Padding alignment */
+ uint32_t rm_thresh; /* Padding threshold */
+ uint32_t rm_pempty[3]; /* 3 empty chunk lists */
+ } rm_padded;
+
+ uint32_t rm_chunks[0]; /* read, write and reply chunks */
+
+ } rm_body;
+};
+
+#define RPCRDMA_HDRLEN_MIN 28
+
+enum rpcrdma_errcode {
+ ERR_VERS = 1,
+ ERR_CHUNK = 2
+};
+
+struct rpcrdma_err_vers {
+ uint32_t rdma_vers_low; /* Version range supported by peer */
+ uint32_t rdma_vers_high;
+};
+
+enum rpcrdma_proc {
+ RDMA_MSG = 0, /* An RPC call or reply msg */
+ RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */
+ RDMA_MSGP = 2, /* An RPC call or reply msg with padding */
+ RDMA_DONE = 3, /* Client signals reply completion */
+ RDMA_ERROR = 4 /* An RPC RDMA encoding error */
+};
+
+#endif /* _LINUX_SUNRPC_RPC_RDMA_H */
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index c6b53d181bf..0751c9464d0 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -70,7 +70,10 @@ struct xdr_buf {
struct page ** pages; /* Array of contiguous pages */
unsigned int page_base, /* Start of page data */
- page_len; /* Length of page data */
+ page_len, /* Length of page data */
+ flags; /* Flags for data disposition */
+#define XDRBUF_READ 0x01 /* target of file read */
+#define XDRBUF_WRITE 0x02 /* source of file write */
unsigned int buflen, /* Total length of storage buffer */
len; /* Length of XDR encoded message */
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index d11cedd14f0..30b17b3bc1a 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -19,25 +19,11 @@
#ifdef __KERNEL__
-extern unsigned int xprt_udp_slot_table_entries;
-extern unsigned int xprt_tcp_slot_table_entries;
-
#define RPC_MIN_SLOT_TABLE (2U)
#define RPC_DEF_SLOT_TABLE (16U)
#define RPC_MAX_SLOT_TABLE (128U)
/*
- * Parameters for choosing a free port
- */
-extern unsigned int xprt_min_resvport;
-extern unsigned int xprt_max_resvport;
-
-#define RPC_MIN_RESVPORT (1U)
-#define RPC_MAX_RESVPORT (65535U)
-#define RPC_DEF_MIN_RESVPORT (665U)
-#define RPC_DEF_MAX_RESVPORT (1023U)
-
-/*
* This describes a timeout strategy
*/
struct rpc_timeout {
@@ -53,6 +39,10 @@ enum rpc_display_format_t {
RPC_DISPLAY_PORT,
RPC_DISPLAY_PROTO,
RPC_DISPLAY_ALL,
+ RPC_DISPLAY_HEX_ADDR,
+ RPC_DISPLAY_HEX_PORT,
+ RPC_DISPLAY_UNIVERSAL_ADDR,
+ RPC_DISPLAY_NETID,
RPC_DISPLAY_MAX,
};
@@ -196,14 +186,22 @@ struct rpc_xprt {
char * address_strings[RPC_DISPLAY_MAX];
};
-struct rpc_xprtsock_create {
- int proto; /* IPPROTO_UDP or IPPROTO_TCP */
+struct xprt_create {
+ int ident; /* XPRT_TRANSPORT identifier */
struct sockaddr * srcaddr; /* optional local address */
struct sockaddr * dstaddr; /* remote peer address */
size_t addrlen;
struct rpc_timeout * timeout; /* optional timeout parameters */
};
+struct xprt_class {
+ struct list_head list;
+ int ident; /* XPRT_TRANSPORT identifier */
+ struct rpc_xprt * (*setup)(struct xprt_create *);
+ struct module *owner;
+ char name[32];
+};
+
/*
* Transport operations used by ULPs
*/
@@ -212,7 +210,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long
/*
* Generic internal transport functions
*/
-struct rpc_xprt * xprt_create_transport(struct rpc_xprtsock_create *args);
+struct rpc_xprt *xprt_create_transport(struct xprt_create *args);
void xprt_connect(struct rpc_task *task);
void xprt_reserve(struct rpc_task *task);
int xprt_reserve_xprt(struct rpc_task *task);
@@ -235,6 +233,8 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
/*
* Transport switch helper functions
*/
+int xprt_register_transport(struct xprt_class *type);
+int xprt_unregister_transport(struct xprt_class *type);
void xprt_set_retrans_timeout_def(struct rpc_task *task);
void xprt_set_retrans_timeout_rtt(struct rpc_task *task);
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
@@ -248,14 +248,6 @@ void xprt_release_rqst_cong(struct rpc_task *task);
void xprt_disconnect(struct rpc_xprt *xprt);
/*
- * Socket transport setup operations
- */
-struct rpc_xprt * xs_setup_udp(struct rpc_xprtsock_create *args);
-struct rpc_xprt * xs_setup_tcp(struct rpc_xprtsock_create *args);
-int init_socket_xprt(void);
-void cleanup_socket_xprt(void);
-
-/*
* Reserved bit positions in xprt->state
*/
#define XPRT_LOCKED (0)
diff --git a/include/linux/sunrpc/xprtrdma.h b/include/linux/sunrpc/xprtrdma.h
new file mode 100644
index 00000000000..4de56b1d372
--- /dev/null
+++ b/include/linux/sunrpc/xprtrdma.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRTRDMA_H
+#define _LINUX_SUNRPC_XPRTRDMA_H
+
+/*
+ * RPC transport identifier for RDMA
+ */
+#define XPRT_TRANSPORT_RDMA 256
+
+/*
+ * rpcbind (v3+) RDMA netid.
+ */
+#define RPCBIND_NETID_RDMA "rdma"
+
+/*
+ * Constants. Max RPC/NFS header is big enough to account for
+ * additional marshaling buffers passed down by Linux client.
+ *
+ * RDMA header is currently fixed max size, and is big enough for a
+ * fully-chunked NFS message (read chunks are the largest). Note only
+ * a single chunk type per message is supported currently.
+ */
+#define RPCRDMA_MIN_SLOT_TABLE (2U)
+#define RPCRDMA_DEF_SLOT_TABLE (32U)
+#define RPCRDMA_MAX_SLOT_TABLE (256U)
+
+#define RPCRDMA_DEF_INLINE (1024) /* default inline max */
+
+#define RPCRDMA_INLINE_PAD_THRESH (512)/* payload threshold to pad (bytes) */
+
+#define RDMA_RESOLVE_TIMEOUT (5*HZ) /* TBD 5 seconds */
+#define RDMA_CONNECT_RETRY_MAX (2) /* retries if no listener backlog */
+
+/* memory registration strategies */
+#define RPCRDMA_PERSISTENT_REGISTRATION (1)
+
+enum rpcrdma_memreg {
+ RPCRDMA_BOUNCEBUFFERS = 0,
+ RPCRDMA_REGISTER,
+ RPCRDMA_MEMWINDOWS,
+ RPCRDMA_MEMWINDOWS_ASYNC,
+ RPCRDMA_MTHCAFMR,
+ RPCRDMA_ALLPHYSICAL,
+ RPCRDMA_LAST
+};
+
+#endif /* _LINUX_SUNRPC_XPRTRDMA_H */
diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h
new file mode 100644
index 00000000000..2c6c2c2783d
--- /dev/null
+++ b/include/linux/sunrpc/xprtsock.h
@@ -0,0 +1,51 @@
+/*
+ * linux/include/linux/sunrpc/xprtsock.h
+ *
+ * Declarations for the RPC transport socket provider.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRTSOCK_H
+#define _LINUX_SUNRPC_XPRTSOCK_H
+
+#ifdef __KERNEL__
+
+/*
+ * Socket transport setup operations
+ */
+struct rpc_xprt *xs_setup_udp(struct xprt_create *args);
+struct rpc_xprt *xs_setup_tcp(struct xprt_create *args);
+
+int init_socket_xprt(void);
+void cleanup_socket_xprt(void);
+
+/*
+ * RPC transport identifiers for UDP, TCP
+ *
+ * To preserve compatibility with the historical use of raw IP protocol
+ * id's for transport selection, these are specified with the previous
+ * values. No such restriction exists for new transports, except that
+ * they may not collide with these values (17 and 6, respectively).
+ */
+#define XPRT_TRANSPORT_UDP IPPROTO_UDP
+#define XPRT_TRANSPORT_TCP IPPROTO_TCP
+
+/*
+ * RPC slot table sizes for UDP, TCP transports
+ */
+extern unsigned int xprt_udp_slot_table_entries;
+extern unsigned int xprt_tcp_slot_table_entries;
+
+/*
+ * Parameters for choosing a free port
+ */
+extern unsigned int xprt_min_resvport;
+extern unsigned int xprt_max_resvport;
+
+#define RPC_MIN_RESVPORT (1U)
+#define RPC_MAX_RESVPORT (65535U)
+#define RPC_DEF_MIN_RESVPORT (665U)
+#define RPC_DEF_MAX_RESVPORT (1023U)
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index be8228e50a2..149ab62329e 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -3,6 +3,8 @@
*
* Copyright (c) 2001,2002 Patrick Mochel
* Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
*
* Please see Documentation/filesystems/sysfs.txt for more information.
*/
@@ -17,23 +19,20 @@
struct kobject;
struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
/* FIXME
* The *owner field is no longer used, but leave around
* until the tree gets cleaned up fully.
*/
struct attribute {
- const char * name;
- struct module * owner;
+ const char *name;
+ struct module *owner;
mode_t mode;
};
struct attribute_group {
- const char * name;
- struct attribute ** attrs;
+ const char *name;
+ struct attribute **attrs;
};
@@ -77,72 +76,41 @@ struct sysfs_ops {
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
-#define SYSFS_TYPE_MASK 0x00ff
-#define SYSFS_ROOT 0x0001
-#define SYSFS_DIR 0x0002
-#define SYSFS_KOBJ_ATTR 0x0004
-#define SYSFS_KOBJ_BIN_ATTR 0x0008
-#define SYSFS_KOBJ_LINK 0x0020
-#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
-
-#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
-#define SYSFS_FLAG_REMOVED 0x0100
-
#ifdef CONFIG_SYSFS
-extern int sysfs_schedule_callback(struct kobject *kobj,
- void (*func)(void *), void *data, struct module *owner);
-
-extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
-
-extern void
-sysfs_remove_dir(struct kobject *);
-
-extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
- const char *new_name);
-
-extern int __must_check
-sysfs_move_dir(struct kobject *, struct kobject *);
-
-extern int __must_check
-sysfs_create_file(struct kobject *, const struct attribute *);
+int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
+ void *data, struct module *owner);
-extern int __must_check
-sysfs_update_file(struct kobject *, const struct attribute *);
+int __must_check sysfs_create_dir(struct kobject *kobj);
+void sysfs_remove_dir(struct kobject *kobj);
+int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
+int __must_check sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj);
-extern int __must_check
-sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
-
-extern void
-sysfs_remove_file(struct kobject *, const struct attribute *);
-
-extern int __must_check
-sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name);
-
-extern void
-sysfs_remove_link(struct kobject *, const char * name);
+int __must_check sysfs_create_file(struct kobject *kobj,
+ const struct attribute *attr);
+int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
+ mode_t mode);
+void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
int __must_check sysfs_create_bin_file(struct kobject *kobj,
- struct bin_attribute *attr);
+ struct bin_attribute *attr);
void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
-int __must_check sysfs_create_group(struct kobject *,
- const struct attribute_group *);
-void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ const char *name);
+void sysfs_remove_link(struct kobject *kobj, const char *name);
+
+int __must_check sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp);
+void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp);
int sysfs_add_file_to_group(struct kobject *kobj,
- const struct attribute *attr, const char *group);
+ const struct attribute *attr, const char *group);
void sysfs_remove_file_from_group(struct kobject *kobj,
- const struct attribute *attr, const char *group);
-
-void sysfs_notify(struct kobject * k, char *dir, char *attr);
-
+ const struct attribute *attr, const char *group);
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
- void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
+void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
extern int __must_check sysfs_init(void);
@@ -154,75 +122,76 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
return -ENOSYS;
}
-static inline int sysfs_create_dir(struct kobject *kobj,
- struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject *kobj)
{
return 0;
}
-static inline void sysfs_remove_dir(struct kobject * k)
+static inline void sysfs_remove_dir(struct kobject *kobj)
{
;
}
-static inline int sysfs_rename_dir(struct kobject *kobj,
- struct sysfs_dirent *new_parent_sd,
- const char *new_name)
+static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
{
return 0;
}
-static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent)
+static inline int sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj)
{
return 0;
}
-static inline int sysfs_create_file(struct kobject * k, const struct attribute * a)
+static inline int sysfs_create_file(struct kobject *kobj,
+ const struct attribute *attr)
{
return 0;
}
-static inline int sysfs_update_file(struct kobject * k, const struct attribute * a)
-{
- return 0;
-}
-static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+static inline int sysfs_chmod_file(struct kobject *kobj,
+ struct attribute *attr, mode_t mode)
{
return 0;
}
-static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
+static inline void sysfs_remove_file(struct kobject *kobj,
+ const struct attribute *attr)
{
;
}
-static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n)
+static inline int sysfs_create_bin_file(struct kobject *kobj,
+ struct bin_attribute *attr)
{
return 0;
}
-static inline void sysfs_remove_link(struct kobject * k, const char * name)
+static inline int sysfs_remove_bin_file(struct kobject *kobj,
+ struct bin_attribute *attr)
{
- ;
+ return 0;
}
-
-static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
+static inline int sysfs_create_link(struct kobject *kobj,
+ struct kobject *target, const char *name)
{
return 0;
}
-static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a)
+static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
{
- return 0;
+ ;
}
-static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g)
+static inline int sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
{
return 0;
}
-static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
+static inline void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp)
{
;
}
@@ -238,14 +207,8 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj,
{
}
-static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
-{
-}
-
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
- void * (*follow_link)(struct dentry *, struct nameidata *))
+static inline void sysfs_notify(struct kobject *kobj, char *dir, char *attr)
{
- return 0;
}
static inline int __must_check sysfs_init(void)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index c5b94c1a5ee..bac17c59b24 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -315,7 +315,7 @@ struct tcp_sock {
*/
u32 snd_ssthresh; /* Slow start size threshold */
u32 snd_cwnd; /* Sending congestion window */
- u16 snd_cwnd_cnt; /* Linear increase counter */
+ u32 snd_cwnd_cnt; /* Linear increase counter */
u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */
u32 snd_cwnd_used;
u32 snd_cwnd_stamp;
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 525d437b125..47729f18bfd 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -159,15 +159,14 @@
.imbalance_pct = 125, \
.cache_nice_tries = 1, \
.busy_idx = 2, \
- .idle_idx = 0, \
- .newidle_idx = 0, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
.wake_idx = 1, \
.forkexec_idx = 1, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_NEWIDLE \
| SD_BALANCE_EXEC \
| SD_WAKE_AFFINE \
- | SD_WAKE_IDLE \
| BALANCE_FOR_PKG_POWER,\
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6570719eafd..60478f6e5dc 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -21,7 +21,6 @@
* (Note: the *_driver.minor_start values 1, 64, 128, 192 are
* hardcoded at present.)
*/
-#define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
#define NR_LDISCS 17
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 4f33a58fa9d..c5c8f169d3c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -52,6 +52,7 @@ struct ep_device;
* @ep_dev: ep_device for sysfs info
* @extra: descriptors following this endpoint in the configuration
* @extralen: how many bytes of "extra" are valid
+ * @enabled: URBs may be submitted to this endpoint
*
* USB requests are always queued to a given endpoint, identified by a
* descriptor within an active interface in a given USB configuration.
@@ -64,6 +65,7 @@ struct usb_host_endpoint {
unsigned char *extra; /* Extra descriptors */
int extralen;
+ int enabled;
};
/* host-side wrapper for one interface setting's parsed descriptors */
@@ -344,6 +346,11 @@ struct usb_tt;
*
* Usbcore drivers should not set usbdev->state directly. Instead use
* usb_set_device_state().
+ *
+ * @authorized: (user space) policy determines if we authorize this
+ * device to be used or not. By default, wired USB
+ * devices are authorized. WUSB devices are not, until we
+ * authorize them from user space. FIXME -- complete doc
*/
struct usb_device {
int devnum; /* Address on USB bus */
@@ -376,8 +383,11 @@ struct usb_device {
u8 portnum; /* Parent port number (origin 1) */
u8 level; /* Number of USB hub ancestors */
+ unsigned can_submit:1; /* URBs may be submitted */
unsigned discon_suspended:1; /* Disconnected while suspended */
unsigned have_langid:1; /* whether string_langid is valid */
+ unsigned authorized:1; /* Policy has determined we can use it */
+ unsigned wusb:1; /* Device is Wireless USB */
int string_langid; /* language ID for strings */
/* static strings from the device */
@@ -405,6 +415,7 @@ struct usb_device {
int pm_usage_cnt; /* usage counter for autosuspend */
u32 quirks; /* quirks of the whole device */
+ atomic_t urbnum; /* number of URBs submitted for the whole device */
#ifdef CONFIG_PM
struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -419,6 +430,7 @@ struct usb_device {
unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */
unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
unsigned autoresume_disabled:1; /* disabled by the user */
+ unsigned skip_sys_resume:1; /* skip the next system resume */
#endif
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -555,6 +567,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
/*-------------------------------------------------------------------------*/
/**
+ * usb_endpoint_num - get the endpoint's number
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's number: 0 to 15.
+ */
+static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+ return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+/**
+ * usb_endpoint_type - get the endpoint's transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
+ * to @epd's transfer type.
+ */
+static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
+{
+ return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+}
+
+/**
* usb_endpoint_dir_in - check if the endpoint has IN direction
* @epd: endpoint to be checked
*
@@ -996,6 +1031,8 @@ extern int usb_disabled(void);
/*
* urb->transfer_flags:
+ *
+ * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
*/
#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame
@@ -1008,6 +1045,10 @@ extern int usb_disabled(void);
* needed */
#define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */
+#define URB_DIR_IN 0x0200 /* Transfer from device to host */
+#define URB_DIR_OUT 0
+#define URB_DIR_MASK URB_DIR_IN
+
struct usb_iso_packet_descriptor {
unsigned int offset;
unsigned int length; /* expected length */
@@ -1037,6 +1078,8 @@ typedef void (*usb_complete_t)(struct urb *);
* @urb_list: For use by current owner of the URB.
* @anchor_list: membership in the list of an anchor
* @anchor: to anchor URBs to a common mooring
+ * @ep: Points to the endpoint's data structure. Will eventually
+ * replace @pipe.
* @pipe: Holds endpoint number, direction, type, and more.
* Create these values with the eight macros available;
* usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
@@ -1201,10 +1244,10 @@ struct urb
{
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
- spinlock_t lock; /* lock for the URB */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
u8 reject; /* submissions will fail */
+ int unlinked; /* unlink error code */
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
@@ -1212,6 +1255,7 @@ struct urb
struct list_head anchor_list; /* the URB may be anchored by the driver */
struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
+ struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
@@ -1257,7 +1301,6 @@ static inline void usb_fill_control_urb (struct urb *urb,
usb_complete_t complete_fn,
void *context)
{
- spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
@@ -1288,7 +1331,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
usb_complete_t complete_fn,
void *context)
{
- spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
@@ -1324,7 +1366,6 @@ static inline void usb_fill_int_urb (struct urb *urb,
void *context,
int interval)
{
- spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
@@ -1352,6 +1393,30 @@ extern void usb_unanchor_urb(struct urb *urb);
extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
unsigned int timeout);
+/**
+ * usb_urb_dir_in - check if an URB describes an IN transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_in(struct urb *urb)
+{
+ return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN;
+}
+
+/**
+ * usb_urb_dir_out - check if an URB describes an OUT transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_out(struct urb *urb)
+{
+ return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
+}
+
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
gfp_t mem_flags, dma_addr_t *dma);
void usb_buffer_free (struct usb_device *dev, size_t size,
@@ -1364,13 +1429,13 @@ void usb_buffer_unmap (struct urb *urb);
#endif
struct scatterlist;
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int nents);
#if 0
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents);
#endif
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents);
/*-------------------------------------------------------------------*
diff --git a/include/linux/usb_gadget.h b/include/linux/usb/gadget.h
index 4f59b2aa8a9..46705e91573 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb/gadget.h
@@ -1,5 +1,5 @@
/*
- * <linux/usb_gadget.h>
+ * <linux/usb/gadget.h>
*
* We call the USB code inside a Linux-based peripheral device a "gadget"
* driver, except for the hardware-specific bus glue. One USB host can
@@ -22,10 +22,10 @@ struct usb_ep;
/**
* struct usb_request - describes one i/o request
* @buf: Buffer used for data. Always provide this; some controllers
- * only use PIO, or don't use DMA for some endpoints.
+ * only use PIO, or don't use DMA for some endpoints.
* @dma: DMA address corresponding to 'buf'. If you don't set this
- * field, and the usb controller needs one, it is responsible
- * for mapping and unmapping the buffer.
+ * field, and the usb controller needs one, it is responsible
+ * for mapping and unmapping the buffer.
* @length: Length of that data
* @no_interrupt: If true, hints that no completion irq is needed.
* Helpful sometimes with deep request queues that are handled
@@ -45,16 +45,16 @@ struct usb_ep;
* @context: For use by the completion callback
* @list: For use by the gadget driver.
* @status: Reports completion code, zero or a negative errno.
- * Normally, faults block the transfer queue from advancing until
- * the completion callback returns.
- * Code "-ESHUTDOWN" indicates completion caused by device disconnect,
- * or when the driver disabled the endpoint.
+ * Normally, faults block the transfer queue from advancing until
+ * the completion callback returns.
+ * Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ * or when the driver disabled the endpoint.
* @actual: Reports bytes transferred to/from the buffer. For reads (OUT
- * transfers) this may be less than the requested length. If the
- * short_not_ok flag is set, short reads are treated as errors
- * even when status otherwise indicates successful completion.
- * Note that for writes (IN transfers) some data bytes may still
- * reside in a device-side FIFO when the request is reported as
+ * transfers) this may be less than the requested length. If the
+ * short_not_ok flag is set, short reads are treated as errors
+ * even when status otherwise indicates successful completion.
+ * Note that for writes (IN transfers) some data bytes may still
+ * reside in a device-side FIFO when the request is reported as
* complete.
*
* These are allocated/freed through the endpoint they're used with. The
@@ -128,7 +128,7 @@ struct usb_ep_ops {
* value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint.
* @driver_data:for use by the gadget driver. all other fields are
- * read-only to gadget drivers.
+ * read-only to gadget drivers.
*
* the bus controller driver lists all the general purpose endpoints in
* gadget->ep_list. the control endpoint (gadget->ep0) is not in that list,
@@ -148,10 +148,10 @@ struct usb_ep {
/**
* usb_ep_enable - configure endpoint, making it usable
* @ep:the endpoint being configured. may not be the endpoint named "ep0".
- * drivers discover endpoints through the ep_list of a usb_gadget.
+ * drivers discover endpoints through the ep_list of a usb_gadget.
* @desc:descriptor for desired behavior. caller guarantees this pointer
- * remains valid until the endpoint is disabled; the data byte order
- * is little-endian (usb-standard).
+ * remains valid until the endpoint is disabled; the data byte order
+ * is little-endian (usb-standard).
*
* when configurations are set, or when interface settings change, the driver
* will enable or disable the relevant endpoints. while it is enabled, an
@@ -232,7 +232,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
* @ep:the endpoint associated with the request
* @req:the request being submitted
* @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
- * pre-allocate all necessary memory with the request.
+ * pre-allocate all necessary memory with the request.
*
* This tells the device controller to perform the specified request through
* that endpoint (reading or writing a buffer). When the request completes,
@@ -415,7 +415,7 @@ struct usb_gadget_ops {
* struct usb_gadget - represents a usb slave device
* @ops: Function pointers used to access hardware-specific operations.
* @ep0: Endpoint zero, used when reading or writing responses to
- * driver setup() requests
+ * driver setup() requests
* @ep_list: List of other endpoints supported by the device.
* @speed: Speed of current connection to USB host.
* @is_dualspeed: True if the controller supports both high and full speed
@@ -432,7 +432,7 @@ struct usb_gadget_ops {
* @b_hnp_enable: OTG device feature flag, indicating that the A-Host
* enabled HNP support.
* @name: Identifies the controller hardware type. Used in diagnostics
- * and sometimes configuration.
+ * and sometimes configuration.
* @dev: Driver model state for this abstract device.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
@@ -480,6 +480,39 @@ static inline void *get_gadget_data (struct usb_gadget *gadget)
/**
+ * gadget_is_dualspeed - return true iff the hardware handles high speed
+ * @gadget: controller that might support both high and full speeds
+ */
+static inline int gadget_is_dualspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ /* runtime test would check "g->is_dualspeed" ... that might be
+ * useful to work around hardware bugs, but is mostly pointless
+ */
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/**
+ * gadget_is_otg - return true iff the hardware is OTG-ready
+ * @gadget: controller that might have a Mini-AB connector
+ *
+ * This is a runtime test, since kernels with a USB-OTG stack sometimes
+ * run on boards which only have a Mini-B (or Mini-A) connector.
+ */
+static inline int gadget_is_otg(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_OTG
+ return g->is_otg;
+#else
+ return 0;
+#endif
+}
+
+
+/**
* usb_gadget_frame_number - returns the current frame number
* @gadget: controller that reports the frame number
*
@@ -655,23 +688,23 @@ usb_gadget_disconnect (struct usb_gadget *gadget)
* @function: String describing the gadget's function
* @speed: Highest speed the driver handles.
* @bind: Invoked when the driver is bound to a gadget, usually
- * after registering the driver.
- * At that point, ep0 is fully initialized, and ep_list holds
- * the currently-available endpoints.
- * Called in a context that permits sleeping.
+ * after registering the driver.
+ * At that point, ep0 is fully initialized, and ep_list holds
+ * the currently-available endpoints.
+ * Called in a context that permits sleeping.
* @setup: Invoked for ep0 control requests that aren't handled by
- * the hardware level driver. Most calls must be handled by
- * the gadget driver, including descriptor and configuration
- * management. The 16 bit members of the setup data are in
- * USB byte order. Called in_interrupt; this may not sleep. Driver
+ * the hardware level driver. Most calls must be handled by
+ * the gadget driver, including descriptor and configuration
+ * management. The 16 bit members of the setup data are in
+ * USB byte order. Called in_interrupt; this may not sleep. Driver
* queues a response to ep0, or returns negative to stall.
* @disconnect: Invoked after all transfers have been stopped,
- * when the host is disconnected. May be called in_interrupt; this
- * may not sleep. Some devices can't detect disconnect, so this might
+ * when the host is disconnected. May be called in_interrupt; this
+ * may not sleep. Some devices can't detect disconnect, so this might
* not be called except as part of controller shutdown.
* @unbind: Invoked when the driver is unbound from a gadget,
- * usually from rmmod (after a disconnect is reported).
- * Called in a context that permits sleeping.
+ * usually from rmmod (after a disconnect is reported).
+ * Called in a context that permits sleeping.
* @suspend: Invoked on USB suspend. May be called in_interrupt.
* @resume: Invoked on USB resume. May be called in_interrupt.
* @driver: Driver model state for this driver.
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 8da374caf58..2692ec9389c 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -4,11 +4,8 @@
* belong here.
*/
-/* device must not be autosuspended */
-#define USB_QUIRK_NO_AUTOSUSPEND 0x00000001
-
/* string descriptors must not be fetched using a 255-byte read */
-#define USB_QUIRK_STRING_FETCH_255 0x00000002
+#define USB_QUIRK_STRING_FETCH_255 0x00000001
/* device can't resume correctly so reset it instead */
-#define USB_QUIRK_RESET_RESUME 0x00000004
+#define USB_QUIRK_RESET_RESUME 0x00000002
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index e8b8928232c..488ce128885 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -141,7 +141,7 @@ struct usb_serial {
};
#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
-#define NUM_DONT_CARE (-1)
+#define NUM_DONT_CARE 99
/* get and set the serial private data pointer helper functions */
static inline void *usb_get_serial_data (struct usb_serial *serial)
@@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
* in the syslog messages when a device is inserted or removed.
* @id_table: pointer to a list of usb_device_id structures that define all
* of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- * have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- * have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
+ * @num_interrupt_in: If a device doesn't have this many interrupt-in
+ * endpoints, it won't be sent to the driver's attach() method.
+ * (But it might still be sent to the probe() method.)
+ * @num_interrupt_out: If a device doesn't have this many interrupt-out
+ * endpoints, it won't be sent to the driver's attach() method.
+ * (But it might still be sent to the probe() method.)
+ * @num_bulk_in: If a device doesn't have this many bulk-in
+ * endpoints, it won't be sent to the driver's attach() method.
+ * (But it might still be sent to the probe() method.)
+ * @num_bulk_out: If a device doesn't have this many bulk-out
+ * endpoints, it won't be sent to the driver's attach() method.
+ * (But it might still be sent to the probe() method.)
* @num_ports: the number of different ports this device will have.
* @calc_num_ports: pointer to a function to determine how many ports this
* device has dynamically. It will be called after the probe()
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
deleted file mode 100644
index 4f2d012d730..00000000000
--- a/include/linux/usb_sl811.h
+++ /dev/null
@@ -1,26 +0,0 @@
-
-/*
- * board initialization should put one of these into dev->platform_data
- * and place the sl811hs onto platform_bus named "sl811-hcd".
- */
-
-struct sl811_platform_data {
- unsigned can_wakeup:1;
-
- /* given port_power, msec/2 after power on till power good */
- u8 potpg;
-
- /* mA/2 power supplied on this port (max = default = 250) */
- u8 power;
-
- /* sl811 relies on an external source of VBUS current */
- void (*port_power)(struct device *dev, int is_on);
-
- /* pulse sl811 nRST (probably with a GPIO) */
- void (*reset)(struct device *dev);
-
- // some boards need something like these:
- // int (*check_overcurrent)(struct device *dev);
- // void (*clock_enable)(struct device *dev, int is_on);
-};
-
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
index e63e0c03ee0..2fb46bc9340 100644
--- a/include/linux/video_output.h
+++ b/include/linux/video_output.h
@@ -31,9 +31,9 @@ struct output_properties {
struct output_device {
int request_state;
struct output_properties *props;
- struct class_device class_dev;
+ struct device dev;
};
-#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+#define to_output_device(obj) container_of(obj, struct output_device, dev)
struct output_device *video_output_register(const char *name,
struct device *dev,
void *devdata,
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index c7c3337c3a8..d1321a81c9c 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -62,8 +62,6 @@ struct writeback_control {
unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned for_writepages:1; /* This is a writepages() call */
unsigned range_cyclic:1; /* range_start is cyclic */
-
- void *fs_private; /* For use by ->writepages() */
};
/*
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index 9fa09fb800a..0fa5d591255 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -133,7 +133,7 @@ struct videobuf_qtype_ops {
enum v4l2_memory memory);
int (*sync) (struct videobuf_queue* q,
struct videobuf_buffer *buf);
- int (*copy_to_user) (struct videobuf_queue *q,
+ int (*video_copy_to_user)(struct videobuf_queue *q,
char __user *data,
size_t count,
int nonblocking);
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
new file mode 100644
index 00000000000..911c2cd0294
--- /dev/null
+++ b/include/net/inet_frag.h
@@ -0,0 +1,60 @@
+#ifndef __NET_FRAG_H__
+#define __NET_FRAG_H__
+
+struct inet_frag_queue {
+ struct hlist_node list;
+ struct list_head lru_list; /* lru list member */
+ spinlock_t lock;
+ atomic_t refcnt;
+ struct timer_list timer; /* when will this queue expire? */
+ struct sk_buff *fragments; /* list of received fragments */
+ ktime_t stamp;
+ int len; /* total length of orig datagram */
+ int meat;
+ __u8 last_in; /* first/last segment arrived? */
+
+#define COMPLETE 4
+#define FIRST_IN 2
+#define LAST_IN 1
+};
+
+#define INETFRAGS_HASHSZ 64
+
+struct inet_frags_ctl {
+ int high_thresh;
+ int low_thresh;
+ int timeout;
+ int secret_interval;
+};
+
+struct inet_frags {
+ struct list_head lru_list;
+ struct hlist_head hash[INETFRAGS_HASHSZ];
+ rwlock_t lock;
+ u32 rnd;
+ int nqueues;
+ int qsize;
+ atomic_t mem;
+ struct timer_list secret_timer;
+ struct inet_frags_ctl *ctl;
+
+ unsigned int (*hashfn)(struct inet_frag_queue *);
+ void (*destructor)(struct inet_frag_queue *);
+ void (*skb_free)(struct sk_buff *);
+};
+
+void inet_frags_init(struct inet_frags *);
+void inet_frags_fini(struct inet_frags *);
+
+void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
+void inet_frag_destroy(struct inet_frag_queue *q,
+ struct inet_frags *f, int *work);
+int inet_frag_evictor(struct inet_frags *f);
+
+static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
+{
+ if (atomic_dec_and_test(&q->refcnt))
+ inet_frag_destroy(q, f, NULL);
+}
+
+#endif
diff --git a/include/net/ip.h b/include/net/ip.h
index 3af3ed9d320..840dd91b513 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -160,6 +160,7 @@ DECLARE_SNMP_STAT(struct ipstats_mib, ip_statistics);
#define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field)
#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field)
#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field)
+#define IP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ip_statistics, field, val)
DECLARE_SNMP_STAT(struct linux_mib, net_statistics);
#define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field)
#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field)
@@ -177,10 +178,8 @@ extern int sysctl_ip_default_ttl;
extern int sysctl_ip_nonlocal_bind;
/* From ip_fragment.c */
-extern int sysctl_ipfrag_high_thresh;
-extern int sysctl_ipfrag_low_thresh;
-extern int sysctl_ipfrag_time;
-extern int sysctl_ipfrag_secret_interval;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl ip4_frags_ctl;
extern int sysctl_ipfrag_max_dist;
/* From inetpeer.c */
@@ -332,9 +331,9 @@ enum ip_defrag_users
IP_DEFRAG_VS_FWD
};
-struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
-extern int ip_frag_nqueues;
-extern atomic_t ip_frag_mem;
+int ip_defrag(struct sk_buff *skb, u32 user);
+int ip_frag_mem(void);
+int ip_frag_nqueues(void);
/*
* Functions provided by ip_forward.c
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 672564e5a81..41870564df8 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -464,10 +464,10 @@ struct ip_vs_protocol {
unsigned int proto_off,
int inverse);
- int (*snat_handler)(struct sk_buff **pskb,
+ int (*snat_handler)(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
- int (*dnat_handler)(struct sk_buff **pskb,
+ int (*dnat_handler)(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
@@ -654,11 +654,11 @@ struct ip_vs_app
/* output hook: return false if can't linearize. diff set for TCP. */
int (*pkt_out)(struct ip_vs_app *, struct ip_vs_conn *,
- struct sk_buff **, int *diff);
+ struct sk_buff *, int *diff);
/* input hook: return false if can't linearize. diff set for TCP. */
int (*pkt_in)(struct ip_vs_app *, struct ip_vs_conn *,
- struct sk_buff **, int *diff);
+ struct sk_buff *, int *diff);
/* ip_vs_app initializer */
int (*init_conn)(struct ip_vs_app *, struct ip_vs_conn *);
@@ -832,8 +832,8 @@ register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port);
extern int ip_vs_app_inc_get(struct ip_vs_app *inc);
extern void ip_vs_app_inc_put(struct ip_vs_app *inc);
-extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff **pskb);
-extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff **pskb);
+extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb);
+extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
extern int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
char *o_buf, int o_len, char *n_buf, int n_len);
extern int ip_vs_app_init(void);
@@ -984,7 +984,6 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
return fwd;
}
-extern int ip_vs_make_skb_writable(struct sk_buff **pskb, int len);
extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int dir);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 31b3f1b45a2..cc796cbc1b2 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -120,12 +120,21 @@ extern int sysctl_mld_max_msf;
SNMP_INC_STATS##modifier(statname##_statistics, (field)); \
})
+#define _DEVADD(statname, modifier, idev, field, val) \
+({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_ADD_STATS##modifier((_idev)->stats.statname, (field), (val)); \
+ SNMP_ADD_STATS##modifier(statname##_statistics, (field), (val));\
+})
+
/* MIBs */
DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
#define IP6_INC_STATS(idev,field) _DEVINC(ipv6, , idev, field)
#define IP6_INC_STATS_BH(idev,field) _DEVINC(ipv6, _BH, idev, field)
#define IP6_INC_STATS_USER(idev,field) _DEVINC(ipv6, _USER, idev, field)
+#define IP6_ADD_STATS_BH(idev,field,val) _DEVADD(ipv6, _BH, idev, field, val)
DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
@@ -240,7 +249,7 @@ extern int ip6_ra_control(struct sock *sk, int sel,
void (*destructor)(struct sock *));
-extern int ipv6_parse_hopopts(struct sk_buff **skbp);
+extern int ipv6_parse_hopopts(struct sk_buff *skb);
extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
@@ -252,8 +261,8 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
-extern int ip6_frag_nqueues;
-extern atomic_t ip6_frag_mem;
+int ip6_frag_nqueues(void);
+int ip6_frag_mem(void);
#define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */
@@ -565,10 +574,8 @@ extern int inet6_hash_connect(struct inet_timewait_death_row *death_row,
/*
* reassembly.c
*/
-extern int sysctl_ip6frag_high_thresh;
-extern int sysctl_ip6frag_low_thresh;
-extern int sysctl_ip6frag_time;
-extern int sysctl_ip6frag_secret_interval;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl ip6_frags_ctl;
extern const struct proto_ops inet6_stream_ops;
extern const struct proto_ops inet6_dgram_ops;
diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
index 070d12cb463..f703533fb4d 100644
--- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
@@ -15,8 +15,7 @@ extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
struct net_device *out,
int (*okfn)(struct sk_buff *));
-extern unsigned int nf_ct_frag6_timeout;
-extern unsigned int nf_ct_frag6_low_thresh;
-extern unsigned int nf_ct_frag6_high_thresh;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl nf_frags_ctl;
#endif /* _NF_CONNTRACK_IPV6_H*/
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 4056f5f08da..a532e7b5ed6 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -22,7 +22,7 @@
of connection tracking. */
extern unsigned int nf_conntrack_in(int pf,
unsigned int hooknum,
- struct sk_buff **pskb);
+ struct sk_buff *skb);
extern int nf_conntrack_init(void);
extern void nf_conntrack_cleanup(void);
@@ -60,17 +60,17 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
extern struct nf_conntrack_tuple_hash *
nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple);
-extern int __nf_conntrack_confirm(struct sk_buff **pskb);
+extern int __nf_conntrack_confirm(struct sk_buff *skb);
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
-static inline int nf_conntrack_confirm(struct sk_buff **pskb)
+static inline int nf_conntrack_confirm(struct sk_buff *skb)
{
- struct nf_conn *ct = (struct nf_conn *)(*pskb)->nfct;
+ struct nf_conn *ct = (struct nf_conn *)skb->nfct;
int ret = NF_ACCEPT;
if (ct) {
if (!nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
- ret = __nf_conntrack_confirm(pskb);
+ ret = __nf_conntrack_confirm(skb);
nf_ct_deliver_cached_events(ct);
}
return ret;
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 0dcc4c828ce..d7b2d5483a7 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -29,7 +29,7 @@ struct nf_conntrack_helper
/* Function to call when data passes; return verdict, or -1 to
invalidate. */
- int (*help)(struct sk_buff **pskb,
+ int (*help)(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info conntrackinfo);
diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h
index c3cd127ba4b..f29eeb9777e 100644
--- a/include/net/netfilter/nf_nat_core.h
+++ b/include/net/netfilter/nf_nat_core.h
@@ -10,12 +10,12 @@
extern unsigned int nf_nat_packet(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
- struct sk_buff **pskb);
+ struct sk_buff *skb);
extern int nf_nat_icmp_reply_translation(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
- struct sk_buff **pskb);
+ struct sk_buff *skb);
static inline int nf_nat_initialized(struct nf_conn *ct,
enum nf_nat_manip_type manip)
diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h
index ec98ecf95fc..58dd2268794 100644
--- a/include/net/netfilter/nf_nat_helper.h
+++ b/include/net/netfilter/nf_nat_helper.h
@@ -7,21 +7,21 @@
struct sk_buff;
/* These return true or false. */
-extern int nf_nat_mangle_tcp_packet(struct sk_buff **skb,
+extern int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
-extern int nf_nat_mangle_udp_packet(struct sk_buff **skb,
+extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
-extern int nf_nat_seq_adjust(struct sk_buff **pskb,
+extern int nf_nat_seq_adjust(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index 14c7b2d7263..04578bfe23e 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -18,7 +18,7 @@ struct nf_nat_protocol
/* Translate a packet to the target according to manip type.
Return true if succeeded. */
- int (*manip_pkt)(struct sk_buff **pskb,
+ int (*manip_pkt)(struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype);
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index f9743187d57..75d1825031d 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -6,7 +6,7 @@
extern int nf_nat_rule_init(void) __init;
extern void nf_nat_rule_cleanup(void);
-extern int nf_nat_rule_find(struct sk_buff **pskb,
+extern int nf_nat_rule_find(struct sk_buff *skb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 105bf12b0c7..1166ffb4b3e 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -45,7 +45,7 @@ struct net_protocol {
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_protocol
{
- int (*handler)(struct sk_buff **skb);
+ int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb,
struct inet6_skb_parm *opt,
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 77be396ca63..0e844845f3f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1051,7 +1051,7 @@ extern int xfrm4_output(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi);
-extern int xfrm6_rcv(struct sk_buff **pskb);
+extern int xfrm6_rcv(struct sk_buff *skb);
extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
xfrm_address_t *saddr, u8 proto);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h
index d143171896a..ba615e4c1d7 100644
--- a/include/scsi/libsrp.h
+++ b/include/scsi/libsrp.h
@@ -59,7 +59,7 @@ extern void srp_target_free(struct srp_target *);
extern struct iu_entry *srp_iu_get(struct srp_target *);
extern void srp_iu_put(struct iu_entry *);
-extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64);
+extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64, u64);
extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
srp_rdma_t, int, int);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 53e170586c2..65ab5145a09 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -33,20 +33,17 @@ struct scsi_cmnd {
struct list_head list; /* scsi_cmnd participates in queue lists */
struct list_head eh_entry; /* entry for the host eh_cmd_q */
int eh_eflags; /* Used by error handlr */
- void (*done) (struct scsi_cmnd *); /* Mid-level done function */
/*
* A SCSI Command is assigned a nonzero serial_number before passed
* to the driver's queue command function. The serial_number is
* cleared when scsi_done is entered indicating that the command
- * has been completed. It currently doesn't have much use other
- * than printk's. Some lldd's use this number for other purposes.
- * It's almost certain that such usages are either incorrect or
- * meaningless. Please kill all usages other than printk's. Also,
- * as this number is always identical to ->pid, please convert
- * printk's to use ->pid, so that we can kill this field.
+ * has been completed. It is a bug for LLDDs to use this number
+ * for purposes other than printk (and even that is only useful
+ * for debugging).
*/
unsigned long serial_number;
+
/*
* This is set to jiffies as it was when the command was first
* allocated. It is used to time how long the command has
@@ -116,7 +113,6 @@ struct scsi_cmnd {
int result; /* Status code from lower level driver */
unsigned char tag; /* SCSI-II queued command tag */
- unsigned long pid; /* Process ID, starts at 0. Unique per host. */
};
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
@@ -124,7 +120,6 @@ extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
struct device *);
-extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index 5a43a4cd96c..e89844cc2cd 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -9,6 +9,8 @@ extern void __scsi_print_command(unsigned char *);
extern void scsi_show_extd_sense(unsigned char, unsigned char);
extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
+extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *,
+ struct scsi_sense_hdr *);
extern void scsi_print_sense(char *, struct scsi_cmnd *);
extern void __scsi_print_sense(const char *name,
const unsigned char *sense_buffer,
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 3465f31a21c..1f5ca7f6211 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -5,14 +5,17 @@
struct module;
struct scsi_cmnd;
+struct scsi_device;
+struct request;
+struct request_queue;
struct scsi_driver {
struct module *owner;
struct device_driver gendrv;
- int (*init_command)(struct scsi_cmnd *);
void (*rescan)(struct device *);
+ int (*done)(struct scsi_cmnd *);
};
#define to_scsi_driver(drv) \
container_of((drv), struct scsi_driver, gendrv)
@@ -25,4 +28,9 @@ extern int scsi_register_interface(struct class_interface *);
#define scsi_unregister_interface(intf) \
class_interface_unregister(intf)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req);
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req);
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req);
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret);
+
#endif /* _SCSI_SCSI_DRIVER_H */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index c5c0f6762a0..44224ba4dd9 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -1,7 +1,7 @@
#ifndef _SCSI_SCSI_EH_H
#define _SCSI_SCSI_EH_H
-struct scsi_cmnd;
+#include <scsi/scsi_cmnd.h>
struct scsi_device;
struct Scsi_Host;
@@ -65,4 +65,25 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
extern int scsi_reset_provider(struct scsi_device *, int);
+struct scsi_eh_save {
+ int result;
+ enum dma_data_direction data_direction;
+ unsigned char cmd_len;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+
+ void *buffer;
+ unsigned bufflen;
+ unsigned short use_sg;
+ int resid;
+
+ struct scatterlist sense_sgl;
+};
+
+extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
+ struct scsi_eh_save *ses, unsigned char *cmnd,
+ int cmnd_size, unsigned sense_bytes);
+
+extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
+ struct scsi_eh_save *ses);
+
#endif /* _SCSI_SCSI_EH_H */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 3b8a6a85c2f..7d210cd6c38 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -32,6 +32,9 @@ struct blk_queue_tags;
#define SG_NONE 0
#define SG_ALL 0xff
+#define MODE_UNKNOWN 0x00
+#define MODE_INITIATOR 0x01
+#define MODE_TARGET 0x02
#define DISABLE_CLUSTERING 0
#define ENABLE_CLUSTERING 1
@@ -145,9 +148,6 @@ struct scsi_host_template {
int (* transfer_response)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
- /* Used as callback for the completion of task management request. */
- int (* tsk_mgmt_response)(u64 mid, int result);
-
/*
* This is an error handling strategy routine. You don't need to
* define one of these if you don't want to - there is a default
@@ -408,6 +408,11 @@ struct scsi_host_template {
unsigned char present;
/*
+ * This specifies the mode that a LLD supports.
+ */
+ unsigned supported_mode:2;
+
+ /*
* true if this host adapter uses unchecked DMA onto an ISA bus.
*/
unsigned unchecked_isa_dma:1;
@@ -575,8 +580,9 @@ struct Scsi_Host {
* Used to assign serial numbers to the cmds.
* Protected by the host lock.
*/
- unsigned long cmd_serial_number, cmd_pid;
+ unsigned long cmd_serial_number;
+ unsigned active_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned use_blk_tcq:1;
diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h
index 4f4427937af..d0fefb96158 100644
--- a/include/scsi/scsi_tgt.h
+++ b/include/scsi/scsi_tgt.h
@@ -11,9 +11,11 @@ struct scsi_lun;
extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
extern void scsi_tgt_free_queue(struct Scsi_Host *);
-extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64);
-extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *,
- void *);
+extern int scsi_tgt_queue_command(struct scsi_cmnd *, u64, struct scsi_lun *, u64);
+extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, u64, int, u64,
+ struct scsi_lun *, void *);
extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
enum dma_data_direction, gfp_t);
extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
+extern int scsi_tgt_it_nexus_create(struct Scsi_Host *, u64, char *);
+extern int scsi_tgt_it_nexus_destroy(struct Scsi_Host *, u64);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index 4cf9dff29a2..f2ee7c238a4 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -23,13 +23,15 @@
#define __SCSI_TARGET_IF_H
/* user -> kernel */
-#define TGT_UEVENT_CMD_RSP 0x0001
-#define TGT_UEVENT_TSK_MGMT_RSP 0x0002
+#define TGT_UEVENT_CMD_RSP 0x0001
+#define TGT_UEVENT_IT_NEXUS_RSP 0x0002
+#define TGT_UEVENT_TSK_MGMT_RSP 0x0003
/* kernel -> user */
-#define TGT_KEVENT_CMD_REQ 0x1001
-#define TGT_KEVENT_CMD_DONE 0x1002
-#define TGT_KEVENT_TSK_MGMT_REQ 0x1003
+#define TGT_KEVENT_CMD_REQ 0x1001
+#define TGT_KEVENT_CMD_DONE 0x1002
+#define TGT_KEVENT_IT_NEXUS_REQ 0x1003
+#define TGT_KEVENT_TSK_MGMT_REQ 0x1004
struct tgt_event_hdr {
uint16_t version;
@@ -46,6 +48,7 @@ struct tgt_event {
struct {
int host_no;
int result;
+ aligned_u64 itn_id;
aligned_u64 tag;
aligned_u64 uaddr;
aligned_u64 sense_uaddr;
@@ -55,15 +58,22 @@ struct tgt_event {
} cmd_rsp;
struct {
int host_no;
- aligned_u64 mid;
int result;
+ aligned_u64 itn_id;
+ aligned_u64 mid;
} tsk_mgmt_rsp;
-
+ struct {
+ __s32 host_no;
+ __s32 result;
+ aligned_u64 itn_id;
+ __u32 function;
+ } it_nexus_rsp;
/* kernel -> user */
struct {
int host_no;
uint32_t data_len;
+ aligned_u64 itn_id;
uint8_t scb[16];
uint8_t lun[8];
int attribute;
@@ -71,16 +81,25 @@ struct tgt_event {
} cmd_req;
struct {
int host_no;
- aligned_u64 tag;
int result;
+ aligned_u64 itn_id;
+ aligned_u64 tag;
} cmd_done;
struct {
int host_no;
int function;
+ aligned_u64 itn_id;
aligned_u64 tag;
uint8_t lun[8];
aligned_u64 mid;
} tsk_mgmt_req;
+ struct {
+ __s32 host_no;
+ __u32 function;
+ aligned_u64 itn_id;
+ __u32 max_cmds;
+ __u8 initiator_id[16];
+ } it_nexus_req;
} p;
} __attribute__ ((aligned (sizeof(uint64_t))));
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index 3c18baa65a7..0dfef752f0e 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -65,6 +65,18 @@ struct scsi_transport_template {
* EH_NOT_HANDLED Begin normal error recovery
*/
enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
+ /*
+ * Used as callback for the completion of i_t_nexus request
+ * for target drivers.
+ */
+ int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+
+ /*
+ * Used as callback for the completion of task management
+ * request for target drivers.
+ */
+ int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
};
#define transport_class_to_shost(tc) \
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index a0d80bcaa93..e466d886e19 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -589,6 +589,10 @@ struct fc_function_template {
int (*vport_disable)(struct fc_vport *, bool);
int (*vport_delete)(struct fc_vport *);
+ /* target-mode drivers' functions */
+ int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
+ int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
u32 dd_fcvport_size;
@@ -632,6 +636,8 @@ struct fc_function_template {
unsigned long show_host_fabric_name:1;
unsigned long show_host_symbolic_name:1;
unsigned long show_host_system_hostname:1;
+
+ unsigned long disable_target_scan:1;
};
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 706c0cd36c1..7ff6199cbd5 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -24,6 +24,8 @@
#define SCSI_TRANSPORT_ISCSI_H
#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
#include <scsi/iscsi_if.h>
struct scsi_transport_template;
diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h
new file mode 100644
index 00000000000..9c60ca1c08c
--- /dev/null
+++ b/include/scsi/scsi_transport_srp.h
@@ -0,0 +1,39 @@
+#ifndef SCSI_TRANSPORT_SRP_H
+#define SCSI_TRANSPORT_SRP_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+#define SRP_RPORT_ROLE_INITIATOR 0
+#define SRP_RPORT_ROLE_TARGET 1
+
+struct srp_rport_identifiers {
+ u8 port_id[16];
+ u8 roles;
+};
+
+struct srp_rport {
+ struct device dev;
+
+ u8 port_id[16];
+ u8 roles;
+};
+
+struct srp_function_template {
+ /* for target drivers */
+ int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
+ int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+};
+
+extern struct scsi_transport_template *
+srp_attach_transport(struct srp_function_template *);
+extern void srp_release_transport(struct scsi_transport_template *);
+
+extern struct srp_rport *srp_rport_add(struct Scsi_Host *,
+ struct srp_rport_identifiers *);
+extern void srp_rport_del(struct srp_rport *);
+
+extern void srp_remove_host(struct Scsi_Host *);
+
+#endif
diff --git a/include/scsi/sd.h b/include/scsi/sd.h
index ce02ad1f518..f7513313ef0 100644
--- a/include/scsi/sd.h
+++ b/include/scsi/sd.h
@@ -47,20 +47,6 @@ struct scsi_disk {
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
-static int sd_revalidate_disk(struct gendisk *disk);
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-static int sd_probe(struct device *);
-static int sd_remove(struct device *);
-static void sd_shutdown(struct device *dev);
-static int sd_suspend(struct device *dev, pm_message_t state);
-static int sd_resume(struct device *dev);
-static void sd_rescan(struct device *);
-static int sd_init_command(struct scsi_cmnd *);
-static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
-static void sd_print_result(struct scsi_disk *, int);
-
#define sd_printk(prefix, sdsk, fmt, a...) \
(sdsk)->disk ? \
sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \
diff --git a/init/Kconfig b/init/Kconfig
index d54d0cadcc0..54f31a191b8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -281,6 +281,27 @@ config CPUSETS
Say N if unsure.
+config FAIR_GROUP_SCHED
+ bool "Fair group CPU scheduler"
+ default y
+ depends on EXPERIMENTAL
+ help
+ This feature lets CPU scheduler recognize task groups and control CPU
+ bandwidth allocation to such task groups.
+
+choice
+ depends on FAIR_GROUP_SCHED
+ prompt "Basis for grouping tasks"
+ default FAIR_USER_SCHED
+
+config FAIR_USER_SCHED
+ bool "user id"
+ help
+ This option will choose userid as the basis for grouping
+ tasks, thus providing equal CPU bandwidth to each user.
+
+endchoice
+
config SYSFS_DEPRECATED
bool "Create deprecated sysfs files"
default y
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 04f3ffb8d9d..0ae703c157b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1525,6 +1525,7 @@ add_names:
context->names[idx].ino = (unsigned long)-1;
}
}
+EXPORT_SYMBOL_GPL(__audit_inode_child);
/**
* auditsc_get_stamp - get local copies of audit_context values
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index 81e69782963..09e9574eeb2 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -119,7 +119,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
* No locking available for sched_info (and too expensive to add one)
* Mitigate by taking snapshot of values
*/
- t1 = tsk->sched_info.pcnt;
+ t1 = tsk->sched_info.pcount;
t2 = tsk->sched_info.run_delay;
t3 = tsk->sched_info.cpu_time;
diff --git a/kernel/exit.c b/kernel/exit.c
index 993369ee94d..7f7959de4a8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -111,6 +111,7 @@ static void __exit_signal(struct task_struct *tsk)
*/
sig->utime = cputime_add(sig->utime, tsk->utime);
sig->stime = cputime_add(sig->stime, tsk->stime);
+ sig->gtime = cputime_add(sig->gtime, tsk->gtime);
sig->min_flt += tsk->min_flt;
sig->maj_flt += tsk->maj_flt;
sig->nvcsw += tsk->nvcsw;
@@ -1242,6 +1243,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
cputime_add(p->stime,
cputime_add(sig->stime,
sig->cstime)));
+ psig->cgtime =
+ cputime_add(psig->cgtime,
+ cputime_add(p->gtime,
+ cputime_add(sig->gtime,
+ sig->cgtime)));
psig->cmin_flt +=
p->min_flt + sig->min_flt + sig->cmin_flt;
psig->cmaj_flt +=
diff --git a/kernel/fork.c b/kernel/fork.c
index 5e67f90a169..3fc3c138391 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -877,6 +877,8 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
sig->tty_old_pgrp = NULL;
sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
+ sig->gtime = cputime_zero;
+ sig->cgtime = cputime_zero;
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
@@ -1045,6 +1047,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->utime = cputime_zero;
p->stime = cputime_zero;
+ p->gtime = cputime_zero;
#ifdef CONFIG_TASK_XACCT
p->rchar = 0; /* I/O counter: bytes read */
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index d0e5c48e18c..6046939d080 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kexec.h>
+#include <linux/sched.h>
#define KERNEL_ATTR_RO(_name) \
static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
@@ -116,6 +117,13 @@ static int __init ksysfs_init(void)
&notes_attr);
}
+ /*
+ * Create "/sys/kernel/uids" directory and corresponding root user's
+ * directory under it.
+ */
+ if (!error)
+ error = uids_kobject_init();
+
return error;
}
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 734da579ad1..a6f1ee9c92d 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -1521,7 +1521,7 @@ cache_hit:
}
static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
- struct held_lock *hlock, int chain_head)
+ struct held_lock *hlock, int chain_head, u64 chain_key)
{
/*
* Trylock needs to maintain the stack of held locks, but it
@@ -1534,7 +1534,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
* graph_lock for us)
*/
if (!hlock->trylock && (hlock->check == 2) &&
- lookup_chain_cache(curr->curr_chain_key, hlock->class)) {
+ lookup_chain_cache(chain_key, hlock->class)) {
/*
* Check whether last held lock:
*
@@ -1576,7 +1576,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
#else
static inline int validate_chain(struct task_struct *curr,
struct lockdep_map *lock, struct held_lock *hlock,
- int chain_head)
+ int chain_head, u64 chain_key)
{
return 1;
}
@@ -2450,11 +2450,11 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
chain_head = 1;
}
chain_key = iterate_chain_key(chain_key, id);
- curr->curr_chain_key = chain_key;
- if (!validate_chain(curr, lock, hlock, chain_head))
+ if (!validate_chain(curr, lock, hlock, chain_head, chain_key))
return 0;
+ curr->curr_chain_key = chain_key;
curr->lockdep_depth++;
check_chain_key(curr);
#ifdef CONFIG_DEBUG_LOCKDEP
@@ -3199,3 +3199,19 @@ void debug_show_held_locks(struct task_struct *task)
}
EXPORT_SYMBOL_GPL(debug_show_held_locks);
+
+void lockdep_sys_exit(void)
+{
+ struct task_struct *curr = current;
+
+ if (unlikely(curr->lockdep_depth)) {
+ if (!debug_locks_off())
+ return;
+ printk("\n================================================\n");
+ printk( "[ BUG: lock held when returning to user space! ]\n");
+ printk( "------------------------------------------------\n");
+ printk("%s/%d is leaving the kernel with locks still held!\n",
+ curr->comm, curr->pid);
+ lockdep_print_held_locks(curr);
+ }
+}
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
index c851b2dcc68..8a135bd163c 100644
--- a/kernel/lockdep_proc.c
+++ b/kernel/lockdep_proc.c
@@ -25,28 +25,38 @@
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct lock_class *class = v;
+ struct lock_class *class;
(*pos)++;
- if (class->lock_entry.next != &all_lock_classes)
- class = list_entry(class->lock_entry.next, struct lock_class,
- lock_entry);
- else
- class = NULL;
- m->private = class;
+ if (v == SEQ_START_TOKEN)
+ class = m->private;
+ else {
+ class = v;
+
+ if (class->lock_entry.next != &all_lock_classes)
+ class = list_entry(class->lock_entry.next,
+ struct lock_class, lock_entry);
+ else
+ class = NULL;
+ }
return class;
}
static void *l_start(struct seq_file *m, loff_t *pos)
{
- struct lock_class *class = m->private;
+ struct lock_class *class;
+ loff_t i = 0;
- if (&class->lock_entry == all_lock_classes.next)
- seq_printf(m, "all lock classes:\n");
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
- return class;
+ list_for_each_entry(class, &all_lock_classes, lock_entry) {
+ if (++i == *pos)
+ return class;
+ }
+ return NULL;
}
static void l_stop(struct seq_file *m, void *v)
@@ -101,10 +111,15 @@ static void print_name(struct seq_file *m, struct lock_class *class)
static int l_show(struct seq_file *m, void *v)
{
unsigned long nr_forward_deps, nr_backward_deps;
- struct lock_class *class = m->private;
+ struct lock_class *class = v;
struct lock_list *entry;
char c1, c2, c3, c4;
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(m, "all lock classes:\n");
+ return 0;
+ }
+
seq_printf(m, "%p", class->key);
#ifdef CONFIG_DEBUG_LOCKDEP
seq_printf(m, " OPS:%8ld", class->ops);
@@ -523,10 +538,11 @@ static void *ls_start(struct seq_file *m, loff_t *pos)
{
struct lock_stat_seq *data = m->private;
- if (data->iter == data->stats)
- seq_header(m);
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
- if (data->iter == data->iter_end)
+ data->iter = data->stats + *pos;
+ if (data->iter >= data->iter_end)
data->iter = NULL;
return data->iter;
@@ -538,8 +554,13 @@ static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
(*pos)++;
- data->iter = v;
- data->iter++;
+ if (v == SEQ_START_TOKEN)
+ data->iter = data->stats;
+ else {
+ data->iter = v;
+ data->iter++;
+ }
+
if (data->iter == data->iter_end)
data->iter = NULL;
@@ -552,9 +573,11 @@ static void ls_stop(struct seq_file *m, void *v)
static int ls_show(struct seq_file *m, void *v)
{
- struct lock_stat_seq *data = m->private;
+ if (v == SEQ_START_TOKEN)
+ seq_header(m);
+ else
+ seq_stats(m, v);
- seq_stats(m, data->iter);
return 0;
}
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 691b86564dd..d7fe50cc556 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -51,6 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
EXPORT_SYMBOL(__mutex_init);
+#ifndef CONFIG_DEBUG_LOCK_ALLOC
/*
* We split the mutex lock/unlock logic into separate fastpath and
* slowpath functions, to reduce the register pressure on the fastpath.
@@ -92,6 +93,7 @@ void inline fastcall __sched mutex_lock(struct mutex *lock)
}
EXPORT_SYMBOL(mutex_lock);
+#endif
static void fastcall noinline __sched
__mutex_unlock_slowpath(atomic_t *lock_count);
@@ -122,7 +124,8 @@ EXPORT_SYMBOL(mutex_unlock);
* Lock a mutex (possibly interruptible), slowpath:
*/
static inline int __sched
-__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
+__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
+ unsigned long ip)
{
struct task_struct *task = current;
struct mutex_waiter waiter;
@@ -132,7 +135,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
spin_lock_mutex(&lock->wait_lock, flags);
debug_mutex_lock_common(lock, &waiter);
- mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
+ mutex_acquire(&lock->dep_map, subclass, 0, ip);
debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
/* add waiting tasks to the end of the waitqueue (FIFO): */
@@ -143,7 +146,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
if (old_val == 1)
goto done;
- lock_contended(&lock->dep_map, _RET_IP_);
+ lock_contended(&lock->dep_map, ip);
for (;;) {
/*
@@ -166,7 +169,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
if (unlikely(state == TASK_INTERRUPTIBLE &&
signal_pending(task))) {
mutex_remove_waiter(lock, &waiter, task_thread_info(task));
- mutex_release(&lock->dep_map, 1, _RET_IP_);
+ mutex_release(&lock->dep_map, 1, ip);
spin_unlock_mutex(&lock->wait_lock, flags);
debug_mutex_free_waiter(&waiter);
@@ -197,20 +200,12 @@ done:
return 0;
}
-static void fastcall noinline __sched
-__mutex_lock_slowpath(atomic_t *lock_count)
-{
- struct mutex *lock = container_of(lock_count, struct mutex, count);
-
- __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0);
-}
-
#ifdef CONFIG_DEBUG_LOCK_ALLOC
void __sched
mutex_lock_nested(struct mutex *lock, unsigned int subclass)
{
might_sleep();
- __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass);
+ __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, _RET_IP_);
}
EXPORT_SYMBOL_GPL(mutex_lock_nested);
@@ -219,7 +214,7 @@ int __sched
mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
{
might_sleep();
- return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass);
+ return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass, _RET_IP_);
}
EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -271,6 +266,7 @@ __mutex_unlock_slowpath(atomic_t *lock_count)
__mutex_unlock_common_slowpath(lock_count, 1);
}
+#ifndef CONFIG_DEBUG_LOCK_ALLOC
/*
* Here come the less common (and hence less performance-critical) APIs:
* mutex_lock_interruptible() and mutex_trylock().
@@ -298,13 +294,22 @@ int fastcall __sched mutex_lock_interruptible(struct mutex *lock)
EXPORT_SYMBOL(mutex_lock_interruptible);
+static void fastcall noinline __sched
+__mutex_lock_slowpath(atomic_t *lock_count)
+{
+ struct mutex *lock = container_of(lock_count, struct mutex, count);
+
+ __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
+}
+
static int fastcall noinline __sched
__mutex_lock_interruptible_slowpath(atomic_t *lock_count)
{
struct mutex *lock = container_of(lock_count, struct mutex, count);
- return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0);
+ return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, _RET_IP_);
}
+#endif
/*
* Spinlock based trylock, we take the spinlock and check whether we
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 7a15afb73ed..57efe0400bc 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -712,7 +712,7 @@ sys_timer_getoverrun(timer_t timer_id)
{
struct k_itimer *timr;
int overrun;
- long flags;
+ unsigned long flags;
timr = lock_timer(timer_id, &flags);
if (!timr)
@@ -784,7 +784,7 @@ sys_timer_settime(timer_t timer_id, int flags,
struct k_itimer *timr;
struct itimerspec new_spec, old_spec;
int error = 0;
- long flag;
+ unsigned long flag;
struct itimerspec *rtn = old_setting ? &old_spec : NULL;
if (!new_setting)
@@ -836,7 +836,7 @@ asmlinkage long
sys_timer_delete(timer_t timer_id)
{
struct k_itimer *timer;
- long flags;
+ unsigned long flags;
retry_delete:
timer = lock_timer(timer_id, &flags);
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 2c2dd8410dc..130214f3d22 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -49,6 +49,14 @@
#include <linux/cpu.h>
#include <linux/mutex.h>
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key rcu_lock_key;
+struct lockdep_map rcu_lock_map =
+ STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+
+EXPORT_SYMBOL_GPL(rcu_lock_map);
+#endif
+
/* Definition for rcupdate control block. */
static struct rcu_ctrlblk rcu_ctrlblk = {
.cur = -300,
diff --git a/kernel/sched.c b/kernel/sched.c
index 6c10fa796ca..bba57adb950 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -96,7 +96,7 @@ unsigned long long __attribute__((weak)) sched_clock(void)
/*
* Some helpers for converting nanosecond timing to jiffy resolution
*/
-#define NS_TO_JIFFIES(TIME) ((TIME) / (1000000000 / HZ))
+#define NS_TO_JIFFIES(TIME) ((unsigned long)(TIME) / (1000000000 / HZ))
#define JIFFIES_TO_NS(TIME) ((TIME) * (1000000000 / HZ))
#define NICE_0_LOAD SCHED_LOAD_SCALE
@@ -105,11 +105,9 @@ unsigned long long __attribute__((weak)) sched_clock(void)
/*
* These are the 'tuning knobs' of the scheduler:
*
- * Minimum timeslice is 5 msecs (or 1 jiffy, whichever is larger),
- * default timeslice is 100 msecs, maximum timeslice is 800 msecs.
+ * default timeslice is 100 msecs (used only for SCHED_RR tasks).
* Timeslices get refilled after they expire.
*/
-#define MIN_TIMESLICE max(5 * HZ / 1000, 1)
#define DEF_TIMESLICE (100 * HZ / 1000)
#ifdef CONFIG_SMP
@@ -133,24 +131,6 @@ static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val)
}
#endif
-#define SCALE_PRIO(x, prio) \
- max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
-
-/*
- * static_prio_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
- * to time slice values: [800ms ... 100ms ... 5ms]
- */
-static unsigned int static_prio_timeslice(int static_prio)
-{
- if (static_prio == NICE_TO_PRIO(19))
- return 1;
-
- if (static_prio < NICE_TO_PRIO(0))
- return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
- else
- return SCALE_PRIO(DEF_TIMESLICE, static_prio);
-}
-
static inline int rt_policy(int policy)
{
if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
@@ -171,31 +151,91 @@ struct rt_prio_array {
struct list_head queue[MAX_RT_PRIO];
};
-struct load_stat {
- struct load_weight load;
- u64 load_update_start, load_update_last;
- unsigned long delta_fair, delta_exec, delta_stat;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+struct cfs_rq;
+
+/* task group related information */
+struct task_group {
+ /* schedulable entities of this group on each cpu */
+ struct sched_entity **se;
+ /* runqueue "owned" by this group on each cpu */
+ struct cfs_rq **cfs_rq;
+ unsigned long shares;
+ /* spinlock to serialize modification to shares */
+ spinlock_t lock;
+};
+
+/* Default task group's sched entity on each cpu */
+static DEFINE_PER_CPU(struct sched_entity, init_sched_entity);
+/* Default task group's cfs_rq on each cpu */
+static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp;
+
+static struct sched_entity *init_sched_entity_p[NR_CPUS];
+static struct cfs_rq *init_cfs_rq_p[NR_CPUS];
+
+/* Default task group.
+ * Every task in system belong to this group at bootup.
+ */
+struct task_group init_task_group = {
+ .se = init_sched_entity_p,
+ .cfs_rq = init_cfs_rq_p,
};
+#ifdef CONFIG_FAIR_USER_SCHED
+# define INIT_TASK_GRP_LOAD 2*NICE_0_LOAD
+#else
+# define INIT_TASK_GRP_LOAD NICE_0_LOAD
+#endif
+
+static int init_task_group_load = INIT_TASK_GRP_LOAD;
+
+/* return group to which a task belongs */
+static inline struct task_group *task_group(struct task_struct *p)
+{
+ struct task_group *tg;
+
+#ifdef CONFIG_FAIR_USER_SCHED
+ tg = p->user->tg;
+#else
+ tg = &init_task_group;
+#endif
+
+ return tg;
+}
+
+/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
+static inline void set_task_cfs_rq(struct task_struct *p)
+{
+ p->se.cfs_rq = task_group(p)->cfs_rq[task_cpu(p)];
+ p->se.parent = task_group(p)->se[task_cpu(p)];
+}
+
+#else
+
+static inline void set_task_cfs_rq(struct task_struct *p) { }
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
/* CFS-related fields in a runqueue */
struct cfs_rq {
struct load_weight load;
unsigned long nr_running;
- s64 fair_clock;
u64 exec_clock;
- s64 wait_runtime;
- u64 sleeper_bonus;
- unsigned long wait_runtime_overruns, wait_runtime_underruns;
+ u64 min_vruntime;
struct rb_root tasks_timeline;
struct rb_node *rb_leftmost;
struct rb_node *rb_load_balance_curr;
-#ifdef CONFIG_FAIR_GROUP_SCHED
/* 'curr' points to currently running entity on this cfs_rq.
* It is set to NULL otherwise (i.e when none are currently running).
*/
struct sched_entity *curr;
+
+ unsigned long nr_spread_over;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
struct rq *rq; /* cpu runqueue to which this cfs_rq is attached */
/* leaf cfs_rqs are those that hold tasks (lowest schedulable entity in
@@ -206,6 +246,8 @@ struct cfs_rq {
* list is used during load balance.
*/
struct list_head leaf_cfs_rq_list; /* Better name : task_cfs_rq_list? */
+ struct task_group *tg; /* group that "owns" this runqueue */
+ struct rcu_head rcu;
#endif
};
@@ -237,7 +279,7 @@ struct rq {
#ifdef CONFIG_NO_HZ
unsigned char in_nohz_recently;
#endif
- struct load_stat ls; /* capture load from *all* tasks on this cpu */
+ struct load_weight load; /* capture load from *all* tasks on this cpu */
unsigned long nr_load_updates;
u64 nr_switches;
@@ -289,16 +331,19 @@ struct rq {
unsigned long yld_exp_empty;
unsigned long yld_act_empty;
unsigned long yld_both_empty;
- unsigned long yld_cnt;
+ unsigned long yld_count;
/* schedule() stats */
unsigned long sched_switch;
- unsigned long sched_cnt;
+ unsigned long sched_count;
unsigned long sched_goidle;
/* try_to_wake_up() stats */
- unsigned long ttwu_cnt;
+ unsigned long ttwu_count;
unsigned long ttwu_local;
+
+ /* BKL stats */
+ unsigned long bkl_count;
#endif
struct lock_class_key rq_lock_key;
};
@@ -383,6 +428,37 @@ static void update_rq_clock(struct rq *rq)
#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
/*
+ * Tunables that become constants when CONFIG_SCHED_DEBUG is off:
+ */
+#ifdef CONFIG_SCHED_DEBUG
+# define const_debug __read_mostly
+#else
+# define const_debug static const
+#endif
+
+/*
+ * Debugging: various feature bits
+ */
+enum {
+ SCHED_FEAT_NEW_FAIR_SLEEPERS = 1,
+ SCHED_FEAT_START_DEBIT = 2,
+ SCHED_FEAT_TREE_AVG = 4,
+ SCHED_FEAT_APPROX_AVG = 8,
+ SCHED_FEAT_WAKEUP_PREEMPT = 16,
+ SCHED_FEAT_PREEMPT_RESTRICT = 32,
+};
+
+const_debug unsigned int sysctl_sched_features =
+ SCHED_FEAT_NEW_FAIR_SLEEPERS *1 |
+ SCHED_FEAT_START_DEBIT *1 |
+ SCHED_FEAT_TREE_AVG *0 |
+ SCHED_FEAT_APPROX_AVG *0 |
+ SCHED_FEAT_WAKEUP_PREEMPT *1 |
+ SCHED_FEAT_PREEMPT_RESTRICT *1;
+
+#define sched_feat(x) (sysctl_sched_features & SCHED_FEAT_##x)
+
+/*
* For kernel-internal use: high-speed (but slightly incorrect) per-cpu
* clock constructed from sched_clock():
*/
@@ -400,18 +476,7 @@ unsigned long long cpu_clock(int cpu)
return now;
}
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-/* Change a task's ->cfs_rq if it moves across CPUs */
-static inline void set_task_cfs_rq(struct task_struct *p)
-{
- p->se.cfs_rq = &task_rq(p)->cfs;
-}
-#else
-static inline void set_task_cfs_rq(struct task_struct *p)
-{
-}
-#endif
+EXPORT_SYMBOL_GPL(cpu_clock);
#ifndef prepare_arch_switch
# define prepare_arch_switch(next) do { } while (0)
@@ -497,16 +562,13 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
static inline struct rq *__task_rq_lock(struct task_struct *p)
__acquires(rq->lock)
{
- struct rq *rq;
-
-repeat_lock_task:
- rq = task_rq(p);
- spin_lock(&rq->lock);
- if (unlikely(rq != task_rq(p))) {
+ for (;;) {
+ struct rq *rq = task_rq(p);
+ spin_lock(&rq->lock);
+ if (likely(rq == task_rq(p)))
+ return rq;
spin_unlock(&rq->lock);
- goto repeat_lock_task;
}
- return rq;
}
/*
@@ -519,18 +581,17 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
{
struct rq *rq;
-repeat_lock_task:
- local_irq_save(*flags);
- rq = task_rq(p);
- spin_lock(&rq->lock);
- if (unlikely(rq != task_rq(p))) {
+ for (;;) {
+ local_irq_save(*flags);
+ rq = task_rq(p);
+ spin_lock(&rq->lock);
+ if (likely(rq == task_rq(p)))
+ return rq;
spin_unlock_irqrestore(&rq->lock, *flags);
- goto repeat_lock_task;
}
- return rq;
}
-static inline void __task_rq_unlock(struct rq *rq)
+static void __task_rq_unlock(struct rq *rq)
__releases(rq->lock)
{
spin_unlock(&rq->lock);
@@ -545,7 +606,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
/*
* this_rq_lock - lock this runqueue and disable interrupts.
*/
-static inline struct rq *this_rq_lock(void)
+static struct rq *this_rq_lock(void)
__acquires(rq->lock)
{
struct rq *rq;
@@ -645,19 +706,6 @@ static inline void resched_task(struct task_struct *p)
}
#endif
-static u64 div64_likely32(u64 divident, unsigned long divisor)
-{
-#if BITS_PER_LONG == 32
- if (likely(divident <= 0xffffffffULL))
- return (u32)divident / divisor;
- do_div(divident, divisor);
-
- return divident;
-#else
- return divident / divisor;
-#endif
-}
-
#if BITS_PER_LONG == 32
# define WMULT_CONST (~0UL)
#else
@@ -699,16 +747,14 @@ calc_delta_fair(unsigned long delta_exec, struct load_weight *lw)
return calc_delta_mine(delta_exec, NICE_0_LOAD, lw);
}
-static void update_load_add(struct load_weight *lw, unsigned long inc)
+static inline void update_load_add(struct load_weight *lw, unsigned long inc)
{
lw->weight += inc;
- lw->inv_weight = 0;
}
-static void update_load_sub(struct load_weight *lw, unsigned long dec)
+static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
{
lw->weight -= dec;
- lw->inv_weight = 0;
}
/*
@@ -784,29 +830,20 @@ static int balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
int *this_best_prio, struct rq_iterator *iterator);
#include "sched_stats.h"
-#include "sched_rt.c"
-#include "sched_fair.c"
#include "sched_idletask.c"
+#include "sched_fair.c"
+#include "sched_rt.c"
#ifdef CONFIG_SCHED_DEBUG
# include "sched_debug.c"
#endif
#define sched_class_highest (&rt_sched_class)
-static void __update_curr_load(struct rq *rq, struct load_stat *ls)
-{
- if (rq->curr != rq->idle && ls->load.weight) {
- ls->delta_exec += ls->delta_stat;
- ls->delta_fair += calc_delta_fair(ls->delta_stat, &ls->load);
- ls->delta_stat = 0;
- }
-}
-
/*
* Update delta_exec, delta_fair fields for rq.
*
* delta_fair clock advances at a rate inversely proportional to
- * total load (rq->ls.load.weight) on the runqueue, while
+ * total load (rq->load.weight) on the runqueue, while
* delta_exec advances at the same rate as wall-clock (provided
* cpu is not idle).
*
@@ -814,35 +851,17 @@ static void __update_curr_load(struct rq *rq, struct load_stat *ls)
* runqueue over any given interval. This (smoothened) load is used
* during load balance.
*
- * This function is called /before/ updating rq->ls.load
+ * This function is called /before/ updating rq->load
* and when switching tasks.
*/
-static void update_curr_load(struct rq *rq)
-{
- struct load_stat *ls = &rq->ls;
- u64 start;
-
- start = ls->load_update_start;
- ls->load_update_start = rq->clock;
- ls->delta_stat += rq->clock - start;
- /*
- * Stagger updates to ls->delta_fair. Very frequent updates
- * can be expensive.
- */
- if (ls->delta_stat >= sysctl_sched_stat_granularity)
- __update_curr_load(rq, ls);
-}
-
static inline void inc_load(struct rq *rq, const struct task_struct *p)
{
- update_curr_load(rq);
- update_load_add(&rq->ls.load, p->se.load.weight);
+ update_load_add(&rq->load, p->se.load.weight);
}
static inline void dec_load(struct rq *rq, const struct task_struct *p)
{
- update_curr_load(rq);
- update_load_sub(&rq->ls.load, p->se.load.weight);
+ update_load_sub(&rq->load, p->se.load.weight);
}
static void inc_nr_running(struct task_struct *p, struct rq *rq)
@@ -859,8 +878,6 @@ static void dec_nr_running(struct task_struct *p, struct rq *rq)
static void set_load_weight(struct task_struct *p)
{
- p->se.wait_runtime = 0;
-
if (task_has_rt_policy(p)) {
p->se.load.weight = prio_to_weight[0] * 2;
p->se.load.inv_weight = prio_to_wmult[0] >> 1;
@@ -952,20 +969,6 @@ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup)
}
/*
- * activate_idle_task - move idle task to the _front_ of runqueue.
- */
-static inline void activate_idle_task(struct task_struct *p, struct rq *rq)
-{
- update_rq_clock(rq);
-
- if (p->state == TASK_UNINTERRUPTIBLE)
- rq->nr_uninterruptible--;
-
- enqueue_task(rq, p, 0);
- inc_nr_running(p, rq);
-}
-
-/*
* deactivate_task - remove a task from the runqueue.
*/
static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep)
@@ -989,32 +992,50 @@ inline int task_curr(const struct task_struct *p)
/* Used instead of source_load when we know the type == 0 */
unsigned long weighted_cpuload(const int cpu)
{
- return cpu_rq(cpu)->ls.load.weight;
+ return cpu_rq(cpu)->load.weight;
}
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
{
#ifdef CONFIG_SMP
task_thread_info(p)->cpu = cpu;
- set_task_cfs_rq(p);
#endif
+ set_task_cfs_rq(p);
}
#ifdef CONFIG_SMP
+/*
+ * Is this task likely cache-hot:
+ */
+static inline int
+task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
+{
+ s64 delta;
+
+ if (p->sched_class != &fair_sched_class)
+ return 0;
+
+ if (sysctl_sched_migration_cost == -1)
+ return 1;
+ if (sysctl_sched_migration_cost == 0)
+ return 0;
+
+ delta = now - p->se.exec_start;
+
+ return delta < (s64)sysctl_sched_migration_cost;
+}
+
+
void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
{
int old_cpu = task_cpu(p);
struct rq *old_rq = cpu_rq(old_cpu), *new_rq = cpu_rq(new_cpu);
- u64 clock_offset, fair_clock_offset;
+ struct cfs_rq *old_cfsrq = task_cfs_rq(p),
+ *new_cfsrq = cpu_cfs_rq(old_cfsrq, new_cpu);
+ u64 clock_offset;
clock_offset = old_rq->clock - new_rq->clock;
- fair_clock_offset = old_rq->cfs.fair_clock - new_rq->cfs.fair_clock;
-
- if (p->se.wait_start_fair)
- p->se.wait_start_fair -= fair_clock_offset;
- if (p->se.sleep_start_fair)
- p->se.sleep_start_fair -= fair_clock_offset;
#ifdef CONFIG_SCHEDSTATS
if (p->se.wait_start)
@@ -1023,7 +1044,14 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
p->se.sleep_start -= clock_offset;
if (p->se.block_start)
p->se.block_start -= clock_offset;
+ if (old_cpu != new_cpu) {
+ schedstat_inc(p, se.nr_migrations);
+ if (task_hot(p, old_rq->clock, NULL))
+ schedstat_inc(p, se.nr_forced2_migrations);
+ }
#endif
+ p->se.vruntime -= old_cfsrq->min_vruntime -
+ new_cfsrq->min_vruntime;
__set_task_cpu(p, new_cpu);
}
@@ -1078,69 +1106,71 @@ void wait_task_inactive(struct task_struct *p)
int running, on_rq;
struct rq *rq;
-repeat:
- /*
- * We do the initial early heuristics without holding
- * any task-queue locks at all. We'll only try to get
- * the runqueue lock when things look like they will
- * work out!
- */
- rq = task_rq(p);
+ for (;;) {
+ /*
+ * We do the initial early heuristics without holding
+ * any task-queue locks at all. We'll only try to get
+ * the runqueue lock when things look like they will
+ * work out!
+ */
+ rq = task_rq(p);
- /*
- * If the task is actively running on another CPU
- * still, just relax and busy-wait without holding
- * any locks.
- *
- * NOTE! Since we don't hold any locks, it's not
- * even sure that "rq" stays as the right runqueue!
- * But we don't care, since "task_running()" will
- * return false if the runqueue has changed and p
- * is actually now running somewhere else!
- */
- while (task_running(rq, p))
- cpu_relax();
+ /*
+ * If the task is actively running on another CPU
+ * still, just relax and busy-wait without holding
+ * any locks.
+ *
+ * NOTE! Since we don't hold any locks, it's not
+ * even sure that "rq" stays as the right runqueue!
+ * But we don't care, since "task_running()" will
+ * return false if the runqueue has changed and p
+ * is actually now running somewhere else!
+ */
+ while (task_running(rq, p))
+ cpu_relax();
- /*
- * Ok, time to look more closely! We need the rq
- * lock now, to be *sure*. If we're wrong, we'll
- * just go back and repeat.
- */
- rq = task_rq_lock(p, &flags);
- running = task_running(rq, p);
- on_rq = p->se.on_rq;
- task_rq_unlock(rq, &flags);
+ /*
+ * Ok, time to look more closely! We need the rq
+ * lock now, to be *sure*. If we're wrong, we'll
+ * just go back and repeat.
+ */
+ rq = task_rq_lock(p, &flags);
+ running = task_running(rq, p);
+ on_rq = p->se.on_rq;
+ task_rq_unlock(rq, &flags);
- /*
- * Was it really running after all now that we
- * checked with the proper locks actually held?
- *
- * Oops. Go back and try again..
- */
- if (unlikely(running)) {
- cpu_relax();
- goto repeat;
- }
+ /*
+ * Was it really running after all now that we
+ * checked with the proper locks actually held?
+ *
+ * Oops. Go back and try again..
+ */
+ if (unlikely(running)) {
+ cpu_relax();
+ continue;
+ }
- /*
- * It's not enough that it's not actively running,
- * it must be off the runqueue _entirely_, and not
- * preempted!
- *
- * So if it wa still runnable (but just not actively
- * running right now), it's preempted, and we should
- * yield - it could be a while.
- */
- if (unlikely(on_rq)) {
- yield();
- goto repeat;
- }
+ /*
+ * It's not enough that it's not actively running,
+ * it must be off the runqueue _entirely_, and not
+ * preempted!
+ *
+ * So if it wa still runnable (but just not actively
+ * running right now), it's preempted, and we should
+ * yield - it could be a while.
+ */
+ if (unlikely(on_rq)) {
+ schedule_timeout_uninterruptible(1);
+ continue;
+ }
- /*
- * Ahh, all good. It wasn't running, and it wasn't
- * runnable, which means that it will never become
- * running in the future either. We're all done!
- */
+ /*
+ * Ahh, all good. It wasn't running, and it wasn't
+ * runnable, which means that it will never become
+ * running in the future either. We're all done!
+ */
+ break;
+ }
}
/***
@@ -1174,7 +1204,7 @@ void kick_process(struct task_struct *p)
* We want to under-estimate the load of migration sources, to
* balance conservatively.
*/
-static inline unsigned long source_load(int cpu, int type)
+static unsigned long source_load(int cpu, int type)
{
struct rq *rq = cpu_rq(cpu);
unsigned long total = weighted_cpuload(cpu);
@@ -1189,7 +1219,7 @@ static inline unsigned long source_load(int cpu, int type)
* Return a high guess at the load of a migration-target cpu weighted
* according to the scheduling class and "nice" value.
*/
-static inline unsigned long target_load(int cpu, int type)
+static unsigned long target_load(int cpu, int type)
{
struct rq *rq = cpu_rq(cpu);
unsigned long total = weighted_cpuload(cpu);
@@ -1231,7 +1261,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
/* Skip over this group if it has no CPUs allowed */
if (!cpus_intersects(group->cpumask, p->cpus_allowed))
- goto nextgroup;
+ continue;
local_group = cpu_isset(this_cpu, group->cpumask);
@@ -1259,9 +1289,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
min_load = avg_load;
idlest = group;
}
-nextgroup:
- group = group->next;
- } while (group != sd->groups);
+ } while (group = group->next, group != sd->groups);
if (!idlest || 100*this_load < imbalance*min_load)
return NULL;
@@ -1393,8 +1421,13 @@ static int wake_idle(int cpu, struct task_struct *p)
if (sd->flags & SD_WAKE_IDLE) {
cpus_and(tmp, sd->span, p->cpus_allowed);
for_each_cpu_mask(i, tmp) {
- if (idle_cpu(i))
+ if (idle_cpu(i)) {
+ if (i != task_cpu(p)) {
+ schedstat_inc(p,
+ se.nr_wakeups_idle);
+ }
return i;
+ }
}
} else {
break;
@@ -1425,7 +1458,7 @@ static inline int wake_idle(int cpu, struct task_struct *p)
*/
static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
{
- int cpu, this_cpu, success = 0;
+ int cpu, orig_cpu, this_cpu, success = 0;
unsigned long flags;
long old_state;
struct rq *rq;
@@ -1444,6 +1477,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
goto out_running;
cpu = task_cpu(p);
+ orig_cpu = cpu;
this_cpu = smp_processor_id();
#ifdef CONFIG_SMP
@@ -1452,7 +1486,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
new_cpu = cpu;
- schedstat_inc(rq, ttwu_cnt);
+ schedstat_inc(rq, ttwu_count);
if (cpu == this_cpu) {
schedstat_inc(rq, ttwu_local);
goto out_set_cpu;
@@ -1487,6 +1521,13 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
unsigned long tl = this_load;
unsigned long tl_per_task;
+ /*
+ * Attract cache-cold tasks on sync wakeups:
+ */
+ if (sync && !task_hot(p, rq->clock, this_sd))
+ goto out_set_cpu;
+
+ schedstat_inc(p, se.nr_wakeups_affine_attempts);
tl_per_task = cpu_avg_load_per_task(this_cpu);
/*
@@ -1506,6 +1547,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
* there is no bad imbalance.
*/
schedstat_inc(this_sd, ttwu_move_affine);
+ schedstat_inc(p, se.nr_wakeups_affine);
goto out_set_cpu;
}
}
@@ -1517,6 +1559,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
if (this_sd->flags & SD_WAKE_BALANCE) {
if (imbalance*this_load <= 100*load) {
schedstat_inc(this_sd, ttwu_move_balance);
+ schedstat_inc(p, se.nr_wakeups_passive);
goto out_set_cpu;
}
}
@@ -1542,18 +1585,18 @@ out_set_cpu:
out_activate:
#endif /* CONFIG_SMP */
+ schedstat_inc(p, se.nr_wakeups);
+ if (sync)
+ schedstat_inc(p, se.nr_wakeups_sync);
+ if (orig_cpu != cpu)
+ schedstat_inc(p, se.nr_wakeups_migrate);
+ if (cpu == this_cpu)
+ schedstat_inc(p, se.nr_wakeups_local);
+ else
+ schedstat_inc(p, se.nr_wakeups_remote);
update_rq_clock(rq);
activate_task(rq, p, 1);
- /*
- * Sync wakeups (i.e. those types of wakeups where the waker
- * has indicated that it will leave the CPU in short order)
- * don't trigger a preemption, if the woken up task will run on
- * this cpu. (in this case the 'I will reschedule' promise of
- * the waker guarantees that the freshly woken up task is going
- * to be considered on this CPU.)
- */
- if (!sync || cpu != this_cpu)
- check_preempt_curr(rq, p);
+ check_preempt_curr(rq, p);
success = 1;
out_running:
@@ -1584,28 +1627,20 @@ int fastcall wake_up_state(struct task_struct *p, unsigned int state)
*/
static void __sched_fork(struct task_struct *p)
{
- p->se.wait_start_fair = 0;
p->se.exec_start = 0;
p->se.sum_exec_runtime = 0;
p->se.prev_sum_exec_runtime = 0;
- p->se.delta_exec = 0;
- p->se.delta_fair_run = 0;
- p->se.delta_fair_sleep = 0;
- p->se.wait_runtime = 0;
- p->se.sleep_start_fair = 0;
#ifdef CONFIG_SCHEDSTATS
p->se.wait_start = 0;
- p->se.sum_wait_runtime = 0;
p->se.sum_sleep_runtime = 0;
p->se.sleep_start = 0;
p->se.block_start = 0;
p->se.sleep_max = 0;
p->se.block_max = 0;
p->se.exec_max = 0;
+ p->se.slice_max = 0;
p->se.wait_max = 0;
- p->se.wait_runtime_overruns = 0;
- p->se.wait_runtime_underruns = 0;
#endif
INIT_LIST_HEAD(&p->run_list);
@@ -1636,12 +1671,14 @@ void sched_fork(struct task_struct *p, int clone_flags)
#ifdef CONFIG_SMP
cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
#endif
- __set_task_cpu(p, cpu);
+ set_task_cpu(p, cpu);
/*
* Make sure we do not leak PI boosting priority to the child:
*/
p->prio = current->normal_prio;
+ if (!rt_prio(p->prio))
+ p->sched_class = &fair_sched_class;
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
if (likely(sched_info_on()))
@@ -1658,12 +1695,6 @@ void sched_fork(struct task_struct *p, int clone_flags)
}
/*
- * After fork, child runs first. (default) If set to 0 then
- * parent will (try to) run first.
- */
-unsigned int __read_mostly sysctl_sched_child_runs_first = 1;
-
-/*
* wake_up_new_task - wake up a newly created task for the first time.
*
* This function will do some initial scheduler statistics housekeeping
@@ -1674,24 +1705,14 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
{
unsigned long flags;
struct rq *rq;
- int this_cpu;
rq = task_rq_lock(p, &flags);
BUG_ON(p->state != TASK_RUNNING);
- this_cpu = smp_processor_id(); /* parent's CPU */
update_rq_clock(rq);
p->prio = effective_prio(p);
- if (rt_prio(p->prio))
- p->sched_class = &rt_sched_class;
- else
- p->sched_class = &fair_sched_class;
-
- if (!p->sched_class->task_new || !sysctl_sched_child_runs_first ||
- (clone_flags & CLONE_VM) || task_cpu(p) != this_cpu ||
- !current->se.on_rq) {
-
+ if (!p->sched_class->task_new || !current->se.on_rq || !rq->cfs.curr) {
activate_task(rq, p, 0);
} else {
/*
@@ -1800,7 +1821,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
* with the lock held can cause deadlocks; see schedule() for
* details.)
*/
-static inline void finish_task_switch(struct rq *rq, struct task_struct *prev)
+static void finish_task_switch(struct rq *rq, struct task_struct *prev)
__releases(rq->lock)
{
struct mm_struct *mm = rq->prev_mm;
@@ -1982,42 +2003,10 @@ unsigned long nr_active(void)
*/
static void update_cpu_load(struct rq *this_rq)
{
- u64 fair_delta64, exec_delta64, idle_delta64, sample_interval64, tmp64;
- unsigned long total_load = this_rq->ls.load.weight;
- unsigned long this_load = total_load;
- struct load_stat *ls = &this_rq->ls;
+ unsigned long this_load = this_rq->load.weight;
int i, scale;
this_rq->nr_load_updates++;
- if (unlikely(!(sysctl_sched_features & SCHED_FEAT_PRECISE_CPU_LOAD)))
- goto do_avg;
-
- /* Update delta_fair/delta_exec fields first */
- update_curr_load(this_rq);
-
- fair_delta64 = ls->delta_fair + 1;
- ls->delta_fair = 0;
-
- exec_delta64 = ls->delta_exec + 1;
- ls->delta_exec = 0;
-
- sample_interval64 = this_rq->clock - ls->load_update_last;
- ls->load_update_last = this_rq->clock;
-
- if ((s64)sample_interval64 < (s64)TICK_NSEC)
- sample_interval64 = TICK_NSEC;
-
- if (exec_delta64 > sample_interval64)
- exec_delta64 = sample_interval64;
-
- idle_delta64 = sample_interval64 - exec_delta64;
-
- tmp64 = div64_64(SCHED_LOAD_SCALE * exec_delta64, fair_delta64);
- tmp64 = div64_64(tmp64 * exec_delta64, sample_interval64);
-
- this_load = (unsigned long)tmp64;
-
-do_avg:
/* Update our load: */
for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
@@ -2027,7 +2016,13 @@ do_avg:
old_load = this_rq->cpu_load[i];
new_load = this_load;
-
+ /*
+ * Round up the averaging division if load is increasing. This
+ * prevents us from getting stuck on 9 if the load is 10, for
+ * example.
+ */
+ if (new_load > old_load)
+ new_load += scale-1;
this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
}
}
@@ -2179,13 +2174,38 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
* 2) cannot be migrated to this CPU due to cpus_allowed, or
* 3) are cache-hot on their current CPU.
*/
- if (!cpu_isset(this_cpu, p->cpus_allowed))
+ if (!cpu_isset(this_cpu, p->cpus_allowed)) {
+ schedstat_inc(p, se.nr_failed_migrations_affine);
return 0;
+ }
*all_pinned = 0;
- if (task_running(rq, p))
+ if (task_running(rq, p)) {
+ schedstat_inc(p, se.nr_failed_migrations_running);
return 0;
+ }
+
+ /*
+ * Aggressive migration if:
+ * 1) task is cache cold, or
+ * 2) too many balance attempts have failed.
+ */
+
+ if (!task_hot(p, rq->clock, sd) ||
+ sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+ if (task_hot(p, rq->clock, sd)) {
+ schedstat_inc(sd, lb_hot_gained[idle]);
+ schedstat_inc(p, se.nr_forced_migrations);
+ }
+#endif
+ return 1;
+ }
+ if (task_hot(p, rq->clock, sd)) {
+ schedstat_inc(p, se.nr_failed_migrations_hot);
+ return 0;
+ }
return 1;
}
@@ -2264,7 +2284,7 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned)
{
- struct sched_class *class = sched_class_highest;
+ const struct sched_class *class = sched_class_highest;
unsigned long total_load_moved = 0;
int this_best_prio = this_rq->curr->prio;
@@ -2289,7 +2309,7 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
struct sched_domain *sd, enum cpu_idle_type idle)
{
- struct sched_class *class;
+ const struct sched_class *class;
int this_best_prio = MAX_PRIO;
for (class = sched_class_highest; class; class = class->next)
@@ -2653,7 +2673,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
!test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
sd_idle = 1;
- schedstat_inc(sd, lb_cnt[idle]);
+ schedstat_inc(sd, lb_count[idle]);
redo:
group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
@@ -2806,7 +2826,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
!test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
sd_idle = 1;
- schedstat_inc(sd, lb_cnt[CPU_NEWLY_IDLE]);
+ schedstat_inc(sd, lb_count[CPU_NEWLY_IDLE]);
redo:
group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE,
&sd_idle, &cpus, NULL);
@@ -2940,7 +2960,7 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
}
if (likely(sd)) {
- schedstat_inc(sd, alb_cnt);
+ schedstat_inc(sd, alb_count);
if (move_one_task(target_rq, target_cpu, busiest_rq,
sd, CPU_IDLE))
@@ -3033,7 +3053,7 @@ static DEFINE_SPINLOCK(balancing);
*
* Balancing parameters are set up in arch_init_sched_domains.
*/
-static inline void rebalance_domains(int cpu, enum cpu_idle_type idle)
+static void rebalance_domains(int cpu, enum cpu_idle_type idle)
{
int balance = 1;
struct rq *rq = cpu_rq(cpu);
@@ -3280,6 +3300,25 @@ void account_user_time(struct task_struct *p, cputime_t cputime)
}
/*
+ * Account guest cpu time to a process.
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in virtual machine since the last update
+ */
+void account_guest_time(struct task_struct *p, cputime_t cputime)
+{
+ cputime64_t tmp;
+ struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
+
+ tmp = cputime_to_cputime64(cputime);
+
+ p->utime = cputime_add(p->utime, cputime);
+ p->gtime = cputime_add(p->gtime, cputime);
+
+ cpustat->user = cputime64_add(cpustat->user, tmp);
+ cpustat->guest = cputime64_add(cpustat->guest, tmp);
+}
+
+/*
* Account system cpu time to a process.
* @p: the process that the cpu time gets accounted to
* @hardirq_offset: the offset to subtract from hardirq_count()
@@ -3292,6 +3331,12 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
struct rq *rq = this_rq();
cputime64_t tmp;
+ if (p->flags & PF_VCPU) {
+ account_guest_time(p, cputime);
+ p->flags &= ~PF_VCPU;
+ return;
+ }
+
p->stime = cputime_add(p->stime, cputime);
/* Add system time to cpustat. */
@@ -3430,7 +3475,13 @@ static inline void schedule_debug(struct task_struct *prev)
profile_hit(SCHED_PROFILING, __builtin_return_address(0));
- schedstat_inc(this_rq(), sched_cnt);
+ schedstat_inc(this_rq(), sched_count);
+#ifdef CONFIG_SCHEDSTATS
+ if (unlikely(prev->lock_depth >= 0)) {
+ schedstat_inc(this_rq(), bkl_count);
+ schedstat_inc(prev, sched_info.bkl_count);
+ }
+#endif
}
/*
@@ -3439,7 +3490,7 @@ static inline void schedule_debug(struct task_struct *prev)
static inline struct task_struct *
pick_next_task(struct rq *rq, struct task_struct *prev)
{
- struct sched_class *class;
+ const struct sched_class *class;
struct task_struct *p;
/*
@@ -3488,9 +3539,13 @@ need_resched_nonpreemptible:
schedule_debug(prev);
- spin_lock_irq(&rq->lock);
- clear_tsk_need_resched(prev);
+ /*
+ * Do the rq-clock update outside the rq lock:
+ */
+ local_irq_disable();
__update_rq_clock(rq);
+ spin_lock(&rq->lock);
+ clear_tsk_need_resched(prev);
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
@@ -3550,27 +3605,30 @@ asmlinkage void __sched preempt_schedule(void)
if (likely(ti->preempt_count || irqs_disabled()))
return;
-need_resched:
- add_preempt_count(PREEMPT_ACTIVE);
- /*
- * We keep the big kernel semaphore locked, but we
- * clear ->lock_depth so that schedule() doesnt
- * auto-release the semaphore:
- */
+ do {
+ add_preempt_count(PREEMPT_ACTIVE);
+
+ /*
+ * We keep the big kernel semaphore locked, but we
+ * clear ->lock_depth so that schedule() doesnt
+ * auto-release the semaphore:
+ */
#ifdef CONFIG_PREEMPT_BKL
- saved_lock_depth = task->lock_depth;
- task->lock_depth = -1;
+ saved_lock_depth = task->lock_depth;
+ task->lock_depth = -1;
#endif
- schedule();
+ schedule();
#ifdef CONFIG_PREEMPT_BKL
- task->lock_depth = saved_lock_depth;
+ task->lock_depth = saved_lock_depth;
#endif
- sub_preempt_count(PREEMPT_ACTIVE);
+ sub_preempt_count(PREEMPT_ACTIVE);
- /* we could miss a preemption opportunity between schedule and now */
- barrier();
- if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
- goto need_resched;
+ /*
+ * Check again in case we missed a preemption opportunity
+ * between schedule and now.
+ */
+ barrier();
+ } while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));
}
EXPORT_SYMBOL(preempt_schedule);
@@ -3590,29 +3648,32 @@ asmlinkage void __sched preempt_schedule_irq(void)
/* Catch callers which need to be fixed */
BUG_ON(ti->preempt_count || !irqs_disabled());
-need_resched:
- add_preempt_count(PREEMPT_ACTIVE);
- /*
- * We keep the big kernel semaphore locked, but we
- * clear ->lock_depth so that schedule() doesnt
- * auto-release the semaphore:
- */
+ do {
+ add_preempt_count(PREEMPT_ACTIVE);
+
+ /*
+ * We keep the big kernel semaphore locked, but we
+ * clear ->lock_depth so that schedule() doesnt
+ * auto-release the semaphore:
+ */
#ifdef CONFIG_PREEMPT_BKL
- saved_lock_depth = task->lock_depth;
- task->lock_depth = -1;
+ saved_lock_depth = task->lock_depth;
+ task->lock_depth = -1;
#endif
- local_irq_enable();
- schedule();
- local_irq_disable();
+ local_irq_enable();
+ schedule();
+ local_irq_disable();
#ifdef CONFIG_PREEMPT_BKL
- task->lock_depth = saved_lock_depth;
+ task->lock_depth = saved_lock_depth;
#endif
- sub_preempt_count(PREEMPT_ACTIVE);
+ sub_preempt_count(PREEMPT_ACTIVE);
- /* we could miss a preemption opportunity between schedule and now */
- barrier();
- if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
- goto need_resched;
+ /*
+ * Check again in case we missed a preemption opportunity
+ * between schedule and now.
+ */
+ barrier();
+ } while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));
}
#endif /* CONFIG_PREEMPT */
@@ -3636,10 +3697,9 @@ EXPORT_SYMBOL(default_wake_function);
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int sync, void *key)
{
- struct list_head *tmp, *next;
+ wait_queue_t *curr, *next;
- list_for_each_safe(tmp, next, &q->task_list) {
- wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
unsigned flags = curr->flags;
if (curr->func(curr, mode, sync, key) &&
@@ -3729,206 +3789,116 @@ void fastcall complete_all(struct completion *x)
}
EXPORT_SYMBOL(complete_all);
-void fastcall __sched wait_for_completion(struct completion *x)
-{
- might_sleep();
-
- spin_lock_irq(&x->wait.lock);
- if (!x->done) {
- DECLARE_WAITQUEUE(wait, current);
-
- wait.flags |= WQ_FLAG_EXCLUSIVE;
- __add_wait_queue_tail(&x->wait, &wait);
- do {
- __set_current_state(TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&x->wait.lock);
- schedule();
- spin_lock_irq(&x->wait.lock);
- } while (!x->done);
- __remove_wait_queue(&x->wait, &wait);
- }
- x->done--;
- spin_unlock_irq(&x->wait.lock);
-}
-EXPORT_SYMBOL(wait_for_completion);
-
-unsigned long fastcall __sched
-wait_for_completion_timeout(struct completion *x, unsigned long timeout)
+static inline long __sched
+do_wait_for_common(struct completion *x, long timeout, int state)
{
- might_sleep();
-
- spin_lock_irq(&x->wait.lock);
if (!x->done) {
DECLARE_WAITQUEUE(wait, current);
wait.flags |= WQ_FLAG_EXCLUSIVE;
__add_wait_queue_tail(&x->wait, &wait);
do {
- __set_current_state(TASK_UNINTERRUPTIBLE);
+ if (state == TASK_INTERRUPTIBLE &&
+ signal_pending(current)) {
+ __remove_wait_queue(&x->wait, &wait);
+ return -ERESTARTSYS;
+ }
+ __set_current_state(state);
spin_unlock_irq(&x->wait.lock);
timeout = schedule_timeout(timeout);
spin_lock_irq(&x->wait.lock);
if (!timeout) {
__remove_wait_queue(&x->wait, &wait);
- goto out;
+ return timeout;
}
} while (!x->done);
__remove_wait_queue(&x->wait, &wait);
}
x->done--;
-out:
- spin_unlock_irq(&x->wait.lock);
return timeout;
}
-EXPORT_SYMBOL(wait_for_completion_timeout);
-int fastcall __sched wait_for_completion_interruptible(struct completion *x)
+static long __sched
+wait_for_common(struct completion *x, long timeout, int state)
{
- int ret = 0;
-
might_sleep();
spin_lock_irq(&x->wait.lock);
- if (!x->done) {
- DECLARE_WAITQUEUE(wait, current);
-
- wait.flags |= WQ_FLAG_EXCLUSIVE;
- __add_wait_queue_tail(&x->wait, &wait);
- do {
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- __remove_wait_queue(&x->wait, &wait);
- goto out;
- }
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irq(&x->wait.lock);
- schedule();
- spin_lock_irq(&x->wait.lock);
- } while (!x->done);
- __remove_wait_queue(&x->wait, &wait);
- }
- x->done--;
-out:
+ timeout = do_wait_for_common(x, timeout, state);
spin_unlock_irq(&x->wait.lock);
+ return timeout;
+}
- return ret;
+void fastcall __sched wait_for_completion(struct completion *x)
+{
+ wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_interruptible);
+EXPORT_SYMBOL(wait_for_completion);
unsigned long fastcall __sched
-wait_for_completion_interruptible_timeout(struct completion *x,
- unsigned long timeout)
+wait_for_completion_timeout(struct completion *x, unsigned long timeout)
{
- might_sleep();
-
- spin_lock_irq(&x->wait.lock);
- if (!x->done) {
- DECLARE_WAITQUEUE(wait, current);
-
- wait.flags |= WQ_FLAG_EXCLUSIVE;
- __add_wait_queue_tail(&x->wait, &wait);
- do {
- if (signal_pending(current)) {
- timeout = -ERESTARTSYS;
- __remove_wait_queue(&x->wait, &wait);
- goto out;
- }
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irq(&x->wait.lock);
- timeout = schedule_timeout(timeout);
- spin_lock_irq(&x->wait.lock);
- if (!timeout) {
- __remove_wait_queue(&x->wait, &wait);
- goto out;
- }
- } while (!x->done);
- __remove_wait_queue(&x->wait, &wait);
- }
- x->done--;
-out:
- spin_unlock_irq(&x->wait.lock);
- return timeout;
+ return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
+EXPORT_SYMBOL(wait_for_completion_timeout);
-static inline void
-sleep_on_head(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+int __sched wait_for_completion_interruptible(struct completion *x)
{
- spin_lock_irqsave(&q->lock, *flags);
- __add_wait_queue(q, wait);
- spin_unlock(&q->lock);
+ return wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE);
}
+EXPORT_SYMBOL(wait_for_completion_interruptible);
-static inline void
-sleep_on_tail(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+unsigned long fastcall __sched
+wait_for_completion_interruptible_timeout(struct completion *x,
+ unsigned long timeout)
{
- spin_lock_irq(&q->lock);
- __remove_wait_queue(q, wait);
- spin_unlock_irqrestore(&q->lock, *flags);
+ return wait_for_common(x, timeout, TASK_INTERRUPTIBLE);
}
+EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
-void __sched interruptible_sleep_on(wait_queue_head_t *q)
+static long __sched
+sleep_on_common(wait_queue_head_t *q, int state, long timeout)
{
unsigned long flags;
wait_queue_t wait;
init_waitqueue_entry(&wait, current);
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(state);
- sleep_on_head(q, &wait, &flags);
- schedule();
- sleep_on_tail(q, &wait, &flags);
+ spin_lock_irqsave(&q->lock, flags);
+ __add_wait_queue(q, &wait);
+ spin_unlock(&q->lock);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irq(&q->lock);
+ __remove_wait_queue(q, &wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return timeout;
+}
+
+void __sched interruptible_sleep_on(wait_queue_head_t *q)
+{
+ sleep_on_common(q, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
EXPORT_SYMBOL(interruptible_sleep_on);
long __sched
interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
- unsigned long flags;
- wait_queue_t wait;
-
- init_waitqueue_entry(&wait, current);
-
- current->state = TASK_INTERRUPTIBLE;
-
- sleep_on_head(q, &wait, &flags);
- timeout = schedule_timeout(timeout);
- sleep_on_tail(q, &wait, &flags);
-
- return timeout;
+ return sleep_on_common(q, TASK_INTERRUPTIBLE, timeout);
}
EXPORT_SYMBOL(interruptible_sleep_on_timeout);
void __sched sleep_on(wait_queue_head_t *q)
{
- unsigned long flags;
- wait_queue_t wait;
-
- init_waitqueue_entry(&wait, current);
-
- current->state = TASK_UNINTERRUPTIBLE;
-
- sleep_on_head(q, &wait, &flags);
- schedule();
- sleep_on_tail(q, &wait, &flags);
+ sleep_on_common(q, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
EXPORT_SYMBOL(sleep_on);
long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
- unsigned long flags;
- wait_queue_t wait;
-
- init_waitqueue_entry(&wait, current);
-
- current->state = TASK_UNINTERRUPTIBLE;
-
- sleep_on_head(q, &wait, &flags);
- timeout = schedule_timeout(timeout);
- sleep_on_tail(q, &wait, &flags);
-
- return timeout;
+ return sleep_on_common(q, TASK_UNINTERRUPTIBLE, timeout);
}
EXPORT_SYMBOL(sleep_on_timeout);
@@ -3947,7 +3917,7 @@ EXPORT_SYMBOL(sleep_on_timeout);
void rt_mutex_setprio(struct task_struct *p, int prio)
{
unsigned long flags;
- int oldprio, on_rq;
+ int oldprio, on_rq, running;
struct rq *rq;
BUG_ON(prio < 0 || prio > MAX_PRIO);
@@ -3957,8 +3927,12 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
oldprio = p->prio;
on_rq = p->se.on_rq;
- if (on_rq)
+ running = task_running(rq, p);
+ if (on_rq) {
dequeue_task(rq, p, 0);
+ if (running)
+ p->sched_class->put_prev_task(rq, p);
+ }
if (rt_prio(prio))
p->sched_class = &rt_sched_class;
@@ -3968,13 +3942,15 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
p->prio = prio;
if (on_rq) {
+ if (running)
+ p->sched_class->set_curr_task(rq);
enqueue_task(rq, p, 0);
/*
* Reschedule if we are currently running on this runqueue and
* our priority decreased, or if we are not currently running on
* this runqueue and our priority is higher than the current's
*/
- if (task_running(rq, p)) {
+ if (running) {
if (p->prio > oldprio)
resched_task(rq->curr);
} else {
@@ -4138,7 +4114,7 @@ struct task_struct *idle_task(int cpu)
* find_process_by_pid - find a process with a matching PID value.
* @pid: the pid in question.
*/
-static inline struct task_struct *find_process_by_pid(pid_t pid)
+static struct task_struct *find_process_by_pid(pid_t pid)
{
return pid ? find_task_by_pid(pid) : current;
}
@@ -4180,7 +4156,7 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
int sched_setscheduler(struct task_struct *p, int policy,
struct sched_param *param)
{
- int retval, oldprio, oldpolicy = -1, on_rq;
+ int retval, oldprio, oldpolicy = -1, on_rq, running;
unsigned long flags;
struct rq *rq;
@@ -4262,18 +4238,26 @@ recheck:
}
update_rq_clock(rq);
on_rq = p->se.on_rq;
- if (on_rq)
+ running = task_running(rq, p);
+ if (on_rq) {
deactivate_task(rq, p, 0);
+ if (running)
+ p->sched_class->put_prev_task(rq, p);
+ }
+
oldprio = p->prio;
__setscheduler(rq, p, policy, param->sched_priority);
+
if (on_rq) {
+ if (running)
+ p->sched_class->set_curr_task(rq);
activate_task(rq, p, 0);
/*
* Reschedule if we are currently running on this runqueue and
* our priority decreased, or if we are not currently running on
* this runqueue and our priority is higher than the current's
*/
- if (task_running(rq, p)) {
+ if (running) {
if (p->prio > oldprio)
resched_task(rq->curr);
} else {
@@ -4344,10 +4328,10 @@ asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param)
asmlinkage long sys_sched_getscheduler(pid_t pid)
{
struct task_struct *p;
- int retval = -EINVAL;
+ int retval;
if (pid < 0)
- goto out_nounlock;
+ return -EINVAL;
retval = -ESRCH;
read_lock(&tasklist_lock);
@@ -4358,8 +4342,6 @@ asmlinkage long sys_sched_getscheduler(pid_t pid)
retval = p->policy;
}
read_unlock(&tasklist_lock);
-
-out_nounlock:
return retval;
}
@@ -4372,10 +4354,10 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param)
{
struct sched_param lp;
struct task_struct *p;
- int retval = -EINVAL;
+ int retval;
if (!param || pid < 0)
- goto out_nounlock;
+ return -EINVAL;
read_lock(&tasklist_lock);
p = find_process_by_pid(pid);
@@ -4395,7 +4377,6 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param)
*/
retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
-out_nounlock:
return retval;
out_unlock:
@@ -4555,8 +4536,8 @@ asmlinkage long sys_sched_yield(void)
{
struct rq *rq = this_rq_lock();
- schedstat_inc(rq, yld_cnt);
- current->sched_class->yield_task(rq, current);
+ schedstat_inc(rq, yld_count);
+ current->sched_class->yield_task(rq);
/*
* Since we are going to call schedule() anyway, there's
@@ -4750,11 +4731,12 @@ asmlinkage
long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
{
struct task_struct *p;
- int retval = -EINVAL;
+ unsigned int time_slice;
+ int retval;
struct timespec t;
if (pid < 0)
- goto out_nounlock;
+ return -EINVAL;
retval = -ESRCH;
read_lock(&tasklist_lock);
@@ -4766,12 +4748,24 @@ long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
if (retval)
goto out_unlock;
- jiffies_to_timespec(p->policy == SCHED_FIFO ?
- 0 : static_prio_timeslice(p->static_prio), &t);
+ if (p->policy == SCHED_FIFO)
+ time_slice = 0;
+ else if (p->policy == SCHED_RR)
+ time_slice = DEF_TIMESLICE;
+ else {
+ struct sched_entity *se = &p->se;
+ unsigned long flags;
+ struct rq *rq;
+
+ rq = task_rq_lock(p, &flags);
+ time_slice = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se));
+ task_rq_unlock(rq, &flags);
+ }
read_unlock(&tasklist_lock);
+ jiffies_to_timespec(time_slice, &t);
retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
-out_nounlock:
return retval;
+
out_unlock:
read_unlock(&tasklist_lock);
return retval;
@@ -4900,32 +4894,6 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
*/
cpumask_t nohz_cpu_mask = CPU_MASK_NONE;
-/*
- * Increase the granularity value when there are more CPUs,
- * because with more CPUs the 'effective latency' as visible
- * to users decreases. But the relationship is not linear,
- * so pick a second-best guess by going with the log2 of the
- * number of CPUs.
- *
- * This idea comes from the SD scheduler of Con Kolivas:
- */
-static inline void sched_init_granularity(void)
-{
- unsigned int factor = 1 + ilog2(num_online_cpus());
- const unsigned long limit = 100000000;
-
- sysctl_sched_min_granularity *= factor;
- if (sysctl_sched_min_granularity > limit)
- sysctl_sched_min_granularity = limit;
-
- sysctl_sched_latency *= factor;
- if (sysctl_sched_latency > limit)
- sysctl_sched_latency = limit;
-
- sysctl_sched_runtime_limit = sysctl_sched_latency;
- sysctl_sched_wakeup_granularity = sysctl_sched_min_granularity / 2;
-}
-
#ifdef CONFIG_SMP
/*
* This is how migration works:
@@ -5103,35 +5071,34 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p)
struct rq *rq;
int dest_cpu;
-restart:
- /* On same node? */
- mask = node_to_cpumask(cpu_to_node(dead_cpu));
- cpus_and(mask, mask, p->cpus_allowed);
- dest_cpu = any_online_cpu(mask);
-
- /* On any allowed CPU? */
- if (dest_cpu == NR_CPUS)
- dest_cpu = any_online_cpu(p->cpus_allowed);
-
- /* No more Mr. Nice Guy. */
- if (dest_cpu == NR_CPUS) {
- rq = task_rq_lock(p, &flags);
- cpus_setall(p->cpus_allowed);
- dest_cpu = any_online_cpu(p->cpus_allowed);
- task_rq_unlock(rq, &flags);
+ do {
+ /* On same node? */
+ mask = node_to_cpumask(cpu_to_node(dead_cpu));
+ cpus_and(mask, mask, p->cpus_allowed);
+ dest_cpu = any_online_cpu(mask);
+
+ /* On any allowed CPU? */
+ if (dest_cpu == NR_CPUS)
+ dest_cpu = any_online_cpu(p->cpus_allowed);
+
+ /* No more Mr. Nice Guy. */
+ if (dest_cpu == NR_CPUS) {
+ rq = task_rq_lock(p, &flags);
+ cpus_setall(p->cpus_allowed);
+ dest_cpu = any_online_cpu(p->cpus_allowed);
+ task_rq_unlock(rq, &flags);
- /*
- * Don't tell them about moving exiting tasks or
- * kernel threads (both mm NULL), since they never
- * leave kernel.
- */
- if (p->mm && printk_ratelimit())
- printk(KERN_INFO "process %d (%s) no "
- "longer affine to cpu%d\n",
- p->pid, p->comm, dead_cpu);
- }
- if (!__migrate_task(p, dead_cpu, dest_cpu))
- goto restart;
+ /*
+ * Don't tell them about moving exiting tasks or
+ * kernel threads (both mm NULL), since they never
+ * leave kernel.
+ */
+ if (p->mm && printk_ratelimit())
+ printk(KERN_INFO "process %d (%s) no "
+ "longer affine to cpu%d\n",
+ p->pid, p->comm, dead_cpu);
+ }
+ } while (!__migrate_task(p, dead_cpu, dest_cpu));
}
/*
@@ -5173,6 +5140,20 @@ static void migrate_live_tasks(int src_cpu)
}
/*
+ * activate_idle_task - move idle task to the _front_ of runqueue.
+ */
+static void activate_idle_task(struct task_struct *p, struct rq *rq)
+{
+ update_rq_clock(rq);
+
+ if (p->state == TASK_UNINTERRUPTIBLE)
+ rq->nr_uninterruptible--;
+
+ enqueue_task(rq, p, 0);
+ inc_nr_running(p, rq);
+}
+
+/*
* Schedules idle task to be the next runnable task on current CPU.
* It does so by boosting its priority to highest possible and adding it to
* the _front_ of the runqueue. Used by CPU offline code.
@@ -5284,14 +5265,23 @@ static struct ctl_table sd_ctl_root[] = {
static struct ctl_table *sd_alloc_ctl_entry(int n)
{
struct ctl_table *entry =
- kmalloc(n * sizeof(struct ctl_table), GFP_KERNEL);
-
- BUG_ON(!entry);
- memset(entry, 0, n * sizeof(struct ctl_table));
+ kcalloc(n, sizeof(struct ctl_table), GFP_KERNEL);
return entry;
}
+static void sd_free_ctl_entry(struct ctl_table **tablep)
+{
+ struct ctl_table *entry = *tablep;
+
+ for (entry = *tablep; entry->procname; entry++)
+ if (entry->child)
+ sd_free_ctl_entry(&entry->child);
+
+ kfree(*tablep);
+ *tablep = NULL;
+}
+
static void
set_table_entry(struct ctl_table *entry,
const char *procname, void *data, int maxlen,
@@ -5307,7 +5297,10 @@ set_table_entry(struct ctl_table *entry,
static struct ctl_table *
sd_alloc_ctl_domain_table(struct sched_domain *sd)
{
- struct ctl_table *table = sd_alloc_ctl_entry(14);
+ struct ctl_table *table = sd_alloc_ctl_entry(12);
+
+ if (table == NULL)
+ return NULL;
set_table_entry(&table[0], "min_interval", &sd->min_interval,
sizeof(long), 0644, proc_doulongvec_minmax);
@@ -5327,11 +5320,12 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
sizeof(int), 0644, proc_dointvec_minmax);
set_table_entry(&table[8], "imbalance_pct", &sd->imbalance_pct,
sizeof(int), 0644, proc_dointvec_minmax);
- set_table_entry(&table[10], "cache_nice_tries",
+ set_table_entry(&table[9], "cache_nice_tries",
&sd->cache_nice_tries,
sizeof(int), 0644, proc_dointvec_minmax);
- set_table_entry(&table[12], "flags", &sd->flags,
+ set_table_entry(&table[10], "flags", &sd->flags,
sizeof(int), 0644, proc_dointvec_minmax);
+ /* &table[11] is terminator */
return table;
}
@@ -5346,6 +5340,8 @@ static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
for_each_domain(cpu, sd)
domain_num++;
entry = table = sd_alloc_ctl_entry(domain_num + 1);
+ if (table == NULL)
+ return NULL;
i = 0;
for_each_domain(cpu, sd) {
@@ -5360,24 +5356,38 @@ static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
}
static struct ctl_table_header *sd_sysctl_header;
-static void init_sched_domain_sysctl(void)
+static void register_sched_domain_sysctl(void)
{
int i, cpu_num = num_online_cpus();
struct ctl_table *entry = sd_alloc_ctl_entry(cpu_num + 1);
char buf[32];
+ if (entry == NULL)
+ return;
+
sd_ctl_dir[0].child = entry;
- for (i = 0; i < cpu_num; i++, entry++) {
+ for_each_online_cpu(i) {
snprintf(buf, 32, "cpu%d", i);
entry->procname = kstrdup(buf, GFP_KERNEL);
entry->mode = 0555;
entry->child = sd_alloc_ctl_cpu_table(i);
+ entry++;
}
sd_sysctl_header = register_sysctl_table(sd_ctl_root);
}
+
+static void unregister_sched_domain_sysctl(void)
+{
+ unregister_sysctl_table(sd_sysctl_header);
+ sd_sysctl_header = NULL;
+ sd_free_ctl_entry(&sd_ctl_dir[0].child);
+}
#else
-static void init_sched_domain_sysctl(void)
+static void register_sched_domain_sysctl(void)
+{
+}
+static void unregister_sched_domain_sysctl(void)
{
}
#endif
@@ -5499,8 +5509,7 @@ int __init migration_init(void)
int nr_cpu_ids __read_mostly = NR_CPUS;
EXPORT_SYMBOL(nr_cpu_ids);
-#undef SCHED_DOMAIN_DEBUG
-#ifdef SCHED_DOMAIN_DEBUG
+#ifdef CONFIG_SCHED_DEBUG
static void sched_domain_debug(struct sched_domain *sd, int cpu)
{
int level = 0;
@@ -5558,16 +5567,19 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
printk("\n");
printk(KERN_ERR "ERROR: domain->cpu_power not "
"set\n");
+ break;
}
if (!cpus_weight(group->cpumask)) {
printk("\n");
printk(KERN_ERR "ERROR: empty group\n");
+ break;
}
if (cpus_intersects(groupmask, group->cpumask)) {
printk("\n");
printk(KERN_ERR "ERROR: repeated CPUs\n");
+ break;
}
cpus_or(groupmask, groupmask, group->cpumask);
@@ -5701,7 +5713,7 @@ static int __init isolated_cpu_setup(char *str)
return 1;
}
-__setup ("isolcpus=", isolated_cpu_setup);
+__setup("isolcpus=", isolated_cpu_setup);
/*
* init_sched_build_groups takes the cpumask we wish to span, and a pointer
@@ -5930,24 +5942,23 @@ static void init_numa_sched_groups_power(struct sched_group *group_head)
if (!sg)
return;
-next_sg:
- for_each_cpu_mask(j, sg->cpumask) {
- struct sched_domain *sd;
+ do {
+ for_each_cpu_mask(j, sg->cpumask) {
+ struct sched_domain *sd;
- sd = &per_cpu(phys_domains, j);
- if (j != first_cpu(sd->groups->cpumask)) {
- /*
- * Only add "power" once for each
- * physical package.
- */
- continue;
- }
+ sd = &per_cpu(phys_domains, j);
+ if (j != first_cpu(sd->groups->cpumask)) {
+ /*
+ * Only add "power" once for each
+ * physical package.
+ */
+ continue;
+ }
- sg_inc_cpu_power(sg, sd->groups->__cpu_power);
- }
- sg = sg->next;
- if (sg != group_head)
- goto next_sg;
+ sg_inc_cpu_power(sg, sd->groups->__cpu_power);
+ }
+ sg = sg->next;
+ } while (sg != group_head);
}
#endif
@@ -6058,7 +6069,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
/*
* Allocate the per-node list of sched groups
*/
- sched_group_nodes = kzalloc(sizeof(struct sched_group *)*MAX_NUMNODES,
+ sched_group_nodes = kcalloc(MAX_NUMNODES, sizeof(struct sched_group *),
GFP_KERNEL);
if (!sched_group_nodes) {
printk(KERN_WARNING "Can not alloc sched group node list\n");
@@ -6311,6 +6322,8 @@ static int arch_init_sched_domains(const cpumask_t *cpu_map)
err = build_sched_domains(&cpu_default_map);
+ register_sched_domain_sysctl();
+
return err;
}
@@ -6327,6 +6340,8 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
{
int i;
+ unregister_sched_domain_sysctl();
+
for_each_cpu_mask(i, *cpu_map)
cpu_attach_domain(NULL, i);
synchronize_sched();
@@ -6357,6 +6372,8 @@ int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
if (!err && !cpus_empty(*partition2))
err = build_sched_domains(partition2);
+ register_sched_domain_sysctl();
+
return err;
}
@@ -6488,17 +6505,13 @@ void __init sched_init_smp(void)
/* XXX: Theoretical race here - CPU may be hotplugged now */
hotcpu_notifier(update_sched_domains, 0);
- init_sched_domain_sysctl();
-
/* Move init over to a non-isolated CPU */
if (set_cpus_allowed(current, non_isolated_cpus) < 0)
BUG();
- sched_init_granularity();
}
#else
void __init sched_init_smp(void)
{
- sched_init_granularity();
}
#endif /* CONFIG_SMP */
@@ -6512,28 +6525,20 @@ int in_sched_functions(unsigned long addr)
&& addr < (unsigned long)__sched_text_end);
}
-static inline void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
+static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
{
cfs_rq->tasks_timeline = RB_ROOT;
- cfs_rq->fair_clock = 1;
#ifdef CONFIG_FAIR_GROUP_SCHED
cfs_rq->rq = rq;
#endif
+ cfs_rq->min_vruntime = (u64)(-(1LL << 20));
}
void __init sched_init(void)
{
- u64 now = sched_clock();
int highest_cpu = 0;
int i, j;
- /*
- * Link up the scheduling class hierarchy:
- */
- rt_sched_class.next = &fair_sched_class;
- fair_sched_class.next = &idle_sched_class;
- idle_sched_class.next = NULL;
-
for_each_possible_cpu(i) {
struct rt_prio_array *array;
struct rq *rq;
@@ -6546,10 +6551,28 @@ void __init sched_init(void)
init_cfs_rq(&rq->cfs, rq);
#ifdef CONFIG_FAIR_GROUP_SCHED
INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
- list_add(&rq->cfs.leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+ {
+ struct cfs_rq *cfs_rq = &per_cpu(init_cfs_rq, i);
+ struct sched_entity *se =
+ &per_cpu(init_sched_entity, i);
+
+ init_cfs_rq_p[i] = cfs_rq;
+ init_cfs_rq(cfs_rq, rq);
+ cfs_rq->tg = &init_task_group;
+ list_add(&cfs_rq->leaf_cfs_rq_list,
+ &rq->leaf_cfs_rq_list);
+
+ init_sched_entity_p[i] = se;
+ se->cfs_rq = &rq->cfs;
+ se->my_q = cfs_rq;
+ se->load.weight = init_task_group_load;
+ se->load.inv_weight =
+ div64_64(1ULL<<32, init_task_group_load);
+ se->parent = NULL;
+ }
+ init_task_group.shares = init_task_group_load;
+ spin_lock_init(&init_task_group.lock);
#endif
- rq->ls.load_update_last = now;
- rq->ls.load_update_start = now;
for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
rq->cpu_load[j] = 0;
@@ -6634,26 +6657,40 @@ EXPORT_SYMBOL(__might_sleep);
#endif
#ifdef CONFIG_MAGIC_SYSRQ
+static void normalize_task(struct rq *rq, struct task_struct *p)
+{
+ int on_rq;
+ update_rq_clock(rq);
+ on_rq = p->se.on_rq;
+ if (on_rq)
+ deactivate_task(rq, p, 0);
+ __setscheduler(rq, p, SCHED_NORMAL, 0);
+ if (on_rq) {
+ activate_task(rq, p, 0);
+ resched_task(rq->curr);
+ }
+}
+
void normalize_rt_tasks(void)
{
struct task_struct *g, *p;
unsigned long flags;
struct rq *rq;
- int on_rq;
read_lock_irq(&tasklist_lock);
do_each_thread(g, p) {
- p->se.fair_key = 0;
- p->se.wait_runtime = 0;
+ /*
+ * Only normalize user tasks:
+ */
+ if (!p->mm)
+ continue;
+
p->se.exec_start = 0;
- p->se.wait_start_fair = 0;
- p->se.sleep_start_fair = 0;
#ifdef CONFIG_SCHEDSTATS
p->se.wait_start = 0;
p->se.sleep_start = 0;
p->se.block_start = 0;
#endif
- task_rq(p)->cfs.fair_clock = 0;
task_rq(p)->clock = 0;
if (!rt_task(p)) {
@@ -6668,26 +6705,9 @@ void normalize_rt_tasks(void)
spin_lock_irqsave(&p->pi_lock, flags);
rq = __task_rq_lock(p);
-#ifdef CONFIG_SMP
- /*
- * Do not touch the migration thread:
- */
- if (p == rq->migration_thread)
- goto out_unlock;
-#endif
- update_rq_clock(rq);
- on_rq = p->se.on_rq;
- if (on_rq)
- deactivate_task(rq, p, 0);
- __setscheduler(rq, p, SCHED_NORMAL, 0);
- if (on_rq) {
- activate_task(rq, p, 0);
- resched_task(rq->curr);
- }
-#ifdef CONFIG_SMP
- out_unlock:
-#endif
+ normalize_task(rq, p);
+
__task_rq_unlock(rq);
spin_unlock_irqrestore(&p->pi_lock, flags);
} while_each_thread(g, p);
@@ -6740,3 +6760,201 @@ void set_curr_task(int cpu, struct task_struct *p)
}
#endif
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+/* allocate runqueue etc for a new task group */
+struct task_group *sched_create_group(void)
+{
+ struct task_group *tg;
+ struct cfs_rq *cfs_rq;
+ struct sched_entity *se;
+ struct rq *rq;
+ int i;
+
+ tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+ if (!tg)
+ return ERR_PTR(-ENOMEM);
+
+ tg->cfs_rq = kzalloc(sizeof(cfs_rq) * NR_CPUS, GFP_KERNEL);
+ if (!tg->cfs_rq)
+ goto err;
+ tg->se = kzalloc(sizeof(se) * NR_CPUS, GFP_KERNEL);
+ if (!tg->se)
+ goto err;
+
+ for_each_possible_cpu(i) {
+ rq = cpu_rq(i);
+
+ cfs_rq = kmalloc_node(sizeof(struct cfs_rq), GFP_KERNEL,
+ cpu_to_node(i));
+ if (!cfs_rq)
+ goto err;
+
+ se = kmalloc_node(sizeof(struct sched_entity), GFP_KERNEL,
+ cpu_to_node(i));
+ if (!se)
+ goto err;
+
+ memset(cfs_rq, 0, sizeof(struct cfs_rq));
+ memset(se, 0, sizeof(struct sched_entity));
+
+ tg->cfs_rq[i] = cfs_rq;
+ init_cfs_rq(cfs_rq, rq);
+ cfs_rq->tg = tg;
+
+ tg->se[i] = se;
+ se->cfs_rq = &rq->cfs;
+ se->my_q = cfs_rq;
+ se->load.weight = NICE_0_LOAD;
+ se->load.inv_weight = div64_64(1ULL<<32, NICE_0_LOAD);
+ se->parent = NULL;
+ }
+
+ for_each_possible_cpu(i) {
+ rq = cpu_rq(i);
+ cfs_rq = tg->cfs_rq[i];
+ list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+ }
+
+ tg->shares = NICE_0_LOAD;
+ spin_lock_init(&tg->lock);
+
+ return tg;
+
+err:
+ for_each_possible_cpu(i) {
+ if (tg->cfs_rq)
+ kfree(tg->cfs_rq[i]);
+ if (tg->se)
+ kfree(tg->se[i]);
+ }
+ kfree(tg->cfs_rq);
+ kfree(tg->se);
+ kfree(tg);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+/* rcu callback to free various structures associated with a task group */
+static void free_sched_group(struct rcu_head *rhp)
+{
+ struct cfs_rq *cfs_rq = container_of(rhp, struct cfs_rq, rcu);
+ struct task_group *tg = cfs_rq->tg;
+ struct sched_entity *se;
+ int i;
+
+ /* now it should be safe to free those cfs_rqs */
+ for_each_possible_cpu(i) {
+ cfs_rq = tg->cfs_rq[i];
+ kfree(cfs_rq);
+
+ se = tg->se[i];
+ kfree(se);
+ }
+
+ kfree(tg->cfs_rq);
+ kfree(tg->se);
+ kfree(tg);
+}
+
+/* Destroy runqueue etc associated with a task group */
+void sched_destroy_group(struct task_group *tg)
+{
+ struct cfs_rq *cfs_rq;
+ int i;
+
+ for_each_possible_cpu(i) {
+ cfs_rq = tg->cfs_rq[i];
+ list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
+ }
+
+ cfs_rq = tg->cfs_rq[0];
+
+ /* wait for possible concurrent references to cfs_rqs complete */
+ call_rcu(&cfs_rq->rcu, free_sched_group);
+}
+
+/* change task's runqueue when it moves between groups.
+ * The caller of this function should have put the task in its new group
+ * by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
+ * reflect its new group.
+ */
+void sched_move_task(struct task_struct *tsk)
+{
+ int on_rq, running;
+ unsigned long flags;
+ struct rq *rq;
+
+ rq = task_rq_lock(tsk, &flags);
+
+ if (tsk->sched_class != &fair_sched_class)
+ goto done;
+
+ update_rq_clock(rq);
+
+ running = task_running(rq, tsk);
+ on_rq = tsk->se.on_rq;
+
+ if (on_rq) {
+ dequeue_task(rq, tsk, 0);
+ if (unlikely(running))
+ tsk->sched_class->put_prev_task(rq, tsk);
+ }
+
+ set_task_cfs_rq(tsk);
+
+ if (on_rq) {
+ if (unlikely(running))
+ tsk->sched_class->set_curr_task(rq);
+ enqueue_task(rq, tsk, 0);
+ }
+
+done:
+ task_rq_unlock(rq, &flags);
+}
+
+static void set_se_shares(struct sched_entity *se, unsigned long shares)
+{
+ struct cfs_rq *cfs_rq = se->cfs_rq;
+ struct rq *rq = cfs_rq->rq;
+ int on_rq;
+
+ spin_lock_irq(&rq->lock);
+
+ on_rq = se->on_rq;
+ if (on_rq)
+ dequeue_entity(cfs_rq, se, 0);
+
+ se->load.weight = shares;
+ se->load.inv_weight = div64_64((1ULL<<32), shares);
+
+ if (on_rq)
+ enqueue_entity(cfs_rq, se, 0);
+
+ spin_unlock_irq(&rq->lock);
+}
+
+int sched_group_set_shares(struct task_group *tg, unsigned long shares)
+{
+ int i;
+
+ spin_lock(&tg->lock);
+ if (tg->shares == shares)
+ goto done;
+
+ tg->shares = shares;
+ for_each_possible_cpu(i)
+ set_se_shares(tg->se[i], shares);
+
+done:
+ spin_unlock(&tg->lock);
+ return 0;
+}
+
+unsigned long sched_group_shares(struct task_group *tg)
+{
+ return tg->shares;
+}
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index c3ee38bd342..a5e517ec07c 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -28,6 +28,31 @@
printk(x); \
} while (0)
+/*
+ * Ease the printing of nsec fields:
+ */
+static long long nsec_high(long long nsec)
+{
+ if (nsec < 0) {
+ nsec = -nsec;
+ do_div(nsec, 1000000);
+ return -nsec;
+ }
+ do_div(nsec, 1000000);
+
+ return nsec;
+}
+
+static unsigned long nsec_low(long long nsec)
+{
+ if (nsec < 0)
+ nsec = -nsec;
+
+ return do_div(nsec, 1000000);
+}
+
+#define SPLIT_NS(x) nsec_high(x), nsec_low(x)
+
static void
print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
{
@@ -36,23 +61,19 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
else
SEQ_printf(m, " ");
- SEQ_printf(m, "%15s %5d %15Ld %13Ld %13Ld %9Ld %5d ",
+ SEQ_printf(m, "%15s %5d %9Ld.%06ld %9Ld %5d ",
p->comm, p->pid,
- (long long)p->se.fair_key,
- (long long)(p->se.fair_key - rq->cfs.fair_clock),
- (long long)p->se.wait_runtime,
+ SPLIT_NS(p->se.vruntime),
(long long)(p->nvcsw + p->nivcsw),
p->prio);
#ifdef CONFIG_SCHEDSTATS
- SEQ_printf(m, "%15Ld %15Ld %15Ld %15Ld %15Ld\n",
- (long long)p->se.sum_exec_runtime,
- (long long)p->se.sum_wait_runtime,
- (long long)p->se.sum_sleep_runtime,
- (long long)p->se.wait_runtime_overruns,
- (long long)p->se.wait_runtime_underruns);
+ SEQ_printf(m, "%9Ld.%06ld %9Ld.%06ld %9Ld.%06ld\n",
+ SPLIT_NS(p->se.vruntime),
+ SPLIT_NS(p->se.sum_exec_runtime),
+ SPLIT_NS(p->se.sum_sleep_runtime));
#else
- SEQ_printf(m, "%15Ld %15Ld %15Ld %15Ld %15Ld\n",
- 0LL, 0LL, 0LL, 0LL, 0LL);
+ SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld\n",
+ 0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
#endif
}
@@ -62,14 +83,10 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
SEQ_printf(m,
"\nrunnable tasks:\n"
- " task PID tree-key delta waiting"
- " switches prio"
- " sum-exec sum-wait sum-sleep"
- " wait-overrun wait-underrun\n"
- "------------------------------------------------------------------"
- "----------------"
- "------------------------------------------------"
- "--------------------------------\n");
+ " task PID tree-key switches prio"
+ " exec-runtime sum-exec sum-sleep\n"
+ "------------------------------------------------------"
+ "----------------------------------------------------\n");
read_lock_irq(&tasklist_lock);
@@ -83,45 +100,48 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
read_unlock_irq(&tasklist_lock);
}
-static void
-print_cfs_rq_runtime_sum(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
+void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
{
- s64 wait_runtime_rq_sum = 0;
- struct task_struct *p;
- struct rb_node *curr;
- unsigned long flags;
+ s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1,
+ spread, rq0_min_vruntime, spread0;
struct rq *rq = &per_cpu(runqueues, cpu);
+ struct sched_entity *last;
+ unsigned long flags;
- spin_lock_irqsave(&rq->lock, flags);
- curr = first_fair(cfs_rq);
- while (curr) {
- p = rb_entry(curr, struct task_struct, se.run_node);
- wait_runtime_rq_sum += p->se.wait_runtime;
-
- curr = rb_next(curr);
- }
- spin_unlock_irqrestore(&rq->lock, flags);
-
- SEQ_printf(m, " .%-30s: %Ld\n", "wait_runtime_rq_sum",
- (long long)wait_runtime_rq_sum);
-}
-
-void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
-{
SEQ_printf(m, "\ncfs_rq\n");
-#define P(x) \
- SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(cfs_rq->x))
-
- P(fair_clock);
- P(exec_clock);
- P(wait_runtime);
- P(wait_runtime_overruns);
- P(wait_runtime_underruns);
- P(sleeper_bonus);
-#undef P
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock",
+ SPLIT_NS(cfs_rq->exec_clock));
- print_cfs_rq_runtime_sum(m, cpu, cfs_rq);
+ spin_lock_irqsave(&rq->lock, flags);
+ if (cfs_rq->rb_leftmost)
+ MIN_vruntime = (__pick_next_entity(cfs_rq))->vruntime;
+ last = __pick_last_entity(cfs_rq);
+ if (last)
+ max_vruntime = last->vruntime;
+ min_vruntime = rq->cfs.min_vruntime;
+ rq0_min_vruntime = per_cpu(runqueues, 0).cfs.min_vruntime;
+ spin_unlock_irqrestore(&rq->lock, flags);
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "MIN_vruntime",
+ SPLIT_NS(MIN_vruntime));
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "min_vruntime",
+ SPLIT_NS(min_vruntime));
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "max_vruntime",
+ SPLIT_NS(max_vruntime));
+ spread = max_vruntime - MIN_vruntime;
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread",
+ SPLIT_NS(spread));
+ spread0 = min_vruntime - rq0_min_vruntime;
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread0",
+ SPLIT_NS(spread0));
+ SEQ_printf(m, " .%-30s: %ld\n", "nr_running", cfs_rq->nr_running);
+ SEQ_printf(m, " .%-30s: %ld\n", "load", cfs_rq->load.weight);
+#ifdef CONFIG_SCHEDSTATS
+ SEQ_printf(m, " .%-30s: %ld\n", "bkl_count",
+ rq->bkl_count);
+#endif
+ SEQ_printf(m, " .%-30s: %ld\n", "nr_spread_over",
+ cfs_rq->nr_spread_over);
}
static void print_cpu(struct seq_file *m, int cpu)
@@ -141,31 +161,32 @@ static void print_cpu(struct seq_file *m, int cpu)
#define P(x) \
SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rq->x))
+#define PN(x) \
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x))
P(nr_running);
SEQ_printf(m, " .%-30s: %lu\n", "load",
- rq->ls.load.weight);
- P(ls.delta_fair);
- P(ls.delta_exec);
+ rq->load.weight);
P(nr_switches);
P(nr_load_updates);
P(nr_uninterruptible);
SEQ_printf(m, " .%-30s: %lu\n", "jiffies", jiffies);
- P(next_balance);
+ PN(next_balance);
P(curr->pid);
- P(clock);
- P(idle_clock);
- P(prev_clock_raw);
+ PN(clock);
+ PN(idle_clock);
+ PN(prev_clock_raw);
P(clock_warps);
P(clock_overflows);
P(clock_deep_idle_events);
- P(clock_max_delta);
+ PN(clock_max_delta);
P(cpu_load[0]);
P(cpu_load[1]);
P(cpu_load[2]);
P(cpu_load[3]);
P(cpu_load[4]);
#undef P
+#undef PN
print_cfs_stats(m, cpu);
@@ -177,12 +198,25 @@ static int sched_debug_show(struct seq_file *m, void *v)
u64 now = ktime_to_ns(ktime_get());
int cpu;
- SEQ_printf(m, "Sched Debug Version: v0.05-v20, %s %.*s\n",
+ SEQ_printf(m, "Sched Debug Version: v0.06-v22, %s %.*s\n",
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
- SEQ_printf(m, "now at %Lu nsecs\n", (unsigned long long)now);
+ SEQ_printf(m, "now at %Lu.%06ld msecs\n", SPLIT_NS(now));
+
+#define P(x) \
+ SEQ_printf(m, " .%-40s: %Ld\n", #x, (long long)(x))
+#define PN(x) \
+ SEQ_printf(m, " .%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x))
+ PN(sysctl_sched_latency);
+ PN(sysctl_sched_nr_latency);
+ PN(sysctl_sched_wakeup_granularity);
+ PN(sysctl_sched_batch_wakeup_granularity);
+ PN(sysctl_sched_child_runs_first);
+ P(sysctl_sched_features);
+#undef PN
+#undef P
for_each_online_cpu(cpu)
print_cpu(m, cpu);
@@ -202,7 +236,7 @@ static int sched_debug_open(struct inode *inode, struct file *filp)
return single_open(filp, sched_debug_show, NULL);
}
-static struct file_operations sched_debug_fops = {
+static const struct file_operations sched_debug_fops = {
.open = sched_debug_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -226,6 +260,7 @@ __initcall(init_sched_debug_procfs);
void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
{
+ unsigned long nr_switches;
unsigned long flags;
int num_threads = 1;
@@ -237,41 +272,89 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
rcu_read_unlock();
SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
- SEQ_printf(m, "----------------------------------------------\n");
+ SEQ_printf(m,
+ "---------------------------------------------------------\n");
+#define __P(F) \
+ SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)F)
#define P(F) \
- SEQ_printf(m, "%-25s:%20Ld\n", #F, (long long)p->F)
+ SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)p->F)
+#define __PN(F) \
+ SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
+#define PN(F) \
+ SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
- P(se.wait_runtime);
- P(se.wait_start_fair);
- P(se.exec_start);
- P(se.sleep_start_fair);
- P(se.sum_exec_runtime);
+ PN(se.exec_start);
+ PN(se.vruntime);
+ PN(se.sum_exec_runtime);
+
+ nr_switches = p->nvcsw + p->nivcsw;
#ifdef CONFIG_SCHEDSTATS
- P(se.wait_start);
- P(se.sleep_start);
- P(se.block_start);
- P(se.sleep_max);
- P(se.block_max);
- P(se.exec_max);
- P(se.wait_max);
- P(se.wait_runtime_overruns);
- P(se.wait_runtime_underruns);
- P(se.sum_wait_runtime);
+ PN(se.wait_start);
+ PN(se.sleep_start);
+ PN(se.block_start);
+ PN(se.sleep_max);
+ PN(se.block_max);
+ PN(se.exec_max);
+ PN(se.slice_max);
+ PN(se.wait_max);
+ P(sched_info.bkl_count);
+ P(se.nr_migrations);
+ P(se.nr_migrations_cold);
+ P(se.nr_failed_migrations_affine);
+ P(se.nr_failed_migrations_running);
+ P(se.nr_failed_migrations_hot);
+ P(se.nr_forced_migrations);
+ P(se.nr_forced2_migrations);
+ P(se.nr_wakeups);
+ P(se.nr_wakeups_sync);
+ P(se.nr_wakeups_migrate);
+ P(se.nr_wakeups_local);
+ P(se.nr_wakeups_remote);
+ P(se.nr_wakeups_affine);
+ P(se.nr_wakeups_affine_attempts);
+ P(se.nr_wakeups_passive);
+ P(se.nr_wakeups_idle);
+
+ {
+ u64 avg_atom, avg_per_cpu;
+
+ avg_atom = p->se.sum_exec_runtime;
+ if (nr_switches)
+ do_div(avg_atom, nr_switches);
+ else
+ avg_atom = -1LL;
+
+ avg_per_cpu = p->se.sum_exec_runtime;
+ if (p->se.nr_migrations)
+ avg_per_cpu = div64_64(avg_per_cpu, p->se.nr_migrations);
+ else
+ avg_per_cpu = -1LL;
+
+ __PN(avg_atom);
+ __PN(avg_per_cpu);
+ }
#endif
- SEQ_printf(m, "%-25s:%20Ld\n",
- "nr_switches", (long long)(p->nvcsw + p->nivcsw));
+ __P(nr_switches);
+ SEQ_printf(m, "%-35s:%21Ld\n",
+ "nr_voluntary_switches", (long long)p->nvcsw);
+ SEQ_printf(m, "%-35s:%21Ld\n",
+ "nr_involuntary_switches", (long long)p->nivcsw);
+
P(se.load.weight);
P(policy);
P(prio);
+#undef PN
+#undef __PN
#undef P
+#undef __P
{
u64 t0, t1;
t0 = sched_clock();
t1 = sched_clock();
- SEQ_printf(m, "%-25s:%20Ld\n",
+ SEQ_printf(m, "%-35s:%21Ld\n",
"clock-delta", (long long)(t1-t0));
}
}
@@ -279,9 +362,32 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
void proc_sched_set_task(struct task_struct *p)
{
#ifdef CONFIG_SCHEDSTATS
- p->se.sleep_max = p->se.block_max = p->se.exec_max = p->se.wait_max = 0;
- p->se.wait_runtime_overruns = p->se.wait_runtime_underruns = 0;
+ p->se.wait_max = 0;
+ p->se.sleep_max = 0;
+ p->se.sum_sleep_runtime = 0;
+ p->se.block_max = 0;
+ p->se.exec_max = 0;
+ p->se.slice_max = 0;
+ p->se.nr_migrations = 0;
+ p->se.nr_migrations_cold = 0;
+ p->se.nr_failed_migrations_affine = 0;
+ p->se.nr_failed_migrations_running = 0;
+ p->se.nr_failed_migrations_hot = 0;
+ p->se.nr_forced_migrations = 0;
+ p->se.nr_forced2_migrations = 0;
+ p->se.nr_wakeups = 0;
+ p->se.nr_wakeups_sync = 0;
+ p->se.nr_wakeups_migrate = 0;
+ p->se.nr_wakeups_local = 0;
+ p->se.nr_wakeups_remote = 0;
+ p->se.nr_wakeups_affine = 0;
+ p->se.nr_wakeups_affine_attempts = 0;
+ p->se.nr_wakeups_passive = 0;
+ p->se.nr_wakeups_idle = 0;
+ p->sched_info.bkl_count = 0;
#endif
- p->se.sum_exec_runtime = 0;
- p->se.prev_sum_exec_runtime = 0;
+ p->se.sum_exec_runtime = 0;
+ p->se.prev_sum_exec_runtime = 0;
+ p->nvcsw = 0;
+ p->nivcsw = 0;
}
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 67c67a87146..a17b785d700 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -25,22 +25,26 @@
* (default: 20ms, units: nanoseconds)
*
* NOTE: this latency value is not the same as the concept of
- * 'timeslice length' - timeslices in CFS are of variable length.
- * (to see the precise effective timeslice length of your workload,
- * run vmstat and monitor the context-switches field)
+ * 'timeslice length' - timeslices in CFS are of variable length
+ * and have no persistent notion like in traditional, time-slice
+ * based scheduling concepts.
*
- * On SMP systems the value of this is multiplied by the log2 of the
- * number of CPUs. (i.e. factor 2x on 2-way systems, 3x on 4-way
- * systems, 4x on 8-way systems, 5x on 16-way systems, etc.)
- * Targeted preemption latency for CPU-bound tasks:
+ * (to see the precise effective timeslice length of your workload,
+ * run vmstat and monitor the context-switches (cs) field)
*/
-unsigned int sysctl_sched_latency __read_mostly = 20000000ULL;
+const_debug unsigned int sysctl_sched_latency = 20000000ULL;
+
+/*
+ * After fork, child runs first. (default) If set to 0 then
+ * parent will (try to) run first.
+ */
+const_debug unsigned int sysctl_sched_child_runs_first = 1;
/*
* Minimal preemption granularity for CPU-bound tasks:
* (default: 2 msec, units: nanoseconds)
*/
-unsigned int sysctl_sched_min_granularity __read_mostly = 2000000ULL;
+const_debug unsigned int sysctl_sched_nr_latency = 20;
/*
* sys_sched_yield() compat mode
@@ -52,52 +56,25 @@ unsigned int __read_mostly sysctl_sched_compat_yield;
/*
* SCHED_BATCH wake-up granularity.
- * (default: 25 msec, units: nanoseconds)
+ * (default: 10 msec, units: nanoseconds)
*
* This option delays the preemption effects of decoupled workloads
* and reduces their over-scheduling. Synchronous workloads will still
* have immediate wakeup/sleep latencies.
*/
-unsigned int sysctl_sched_batch_wakeup_granularity __read_mostly = 25000000UL;
+const_debug unsigned int sysctl_sched_batch_wakeup_granularity = 10000000UL;
/*
* SCHED_OTHER wake-up granularity.
- * (default: 1 msec, units: nanoseconds)
+ * (default: 10 msec, units: nanoseconds)
*
* This option delays the preemption effects of decoupled workloads
* and reduces their over-scheduling. Synchronous workloads will still
* have immediate wakeup/sleep latencies.
*/
-unsigned int sysctl_sched_wakeup_granularity __read_mostly = 1000000UL;
-
-unsigned int sysctl_sched_stat_granularity __read_mostly;
-
-/*
- * Initialized in sched_init_granularity() [to 5 times the base granularity]:
- */
-unsigned int sysctl_sched_runtime_limit __read_mostly;
-
-/*
- * Debugging: various feature bits
- */
-enum {
- SCHED_FEAT_FAIR_SLEEPERS = 1,
- SCHED_FEAT_SLEEPER_AVG = 2,
- SCHED_FEAT_SLEEPER_LOAD_AVG = 4,
- SCHED_FEAT_PRECISE_CPU_LOAD = 8,
- SCHED_FEAT_START_DEBIT = 16,
- SCHED_FEAT_SKIP_INITIAL = 32,
-};
+const_debug unsigned int sysctl_sched_wakeup_granularity = 10000000UL;
-unsigned int sysctl_sched_features __read_mostly =
- SCHED_FEAT_FAIR_SLEEPERS *1 |
- SCHED_FEAT_SLEEPER_AVG *0 |
- SCHED_FEAT_SLEEPER_LOAD_AVG *1 |
- SCHED_FEAT_PRECISE_CPU_LOAD *1 |
- SCHED_FEAT_START_DEBIT *1 |
- SCHED_FEAT_SKIP_INITIAL *0;
-
-extern struct sched_class fair_sched_class;
+const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
/**************************************************************
* CFS operations on generic schedulable entities:
@@ -111,21 +88,9 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
return cfs_rq->rq;
}
-/* currently running entity (if any) on this cfs_rq */
-static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
-{
- return cfs_rq->curr;
-}
-
/* An entity is a task if it doesn't "own" a runqueue */
#define entity_is_task(se) (!se->my_q)
-static inline void
-set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
- cfs_rq->curr = se;
-}
-
#else /* CONFIG_FAIR_GROUP_SCHED */
static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
@@ -133,21 +98,8 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
return container_of(cfs_rq, struct rq, cfs);
}
-static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
-{
- struct rq *rq = rq_of(cfs_rq);
-
- if (unlikely(rq->curr->sched_class != &fair_sched_class))
- return NULL;
-
- return &rq->curr->se;
-}
-
#define entity_is_task(se) 1
-static inline void
-set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
-
#endif /* CONFIG_FAIR_GROUP_SCHED */
static inline struct task_struct *task_of(struct sched_entity *se)
@@ -160,16 +112,38 @@ static inline struct task_struct *task_of(struct sched_entity *se)
* Scheduling class tree data structure manipulation methods:
*/
+static inline u64 max_vruntime(u64 min_vruntime, u64 vruntime)
+{
+ s64 delta = (s64)(vruntime - min_vruntime);
+ if (delta > 0)
+ min_vruntime = vruntime;
+
+ return min_vruntime;
+}
+
+static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
+{
+ s64 delta = (s64)(vruntime - min_vruntime);
+ if (delta < 0)
+ min_vruntime = vruntime;
+
+ return min_vruntime;
+}
+
+static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+ return se->vruntime - cfs_rq->min_vruntime;
+}
+
/*
* Enqueue an entity into the rb-tree:
*/
-static inline void
-__enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
struct rb_node *parent = NULL;
struct sched_entity *entry;
- s64 key = se->fair_key;
+ s64 key = entity_key(cfs_rq, se);
int leftmost = 1;
/*
@@ -182,7 +156,7 @@ __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
* We dont care about collisions. Nodes with
* the same key stay together.
*/
- if (key - entry->fair_key < 0) {
+ if (key < entity_key(cfs_rq, entry)) {
link = &parent->rb_left;
} else {
link = &parent->rb_right;
@@ -199,24 +173,14 @@ __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
rb_link_node(&se->run_node, parent, link);
rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
- update_load_add(&cfs_rq->load, se->load.weight);
- cfs_rq->nr_running++;
- se->on_rq = 1;
-
- schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
}
-static inline void
-__dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
if (cfs_rq->rb_leftmost == &se->run_node)
cfs_rq->rb_leftmost = rb_next(&se->run_node);
- rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
- update_load_sub(&cfs_rq->load, se->load.weight);
- cfs_rq->nr_running--;
- se->on_rq = 0;
- schedstat_add(cfs_rq, wait_runtime, -se->wait_runtime);
+ rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
}
static inline struct rb_node *first_fair(struct cfs_rq *cfs_rq)
@@ -229,118 +193,86 @@ static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
return rb_entry(first_fair(cfs_rq), struct sched_entity, run_node);
}
+static inline struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
+{
+ struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
+ struct sched_entity *se = NULL;
+ struct rb_node *parent;
+
+ while (*link) {
+ parent = *link;
+ se = rb_entry(parent, struct sched_entity, run_node);
+ link = &parent->rb_right;
+ }
+
+ return se;
+}
+
/**************************************************************
* Scheduling class statistics methods:
*/
+
/*
- * Calculate the preemption granularity needed to schedule every
- * runnable task once per sysctl_sched_latency amount of time.
- * (down to a sensible low limit on granularity)
- *
- * For example, if there are 2 tasks running and latency is 10 msecs,
- * we switch tasks every 5 msecs. If we have 3 tasks running, we have
- * to switch tasks every 3.33 msecs to get a 10 msecs observed latency
- * for each task. We do finer and finer scheduling up to until we
- * reach the minimum granularity value.
- *
- * To achieve this we use the following dynamic-granularity rule:
+ * The idea is to set a period in which each task runs once.
*
- * gran = lat/nr - lat/nr/nr
+ * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
+ * this period because otherwise the slices get too small.
*
- * This comes out of the following equations:
- *
- * kA1 + gran = kB1
- * kB2 + gran = kA2
- * kA2 = kA1
- * kB2 = kB1 - d + d/nr
- * lat = d * nr
- *
- * Where 'k' is key, 'A' is task A (waiting), 'B' is task B (running),
- * '1' is start of time, '2' is end of time, 'd' is delay between
- * 1 and 2 (during which task B was running), 'nr' is number of tasks
- * running, 'lat' is the the period of each task. ('lat' is the
- * sched_latency that we aim for.)
+ * p = (nr <= nl) ? l : l*nr/nl
*/
-static long
-sched_granularity(struct cfs_rq *cfs_rq)
+static u64 __sched_period(unsigned long nr_running)
{
- unsigned int gran = sysctl_sched_latency;
- unsigned int nr = cfs_rq->nr_running;
+ u64 period = sysctl_sched_latency;
+ unsigned long nr_latency = sysctl_sched_nr_latency;
- if (nr > 1) {
- gran = gran/nr - gran/nr/nr;
- gran = max(gran, sysctl_sched_min_granularity);
+ if (unlikely(nr_running > nr_latency)) {
+ period *= nr_running;
+ do_div(period, nr_latency);
}
- return gran;
+ return period;
}
/*
- * We rescale the rescheduling granularity of tasks according to their
- * nice level, but only linearly, not exponentially:
+ * We calculate the wall-time slice from the period by taking a part
+ * proportional to the weight.
+ *
+ * s = p*w/rw
*/
-static long
-niced_granularity(struct sched_entity *curr, unsigned long granularity)
+static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- u64 tmp;
+ u64 slice = __sched_period(cfs_rq->nr_running);
- if (likely(curr->load.weight == NICE_0_LOAD))
- return granularity;
- /*
- * Positive nice levels get the same granularity as nice-0:
- */
- if (likely(curr->load.weight < NICE_0_LOAD)) {
- tmp = curr->load.weight * (u64)granularity;
- return (long) (tmp >> NICE_0_SHIFT);
- }
- /*
- * Negative nice level tasks get linearly finer
- * granularity:
- */
- tmp = curr->load.inv_weight * (u64)granularity;
+ slice *= se->load.weight;
+ do_div(slice, cfs_rq->load.weight);
- /*
- * It will always fit into 'long':
- */
- return (long) (tmp >> (WMULT_SHIFT-NICE_0_SHIFT));
+ return slice;
}
-static inline void
-limit_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se)
+/*
+ * We calculate the vruntime slice.
+ *
+ * vs = s/w = p/rw
+ */
+static u64 __sched_vslice(unsigned long rq_weight, unsigned long nr_running)
{
- long limit = sysctl_sched_runtime_limit;
+ u64 vslice = __sched_period(nr_running);
- /*
- * Niced tasks have the same history dynamic range as
- * non-niced tasks:
- */
- if (unlikely(se->wait_runtime > limit)) {
- se->wait_runtime = limit;
- schedstat_inc(se, wait_runtime_overruns);
- schedstat_inc(cfs_rq, wait_runtime_overruns);
- }
- if (unlikely(se->wait_runtime < -limit)) {
- se->wait_runtime = -limit;
- schedstat_inc(se, wait_runtime_underruns);
- schedstat_inc(cfs_rq, wait_runtime_underruns);
- }
+ do_div(vslice, rq_weight);
+
+ return vslice;
}
-static inline void
-__add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+static u64 sched_vslice(struct cfs_rq *cfs_rq)
{
- se->wait_runtime += delta;
- schedstat_add(se, sum_wait_runtime, delta);
- limit_wait_runtime(cfs_rq, se);
+ return __sched_vslice(cfs_rq->load.weight, cfs_rq->nr_running);
}
-static void
-add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+static u64 sched_vslice_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- schedstat_add(cfs_rq, wait_runtime, -se->wait_runtime);
- __add_wait_runtime(cfs_rq, se, delta);
- schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
+ return __sched_vslice(cfs_rq->load.weight + se->load.weight,
+ cfs_rq->nr_running + 1);
}
/*
@@ -348,46 +280,41 @@ add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
* are not in our scheduling class.
*/
static inline void
-__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr)
+__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
+ unsigned long delta_exec)
{
- unsigned long delta, delta_exec, delta_fair, delta_mine;
- struct load_weight *lw = &cfs_rq->load;
- unsigned long load = lw->weight;
+ unsigned long delta_exec_weighted;
+ u64 vruntime;
- delta_exec = curr->delta_exec;
schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max));
curr->sum_exec_runtime += delta_exec;
- cfs_rq->exec_clock += delta_exec;
-
- if (unlikely(!load))
- return;
-
- delta_fair = calc_delta_fair(delta_exec, lw);
- delta_mine = calc_delta_mine(delta_exec, curr->load.weight, lw);
-
- if (cfs_rq->sleeper_bonus > sysctl_sched_min_granularity) {
- delta = min((u64)delta_mine, cfs_rq->sleeper_bonus);
- delta = min(delta, (unsigned long)(
- (long)sysctl_sched_runtime_limit - curr->wait_runtime));
- cfs_rq->sleeper_bonus -= delta;
- delta_mine -= delta;
+ schedstat_add(cfs_rq, exec_clock, delta_exec);
+ delta_exec_weighted = delta_exec;
+ if (unlikely(curr->load.weight != NICE_0_LOAD)) {
+ delta_exec_weighted = calc_delta_fair(delta_exec_weighted,
+ &curr->load);
}
+ curr->vruntime += delta_exec_weighted;
- cfs_rq->fair_clock += delta_fair;
/*
- * We executed delta_exec amount of time on the CPU,
- * but we were only entitled to delta_mine amount of
- * time during that period (if nr_running == 1 then
- * the two values are equal)
- * [Note: delta_mine - delta_exec is negative]:
+ * maintain cfs_rq->min_vruntime to be a monotonic increasing
+ * value tracking the leftmost vruntime in the tree.
*/
- add_wait_runtime(cfs_rq, curr, delta_mine - delta_exec);
+ if (first_fair(cfs_rq)) {
+ vruntime = min_vruntime(curr->vruntime,
+ __pick_next_entity(cfs_rq)->vruntime);
+ } else
+ vruntime = curr->vruntime;
+
+ cfs_rq->min_vruntime =
+ max_vruntime(cfs_rq->min_vruntime, vruntime);
}
static void update_curr(struct cfs_rq *cfs_rq)
{
- struct sched_entity *curr = cfs_rq_curr(cfs_rq);
+ struct sched_entity *curr = cfs_rq->curr;
+ u64 now = rq_of(cfs_rq)->clock;
unsigned long delta_exec;
if (unlikely(!curr))
@@ -398,135 +325,47 @@ static void update_curr(struct cfs_rq *cfs_rq)
* since the last time we changed load (this cannot
* overflow on 32 bits):
*/
- delta_exec = (unsigned long)(rq_of(cfs_rq)->clock - curr->exec_start);
+ delta_exec = (unsigned long)(now - curr->exec_start);
- curr->delta_exec += delta_exec;
-
- if (unlikely(curr->delta_exec > sysctl_sched_stat_granularity)) {
- __update_curr(cfs_rq, curr);
- curr->delta_exec = 0;
- }
- curr->exec_start = rq_of(cfs_rq)->clock;
+ __update_curr(cfs_rq, curr, delta_exec);
+ curr->exec_start = now;
}
static inline void
update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- se->wait_start_fair = cfs_rq->fair_clock;
schedstat_set(se->wait_start, rq_of(cfs_rq)->clock);
}
/*
- * We calculate fair deltas here, so protect against the random effects
- * of a multiplication overflow by capping it to the runtime limit:
- */
-#if BITS_PER_LONG == 32
-static inline unsigned long
-calc_weighted(unsigned long delta, unsigned long weight, int shift)
-{
- u64 tmp = (u64)delta * weight >> shift;
-
- if (unlikely(tmp > sysctl_sched_runtime_limit*2))
- return sysctl_sched_runtime_limit*2;
- return tmp;
-}
-#else
-static inline unsigned long
-calc_weighted(unsigned long delta, unsigned long weight, int shift)
-{
- return delta * weight >> shift;
-}
-#endif
-
-/*
* Task is being enqueued - update stats:
*/
static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- s64 key;
-
/*
* Are we enqueueing a waiting task? (for current tasks
* a dequeue/enqueue event is a NOP)
*/
- if (se != cfs_rq_curr(cfs_rq))
+ if (se != cfs_rq->curr)
update_stats_wait_start(cfs_rq, se);
- /*
- * Update the key:
- */
- key = cfs_rq->fair_clock;
-
- /*
- * Optimize the common nice 0 case:
- */
- if (likely(se->load.weight == NICE_0_LOAD)) {
- key -= se->wait_runtime;
- } else {
- u64 tmp;
-
- if (se->wait_runtime < 0) {
- tmp = -se->wait_runtime;
- key += (tmp * se->load.inv_weight) >>
- (WMULT_SHIFT - NICE_0_SHIFT);
- } else {
- tmp = se->wait_runtime;
- key -= (tmp * se->load.inv_weight) >>
- (WMULT_SHIFT - NICE_0_SHIFT);
- }
- }
-
- se->fair_key = key;
-}
-
-/*
- * Note: must be called with a freshly updated rq->fair_clock.
- */
-static inline void
-__update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
- unsigned long delta_fair = se->delta_fair_run;
-
- schedstat_set(se->wait_max, max(se->wait_max,
- rq_of(cfs_rq)->clock - se->wait_start));
-
- if (unlikely(se->load.weight != NICE_0_LOAD))
- delta_fair = calc_weighted(delta_fair, se->load.weight,
- NICE_0_SHIFT);
-
- add_wait_runtime(cfs_rq, se, delta_fair);
}
static void
update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- unsigned long delta_fair;
-
- if (unlikely(!se->wait_start_fair))
- return;
-
- delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
- (u64)(cfs_rq->fair_clock - se->wait_start_fair));
-
- se->delta_fair_run += delta_fair;
- if (unlikely(abs(se->delta_fair_run) >=
- sysctl_sched_stat_granularity)) {
- __update_stats_wait_end(cfs_rq, se);
- se->delta_fair_run = 0;
- }
-
- se->wait_start_fair = 0;
+ schedstat_set(se->wait_max, max(se->wait_max,
+ rq_of(cfs_rq)->clock - se->wait_start));
schedstat_set(se->wait_start, 0);
}
static inline void
update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- update_curr(cfs_rq);
/*
* Mark the end of the wait period if dequeueing a
* waiting task:
*/
- if (se != cfs_rq_curr(cfs_rq))
+ if (se != cfs_rq->curr)
update_stats_wait_end(cfs_rq, se);
}
@@ -542,79 +381,28 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
se->exec_start = rq_of(cfs_rq)->clock;
}
-/*
- * We are descheduling a task - update its stats:
- */
-static inline void
-update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
- se->exec_start = 0;
-}
-
/**************************************************
* Scheduling class queueing methods:
*/
-static void __enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void
+account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- unsigned long load = cfs_rq->load.weight, delta_fair;
- long prev_runtime;
-
- /*
- * Do not boost sleepers if there's too much bonus 'in flight'
- * already:
- */
- if (unlikely(cfs_rq->sleeper_bonus > sysctl_sched_runtime_limit))
- return;
-
- if (sysctl_sched_features & SCHED_FEAT_SLEEPER_LOAD_AVG)
- load = rq_of(cfs_rq)->cpu_load[2];
-
- delta_fair = se->delta_fair_sleep;
-
- /*
- * Fix up delta_fair with the effect of us running
- * during the whole sleep period:
- */
- if (sysctl_sched_features & SCHED_FEAT_SLEEPER_AVG)
- delta_fair = div64_likely32((u64)delta_fair * load,
- load + se->load.weight);
-
- if (unlikely(se->load.weight != NICE_0_LOAD))
- delta_fair = calc_weighted(delta_fair, se->load.weight,
- NICE_0_SHIFT);
-
- prev_runtime = se->wait_runtime;
- __add_wait_runtime(cfs_rq, se, delta_fair);
- delta_fair = se->wait_runtime - prev_runtime;
+ update_load_add(&cfs_rq->load, se->load.weight);
+ cfs_rq->nr_running++;
+ se->on_rq = 1;
+}
- /*
- * Track the amount of bonus we've given to sleepers:
- */
- cfs_rq->sleeper_bonus += delta_fair;
+static void
+account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+ update_load_sub(&cfs_rq->load, se->load.weight);
+ cfs_rq->nr_running--;
+ se->on_rq = 0;
}
static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- struct task_struct *tsk = task_of(se);
- unsigned long delta_fair;
-
- if ((entity_is_task(se) && tsk->policy == SCHED_BATCH) ||
- !(sysctl_sched_features & SCHED_FEAT_FAIR_SLEEPERS))
- return;
-
- delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
- (u64)(cfs_rq->fair_clock - se->sleep_start_fair));
-
- se->delta_fair_sleep += delta_fair;
- if (unlikely(abs(se->delta_fair_sleep) >=
- sysctl_sched_stat_granularity)) {
- __enqueue_sleeper(cfs_rq, se);
- se->delta_fair_sleep = 0;
- }
-
- se->sleep_start_fair = 0;
-
#ifdef CONFIG_SCHEDSTATS
if (se->sleep_start) {
u64 delta = rq_of(cfs_rq)->clock - se->sleep_start;
@@ -646,6 +434,8 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
* time that the task spent sleeping:
*/
if (unlikely(prof_on == SLEEP_PROFILING)) {
+ struct task_struct *tsk = task_of(se);
+
profile_hits(SLEEP_PROFILING, (void *)get_wchan(tsk),
delta >> 20);
}
@@ -653,27 +443,81 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
#endif
}
+static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+#ifdef CONFIG_SCHED_DEBUG
+ s64 d = se->vruntime - cfs_rq->min_vruntime;
+
+ if (d < 0)
+ d = -d;
+
+ if (d > 3*sysctl_sched_latency)
+ schedstat_inc(cfs_rq, nr_spread_over);
+#endif
+}
+
+static void
+place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
+{
+ u64 vruntime;
+
+ vruntime = cfs_rq->min_vruntime;
+
+ if (sched_feat(TREE_AVG)) {
+ struct sched_entity *last = __pick_last_entity(cfs_rq);
+ if (last) {
+ vruntime += last->vruntime;
+ vruntime >>= 1;
+ }
+ } else if (sched_feat(APPROX_AVG) && cfs_rq->nr_running)
+ vruntime += sched_vslice(cfs_rq)/2;
+
+ if (initial && sched_feat(START_DEBIT))
+ vruntime += sched_vslice_add(cfs_rq, se);
+
+ if (!initial) {
+ if (sched_feat(NEW_FAIR_SLEEPERS) && entity_is_task(se) &&
+ task_of(se)->policy != SCHED_BATCH)
+ vruntime -= sysctl_sched_latency;
+
+ vruntime = max_t(s64, vruntime, se->vruntime);
+ }
+
+ se->vruntime = vruntime;
+
+}
+
static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup)
{
/*
- * Update the fair clock.
+ * Update run-time statistics of the 'current'.
*/
update_curr(cfs_rq);
- if (wakeup)
+ if (wakeup) {
+ place_entity(cfs_rq, se, 0);
enqueue_sleeper(cfs_rq, se);
+ }
update_stats_enqueue(cfs_rq, se);
- __enqueue_entity(cfs_rq, se);
+ check_spread(cfs_rq, se);
+ if (se != cfs_rq->curr)
+ __enqueue_entity(cfs_rq, se);
+ account_entity_enqueue(cfs_rq, se);
}
static void
dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
{
+ /*
+ * Update run-time statistics of the 'current'.
+ */
+ update_curr(cfs_rq);
+
update_stats_dequeue(cfs_rq, se);
if (sleep) {
- se->sleep_start_fair = cfs_rq->fair_clock;
+ se->peer_preempt = 0;
#ifdef CONFIG_SCHEDSTATS
if (entity_is_task(se)) {
struct task_struct *tsk = task_of(se);
@@ -685,68 +529,66 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
}
#endif
}
- __dequeue_entity(cfs_rq, se);
+
+ if (se != cfs_rq->curr)
+ __dequeue_entity(cfs_rq, se);
+ account_entity_dequeue(cfs_rq, se);
}
/*
* Preempt the current task with a newly woken task if needed:
*/
static void
-__check_preempt_curr_fair(struct cfs_rq *cfs_rq, struct sched_entity *se,
- struct sched_entity *curr, unsigned long granularity)
+check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
- s64 __delta = curr->fair_key - se->fair_key;
unsigned long ideal_runtime, delta_exec;
- /*
- * ideal_runtime is compared against sum_exec_runtime, which is
- * walltime, hence do not scale.
- */
- ideal_runtime = max(sysctl_sched_latency / cfs_rq->nr_running,
- (unsigned long)sysctl_sched_min_granularity);
-
- /*
- * If we executed more than what the latency constraint suggests,
- * reduce the rescheduling granularity. This way the total latency
- * of how much a task is not scheduled converges to
- * sysctl_sched_latency:
- */
+ ideal_runtime = sched_slice(cfs_rq, curr);
delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
- if (delta_exec > ideal_runtime)
- granularity = 0;
-
- /*
- * Take scheduling granularity into account - do not
- * preempt the current task unless the best task has
- * a larger than sched_granularity fairness advantage:
- *
- * scale granularity as key space is in fair_clock.
- */
- if (__delta > niced_granularity(curr, granularity))
+ if (delta_exec > ideal_runtime ||
+ (sched_feat(PREEMPT_RESTRICT) && curr->peer_preempt))
resched_task(rq_of(cfs_rq)->curr);
+ curr->peer_preempt = 0;
}
-static inline void
+static void
set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
+ /* 'current' is not kept within the tree. */
+ if (se->on_rq) {
+ /*
+ * Any task has to be enqueued before it get to execute on
+ * a CPU. So account for the time it spent waiting on the
+ * runqueue.
+ */
+ update_stats_wait_end(cfs_rq, se);
+ __dequeue_entity(cfs_rq, se);
+ }
+
+ update_stats_curr_start(cfs_rq, se);
+ cfs_rq->curr = se;
+#ifdef CONFIG_SCHEDSTATS
/*
- * Any task has to be enqueued before it get to execute on
- * a CPU. So account for the time it spent waiting on the
- * runqueue. (note, here we rely on pick_next_task() having
- * done a put_prev_task_fair() shortly before this, which
- * updated rq->fair_clock - used by update_stats_wait_end())
+ * Track our maximum slice length, if the CPU's load is at
+ * least twice that of our own weight (i.e. dont track it
+ * when there are only lesser-weight tasks around):
*/
- update_stats_wait_end(cfs_rq, se);
- update_stats_curr_start(cfs_rq, se);
- set_cfs_rq_curr(cfs_rq, se);
+ if (rq_of(cfs_rq)->load.weight >= 2*se->load.weight) {
+ se->slice_max = max(se->slice_max,
+ se->sum_exec_runtime - se->prev_sum_exec_runtime);
+ }
+#endif
se->prev_sum_exec_runtime = se->sum_exec_runtime;
}
static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
{
- struct sched_entity *se = __pick_next_entity(cfs_rq);
+ struct sched_entity *se = NULL;
- set_next_entity(cfs_rq, se);
+ if (first_fair(cfs_rq)) {
+ se = __pick_next_entity(cfs_rq);
+ set_next_entity(cfs_rq, se);
+ }
return se;
}
@@ -760,33 +602,24 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
if (prev->on_rq)
update_curr(cfs_rq);
- update_stats_curr_end(cfs_rq, prev);
-
- if (prev->on_rq)
+ check_spread(cfs_rq, prev);
+ if (prev->on_rq) {
update_stats_wait_start(cfs_rq, prev);
- set_cfs_rq_curr(cfs_rq, NULL);
+ /* Put 'current' back into the tree. */
+ __enqueue_entity(cfs_rq, prev);
+ }
+ cfs_rq->curr = NULL;
}
static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
- struct sched_entity *next;
-
/*
- * Dequeue and enqueue the task to update its
- * position within the tree:
+ * Update run-time statistics of the 'current'.
*/
- dequeue_entity(cfs_rq, curr, 0);
- enqueue_entity(cfs_rq, curr, 0);
-
- /*
- * Reschedule if another task tops the current one.
- */
- next = __pick_next_entity(cfs_rq);
- if (next == curr)
- return;
+ update_curr(cfs_rq);
- __check_preempt_curr_fair(cfs_rq, next, curr,
- sched_granularity(cfs_rq));
+ if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
+ check_preempt_tick(cfs_rq, curr);
}
/**************************************************
@@ -821,23 +654,28 @@ static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
*/
static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
{
- /* A later patch will take group into account */
- return &cpu_rq(this_cpu)->cfs;
+ return cfs_rq->tg->cfs_rq[this_cpu];
}
/* Iterate thr' all leaf cfs_rq's on a runqueue */
#define for_each_leaf_cfs_rq(rq, cfs_rq) \
list_for_each_entry(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
-/* Do the two (enqueued) tasks belong to the same group ? */
-static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+/* Do the two (enqueued) entities belong to the same group ? */
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
{
- if (curr->se.cfs_rq == p->se.cfs_rq)
+ if (se->cfs_rq == pse->cfs_rq)
return 1;
return 0;
}
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+ return se->parent;
+}
+
#else /* CONFIG_FAIR_GROUP_SCHED */
#define for_each_sched_entity(se) \
@@ -870,11 +708,17 @@ static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
#define for_each_leaf_cfs_rq(rq, cfs_rq) \
for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
-static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
{
return 1;
}
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+ return NULL;
+}
+
#endif /* CONFIG_FAIR_GROUP_SCHED */
/*
@@ -892,6 +736,7 @@ static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup)
break;
cfs_rq = cfs_rq_of(se);
enqueue_entity(cfs_rq, se, wakeup);
+ wakeup = 1;
}
}
@@ -911,6 +756,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
/* Don't dequeue parent if it has other entities besides us */
if (cfs_rq->load.weight)
break;
+ sleep = 1;
}
}
@@ -919,12 +765,10 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
*
* If compat_yield is turned on then we requeue to the end of the tree.
*/
-static void yield_task_fair(struct rq *rq, struct task_struct *p)
+static void yield_task_fair(struct rq *rq)
{
- struct cfs_rq *cfs_rq = task_cfs_rq(p);
- struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
- struct sched_entity *rightmost, *se = &p->se;
- struct rb_node *parent;
+ struct cfs_rq *cfs_rq = task_cfs_rq(rq->curr);
+ struct sched_entity *rightmost, *se = &rq->curr->se;
/*
* Are we the only task in the tree?
@@ -935,52 +779,39 @@ static void yield_task_fair(struct rq *rq, struct task_struct *p)
if (likely(!sysctl_sched_compat_yield)) {
__update_rq_clock(rq);
/*
- * Dequeue and enqueue the task to update its
- * position within the tree:
+ * Update run-time statistics of the 'current'.
*/
- dequeue_entity(cfs_rq, &p->se, 0);
- enqueue_entity(cfs_rq, &p->se, 0);
+ update_curr(cfs_rq);
return;
}
/*
* Find the rightmost entry in the rbtree:
*/
- do {
- parent = *link;
- link = &parent->rb_right;
- } while (*link);
-
- rightmost = rb_entry(parent, struct sched_entity, run_node);
+ rightmost = __pick_last_entity(cfs_rq);
/*
* Already in the rightmost position?
*/
- if (unlikely(rightmost == se))
+ if (unlikely(rightmost->vruntime < se->vruntime))
return;
/*
* Minimally necessary key value to be last in the tree:
+ * Upon rescheduling, sched_class::put_prev_task() will place
+ * 'current' within the tree based on its new key value.
*/
- se->fair_key = rightmost->fair_key + 1;
-
- if (cfs_rq->rb_leftmost == &se->run_node)
- cfs_rq->rb_leftmost = rb_next(&se->run_node);
- /*
- * Relink the task to the rightmost position:
- */
- rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
- rb_link_node(&se->run_node, parent, link);
- rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
+ se->vruntime = rightmost->vruntime + 1;
}
/*
* Preempt the current task with a newly woken task if needed:
*/
-static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
{
struct task_struct *curr = rq->curr;
struct cfs_rq *cfs_rq = task_cfs_rq(curr);
- unsigned long gran;
+ struct sched_entity *se = &curr->se, *pse = &p->se;
+ s64 delta, gran;
if (unlikely(rt_prio(p->prio))) {
update_rq_clock(rq);
@@ -988,16 +819,31 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
resched_task(curr);
return;
}
-
- gran = sysctl_sched_wakeup_granularity;
/*
- * Batch tasks prefer throughput over latency:
+ * Batch tasks do not preempt (their preemption is driven by
+ * the tick):
*/
if (unlikely(p->policy == SCHED_BATCH))
- gran = sysctl_sched_batch_wakeup_granularity;
+ return;
+
+ if (sched_feat(WAKEUP_PREEMPT)) {
+ while (!is_same_group(se, pse)) {
+ se = parent_entity(se);
+ pse = parent_entity(pse);
+ }
- if (is_same_group(curr, p))
- __check_preempt_curr_fair(cfs_rq, &p->se, &curr->se, gran);
+ delta = se->vruntime - pse->vruntime;
+ gran = sysctl_sched_wakeup_granularity;
+ if (unlikely(se->load.weight != NICE_0_LOAD))
+ gran = calc_delta_fair(gran, &se->load);
+
+ if (delta > gran) {
+ int now = !sched_feat(PREEMPT_RESTRICT);
+
+ if (now || p->prio < curr->prio || !se->peer_preempt++)
+ resched_task(curr);
+ }
+ }
}
static struct task_struct *pick_next_task_fair(struct rq *rq)
@@ -1041,7 +887,7 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
* achieve that by always pre-iterating before returning
* the current task:
*/
-static inline struct task_struct *
+static struct task_struct *
__load_balance_iterator(struct cfs_rq *cfs_rq, struct rb_node *curr)
{
struct task_struct *p;
@@ -1078,7 +924,10 @@ static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
if (!cfs_rq->nr_running)
return MAX_PRIO;
- curr = __pick_next_entity(cfs_rq);
+ curr = cfs_rq->curr;
+ if (!curr)
+ curr = __pick_next_entity(cfs_rq);
+
p = task_of(curr);
return p->prio;
@@ -1153,6 +1002,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr)
}
}
+#define swap(a,b) do { typeof(a) tmp = (a); (a) = (b); (b) = tmp; } while (0)
+
/*
* Share the fairness runtime between parent and child, thus the
* total amount of pressure for CPU stays equal - new tasks
@@ -1163,37 +1014,32 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr)
static void task_new_fair(struct rq *rq, struct task_struct *p)
{
struct cfs_rq *cfs_rq = task_cfs_rq(p);
- struct sched_entity *se = &p->se, *curr = cfs_rq_curr(cfs_rq);
+ struct sched_entity *se = &p->se, *curr = cfs_rq->curr;
+ int this_cpu = smp_processor_id();
sched_info_queued(p);
update_curr(cfs_rq);
- update_stats_enqueue(cfs_rq, se);
- /*
- * Child runs first: we let it run before the parent
- * until it reschedules once. We set up the key so that
- * it will preempt the parent:
- */
- se->fair_key = curr->fair_key -
- niced_granularity(curr, sched_granularity(cfs_rq)) - 1;
- /*
- * The first wait is dominated by the child-runs-first logic,
- * so do not credit it with that waiting time yet:
- */
- if (sysctl_sched_features & SCHED_FEAT_SKIP_INITIAL)
- se->wait_start_fair = 0;
+ place_entity(cfs_rq, se, 1);
- /*
- * The statistical average of wait_runtime is about
- * -granularity/2, so initialize the task with that:
- */
- if (sysctl_sched_features & SCHED_FEAT_START_DEBIT)
- se->wait_runtime = -(sched_granularity(cfs_rq) / 2);
+ if (sysctl_sched_child_runs_first && this_cpu == task_cpu(p) &&
+ curr->vruntime < se->vruntime) {
+ /*
+ * Upon rescheduling, sched_class::put_prev_task() will place
+ * 'current' within the tree based on its new key value.
+ */
+ swap(curr->vruntime, se->vruntime);
+ }
+ update_stats_enqueue(cfs_rq, se);
+ check_spread(cfs_rq, se);
+ check_spread(cfs_rq, curr);
__enqueue_entity(cfs_rq, se);
+ account_entity_enqueue(cfs_rq, se);
+ se->peer_preempt = 0;
+ resched_task(rq->curr);
}
-#ifdef CONFIG_FAIR_GROUP_SCHED
/* Account for a task changing its policy or group.
*
* This routine is mostly called to set cfs_rq->curr field when a task
@@ -1206,21 +1052,17 @@ static void set_curr_task_fair(struct rq *rq)
for_each_sched_entity(se)
set_next_entity(cfs_rq_of(se), se);
}
-#else
-static void set_curr_task_fair(struct rq *rq)
-{
-}
-#endif
/*
* All the scheduling class methods:
*/
-struct sched_class fair_sched_class __read_mostly = {
+static const struct sched_class fair_sched_class = {
+ .next = &idle_sched_class,
.enqueue_task = enqueue_task_fair,
.dequeue_task = dequeue_task_fair,
.yield_task = yield_task_fair,
- .check_preempt_curr = check_preempt_curr_fair,
+ .check_preempt_curr = check_preempt_wakeup,
.pick_next_task = pick_next_task_fair,
.put_prev_task = put_prev_task_fair,
@@ -1237,6 +1079,9 @@ static void print_cfs_stats(struct seq_file *m, int cpu)
{
struct cfs_rq *cfs_rq;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+ print_cfs_rq(m, cpu, &cpu_rq(cpu)->cfs);
+#endif
for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
print_cfs_rq(m, cpu, cfs_rq);
}
diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c
index 3503fb2d9f9..6e2ead41516 100644
--- a/kernel/sched_idletask.c
+++ b/kernel/sched_idletask.c
@@ -50,10 +50,15 @@ static void task_tick_idle(struct rq *rq, struct task_struct *curr)
{
}
+static void set_curr_task_idle(struct rq *rq)
+{
+}
+
/*
* Simple, special scheduling class for the per-CPU idle tasks:
*/
-static struct sched_class idle_sched_class __read_mostly = {
+const struct sched_class idle_sched_class = {
+ /* .next is NULL */
/* no enqueue/yield_task for idle tasks */
/* dequeue is not valid, we print a debug message there: */
@@ -66,6 +71,7 @@ static struct sched_class idle_sched_class __read_mostly = {
.load_balance = load_balance_idle,
+ .set_curr_task = set_curr_task_idle,
.task_tick = task_tick_idle,
/* no .task_new for idle tasks */
};
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 4b87476a02d..d0097a0634e 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -7,7 +7,7 @@
* Update the current task's runtime statistics. Skip current tasks that
* are not in our scheduling class.
*/
-static inline void update_curr_rt(struct rq *rq)
+static void update_curr_rt(struct rq *rq)
{
struct task_struct *curr = rq->curr;
u64 delta_exec;
@@ -59,9 +59,9 @@ static void requeue_task_rt(struct rq *rq, struct task_struct *p)
}
static void
-yield_task_rt(struct rq *rq, struct task_struct *p)
+yield_task_rt(struct rq *rq)
{
- requeue_task_rt(rq, p);
+ requeue_task_rt(rq, rq->curr);
}
/*
@@ -206,7 +206,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p)
if (--p->time_slice)
return;
- p->time_slice = static_prio_timeslice(p->static_prio);
+ p->time_slice = DEF_TIMESLICE;
/*
* Requeue to the end of queue if we are not the only element
@@ -218,7 +218,15 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p)
}
}
-static struct sched_class rt_sched_class __read_mostly = {
+static void set_curr_task_rt(struct rq *rq)
+{
+ struct task_struct *p = rq->curr;
+
+ p->se.exec_start = rq->clock;
+}
+
+const struct sched_class rt_sched_class = {
+ .next = &fair_sched_class,
.enqueue_task = enqueue_task_rt,
.dequeue_task = dequeue_task_rt,
.yield_task = yield_task_rt,
@@ -230,5 +238,6 @@ static struct sched_class rt_sched_class __read_mostly = {
.load_balance = load_balance_rt,
+ .set_curr_task = set_curr_task_rt,
.task_tick = task_tick_rt,
};
diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h
index c20a94dda61..1c084842c3e 100644
--- a/kernel/sched_stats.h
+++ b/kernel/sched_stats.h
@@ -16,18 +16,18 @@ static int show_schedstat(struct seq_file *seq, void *v)
struct rq *rq = cpu_rq(cpu);
#ifdef CONFIG_SMP
struct sched_domain *sd;
- int dcnt = 0;
+ int dcount = 0;
#endif
/* runqueue-specific stats */
seq_printf(seq,
"cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %llu %llu %lu",
cpu, rq->yld_both_empty,
- rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt,
- rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
- rq->ttwu_cnt, rq->ttwu_local,
+ rq->yld_act_empty, rq->yld_exp_empty, rq->yld_count,
+ rq->sched_switch, rq->sched_count, rq->sched_goidle,
+ rq->ttwu_count, rq->ttwu_local,
rq->rq_sched_info.cpu_time,
- rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
+ rq->rq_sched_info.run_delay, rq->rq_sched_info.pcount);
seq_printf(seq, "\n");
@@ -39,12 +39,12 @@ static int show_schedstat(struct seq_file *seq, void *v)
char mask_str[NR_CPUS];
cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
- seq_printf(seq, "domain%d %s", dcnt++, mask_str);
+ seq_printf(seq, "domain%d %s", dcount++, mask_str);
for (itype = CPU_IDLE; itype < CPU_MAX_IDLE_TYPES;
itype++) {
seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
"%lu",
- sd->lb_cnt[itype],
+ sd->lb_count[itype],
sd->lb_balanced[itype],
sd->lb_failed[itype],
sd->lb_imbalance[itype],
@@ -55,9 +55,9 @@ static int show_schedstat(struct seq_file *seq, void *v)
}
seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
" %lu %lu %lu\n",
- sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
- sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
- sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
+ sd->alb_count, sd->alb_failed, sd->alb_pushed,
+ sd->sbe_count, sd->sbe_balanced, sd->sbe_pushed,
+ sd->sbf_count, sd->sbf_balanced, sd->sbf_pushed,
sd->ttwu_wake_remote, sd->ttwu_move_affine,
sd->ttwu_move_balance);
}
@@ -101,7 +101,7 @@ rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
{
if (rq) {
rq->rq_sched_info.run_delay += delta;
- rq->rq_sched_info.pcnt++;
+ rq->rq_sched_info.pcount++;
}
}
@@ -129,7 +129,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long long delta)
# define schedstat_set(var, val) do { } while (0)
#endif
-#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
+#ifdef CONFIG_SCHEDSTATS
/*
* Called when a process is dequeued from the active array and given
* the cpu. We should note that with the exception of interactive
@@ -164,7 +164,7 @@ static void sched_info_arrive(struct task_struct *t)
sched_info_dequeued(t);
t->sched_info.run_delay += delta;
t->sched_info.last_arrival = now;
- t->sched_info.pcnt++;
+ t->sched_info.pcount++;
rq_sched_info_arrive(task_rq(t), delta);
}
@@ -233,5 +233,5 @@ sched_info_switch(struct task_struct *prev, struct task_struct *next)
#else
#define sched_info_queued(t) do { } while (0)
#define sched_info_switch(t, next) do { } while (0)
-#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */
+#endif /* CONFIG_SCHEDSTATS */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c7314f95264..ec14aa8ac51 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -222,14 +222,11 @@ static ctl_table kern_table[] = {
#ifdef CONFIG_SCHED_DEBUG
{
.ctl_name = CTL_UNNUMBERED,
- .procname = "sched_min_granularity_ns",
- .data = &sysctl_sched_min_granularity,
+ .procname = "sched_nr_latency",
+ .data = &sysctl_sched_nr_latency,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
- .extra1 = &min_sched_granularity_ns,
- .extra2 = &max_sched_granularity_ns,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -266,38 +263,24 @@ static ctl_table kern_table[] = {
},
{
.ctl_name = CTL_UNNUMBERED,
- .procname = "sched_stat_granularity_ns",
- .data = &sysctl_sched_stat_granularity,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
- .extra1 = &min_wakeup_granularity_ns,
- .extra2 = &max_wakeup_granularity_ns,
- },
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "sched_runtime_limit_ns",
- .data = &sysctl_sched_runtime_limit,
+ .procname = "sched_child_runs_first",
+ .data = &sysctl_sched_child_runs_first,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
- .extra1 = &min_sched_granularity_ns,
- .extra2 = &max_sched_granularity_ns,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
- .procname = "sched_child_runs_first",
- .data = &sysctl_sched_child_runs_first,
+ .procname = "sched_features",
+ .data = &sysctl_sched_features,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
- .procname = "sched_features",
- .data = &sysctl_sched_features,
+ .procname = "sched_migration_cost",
+ .data = &sysctl_sched_migration_cost,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec,
@@ -1053,7 +1036,7 @@ static ctl_table vm_table[] = {
.strategy = &sysctl_string,
},
#endif
-#if defined(CONFIG_X86_32) || \
+#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \
(defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
{
.ctl_name = VM_VDSO_ENABLED,
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index f6635112654..8d53106a0a9 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -23,3 +23,8 @@ config HIGH_RES_TIMERS
hardware is not capable then this option only increases
the size of the kernel image.
+config GENERIC_CLOCKEVENTS_BUILD
+ bool
+ default y
+ depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR
+
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 99b6034fc86..905b0b50792 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,6 +1,6 @@
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
-obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 41dd3105ce7..822beebe664 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -194,6 +194,7 @@ void clockevents_exchange_device(struct clock_event_device *old,
local_irq_restore(flags);
}
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
/**
* clockevents_notify - notification about relevant events
*/
@@ -222,4 +223,4 @@ void clockevents_notify(unsigned long reason, void *arg)
spin_unlock(&clockevents_lock);
}
EXPORT_SYMBOL_GPL(clockevents_notify);
-
+#endif
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 0962e057766..fc3fc79b3d5 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -64,8 +64,9 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
*/
int tick_check_broadcast_device(struct clock_event_device *dev)
{
- if (tick_broadcast_device.evtdev ||
- (dev->features & CLOCK_EVT_FEAT_C3STOP))
+ if ((tick_broadcast_device.evtdev &&
+ tick_broadcast_device.evtdev->rating >= dev->rating) ||
+ (dev->features & CLOCK_EVT_FEAT_C3STOP))
return 0;
clockevents_exchange_device(NULL, dev);
@@ -176,8 +177,6 @@ static void tick_do_periodic_broadcast(void)
*/
static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
{
- dev->next_event.tv64 = KTIME_MAX;
-
tick_do_periodic_broadcast();
/*
@@ -218,26 +217,43 @@ static void tick_do_broadcast_on_off(void *why)
bc = tick_broadcast_device.evtdev;
/*
- * Is the device in broadcast mode forever or is it not
- * affected by the powerstate ?
+ * Is the device not affected by the powerstate ?
*/
- if (!dev || !tick_device_is_functional(dev) ||
- !(dev->features & CLOCK_EVT_FEAT_C3STOP))
+ if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
goto out;
- if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) {
+ /*
+ * Defect device ?
+ */
+ if (!tick_device_is_functional(dev)) {
+ /*
+ * AMD C1E wreckage fixup:
+ *
+ * Device was registered functional in the first
+ * place. Now the secondary CPU detected the C1E
+ * misfeature and notifies us to fix it up
+ */
+ if (*reason != CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
+ goto out;
+ }
+
+ switch (*reason) {
+ case CLOCK_EVT_NOTIFY_BROADCAST_ON:
+ case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
if (!cpu_isset(cpu, tick_broadcast_mask)) {
cpu_set(cpu, tick_broadcast_mask);
if (td->mode == TICKDEV_MODE_PERIODIC)
clockevents_set_mode(dev,
CLOCK_EVT_MODE_SHUTDOWN);
}
- } else {
+ break;
+ case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
if (cpu_isset(cpu, tick_broadcast_mask)) {
cpu_clear(cpu, tick_broadcast_mask);
if (td->mode == TICKDEV_MODE_PERIODIC)
tick_setup_periodic(dev, 0);
}
+ break;
}
if (cpus_empty(tick_broadcast_mask))
@@ -515,11 +531,9 @@ static void tick_broadcast_clear_oneshot(int cpu)
*/
void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
- if (bc->mode != CLOCK_EVT_MODE_ONESHOT) {
- bc->event_handler = tick_handle_oneshot_broadcast;
- clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
- bc->next_event.tv64 = KTIME_MAX;
- }
+ bc->event_handler = tick_handle_oneshot_broadcast;
+ clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+ bc->next_event.tv64 = KTIME_MAX;
}
/*
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 77a21abc871..1bea399a9ef 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -200,7 +200,7 @@ static int tick_check_new_device(struct clock_event_device *newdev)
cpu = smp_processor_id();
if (!cpu_isset(cpu, newdev->cpumask))
- goto out;
+ goto out_bc;
td = &per_cpu(tick_cpu_device, cpu);
curdev = td->evtdev;
@@ -265,7 +265,7 @@ out_bc:
*/
if (tick_check_broadcast_device(newdev))
ret = NOTIFY_STOP;
-out:
+
spin_unlock_irqrestore(&tick_device_lock, flags);
return ret;
@@ -345,6 +345,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
+ case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
tick_broadcast_on_off(reason, dev);
break;
diff --git a/kernel/user.c b/kernel/user.c
index 9ca2848fc35..f0e561e6d08 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -50,12 +50,16 @@ struct user_struct root_user = {
.uid_keyring = &root_user_keyring,
.session_keyring = &root_session_keyring,
#endif
+#ifdef CONFIG_FAIR_USER_SCHED
+ .tg = &init_task_group,
+#endif
};
/*
* These routines must be called with the uidhash spinlock held!
*/
-static inline void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
+static inline void uid_hash_insert(struct user_struct *up,
+ struct hlist_head *hashent)
{
hlist_add_head(&up->uidhash_node, hashent);
}
@@ -65,13 +69,14 @@ static inline void uid_hash_remove(struct user_struct *up)
hlist_del_init(&up->uidhash_node);
}
-static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+static inline struct user_struct *uid_hash_find(uid_t uid,
+ struct hlist_head *hashent)
{
struct user_struct *user;
struct hlist_node *h;
hlist_for_each_entry(user, h, hashent, uidhash_node) {
- if(user->uid == uid) {
+ if (user->uid == uid) {
atomic_inc(&user->__count);
return user;
}
@@ -80,6 +85,203 @@ static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *ha
return NULL;
}
+#ifdef CONFIG_FAIR_USER_SCHED
+
+static struct kobject uids_kobject; /* represents /sys/kernel/uids directory */
+static DEFINE_MUTEX(uids_mutex);
+
+static void sched_destroy_user(struct user_struct *up)
+{
+ sched_destroy_group(up->tg);
+}
+
+static int sched_create_user(struct user_struct *up)
+{
+ int rc = 0;
+
+ up->tg = sched_create_group();
+ if (IS_ERR(up->tg))
+ rc = -ENOMEM;
+
+ return rc;
+}
+
+static void sched_switch_user(struct task_struct *p)
+{
+ sched_move_task(p);
+}
+
+static inline void uids_mutex_lock(void)
+{
+ mutex_lock(&uids_mutex);
+}
+
+static inline void uids_mutex_unlock(void)
+{
+ mutex_unlock(&uids_mutex);
+}
+
+/* return cpu shares held by the user */
+ssize_t cpu_shares_show(struct kset *kset, char *buffer)
+{
+ struct user_struct *up = container_of(kset, struct user_struct, kset);
+
+ return sprintf(buffer, "%lu\n", sched_group_shares(up->tg));
+}
+
+/* modify cpu shares held by the user */
+ssize_t cpu_shares_store(struct kset *kset, const char *buffer, size_t size)
+{
+ struct user_struct *up = container_of(kset, struct user_struct, kset);
+ unsigned long shares;
+ int rc;
+
+ sscanf(buffer, "%lu", &shares);
+
+ rc = sched_group_set_shares(up->tg, shares);
+
+ return (rc ? rc : size);
+}
+
+static void user_attr_init(struct subsys_attribute *sa, char *name, int mode)
+{
+ sa->attr.name = name;
+ sa->attr.mode = mode;
+ sa->show = cpu_shares_show;
+ sa->store = cpu_shares_store;
+}
+
+/* Create "/sys/kernel/uids/<uid>" directory and
+ * "/sys/kernel/uids/<uid>/cpu_share" file for this user.
+ */
+static int user_kobject_create(struct user_struct *up)
+{
+ struct kset *kset = &up->kset;
+ struct kobject *kobj = &kset->kobj;
+ int error;
+
+ memset(kset, 0, sizeof(struct kset));
+ kobj->parent = &uids_kobject; /* create under /sys/kernel/uids dir */
+ kobject_set_name(kobj, "%d", up->uid);
+ kset_init(kset);
+ user_attr_init(&up->user_attr, "cpu_share", 0644);
+
+ error = kobject_add(kobj);
+ if (error)
+ goto done;
+
+ error = sysfs_create_file(kobj, &up->user_attr.attr);
+ if (error)
+ kobject_del(kobj);
+
+ kobject_uevent(kobj, KOBJ_ADD);
+
+done:
+ return error;
+}
+
+/* create these in sysfs filesystem:
+ * "/sys/kernel/uids" directory
+ * "/sys/kernel/uids/0" directory (for root user)
+ * "/sys/kernel/uids/0/cpu_share" file (for root user)
+ */
+int __init uids_kobject_init(void)
+{
+ int error;
+
+ /* create under /sys/kernel dir */
+ uids_kobject.parent = &kernel_subsys.kobj;
+ uids_kobject.kset = &kernel_subsys;
+ kobject_set_name(&uids_kobject, "uids");
+ kobject_init(&uids_kobject);
+
+ error = kobject_add(&uids_kobject);
+ if (!error)
+ error = user_kobject_create(&root_user);
+
+ return error;
+}
+
+/* work function to remove sysfs directory for a user and free up
+ * corresponding structures.
+ */
+static void remove_user_sysfs_dir(struct work_struct *w)
+{
+ struct user_struct *up = container_of(w, struct user_struct, work);
+ struct kobject *kobj = &up->kset.kobj;
+ unsigned long flags;
+ int remove_user = 0;
+
+ /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del()
+ * atomic.
+ */
+ uids_mutex_lock();
+
+ local_irq_save(flags);
+
+ if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
+ uid_hash_remove(up);
+ remove_user = 1;
+ spin_unlock_irqrestore(&uidhash_lock, flags);
+ } else {
+ local_irq_restore(flags);
+ }
+
+ if (!remove_user)
+ goto done;
+
+ sysfs_remove_file(kobj, &up->user_attr.attr);
+ kobject_uevent(kobj, KOBJ_REMOVE);
+ kobject_del(kobj);
+
+ sched_destroy_user(up);
+ key_put(up->uid_keyring);
+ key_put(up->session_keyring);
+ kmem_cache_free(uid_cachep, up);
+
+done:
+ uids_mutex_unlock();
+}
+
+/* IRQs are disabled and uidhash_lock is held upon function entry.
+ * IRQ state (as stored in flags) is restored and uidhash_lock released
+ * upon function exit.
+ */
+static inline void free_user(struct user_struct *up, unsigned long flags)
+{
+ /* restore back the count */
+ atomic_inc(&up->__count);
+ spin_unlock_irqrestore(&uidhash_lock, flags);
+
+ INIT_WORK(&up->work, remove_user_sysfs_dir);
+ schedule_work(&up->work);
+}
+
+#else /* CONFIG_FAIR_USER_SCHED */
+
+static void sched_destroy_user(struct user_struct *up) { }
+static int sched_create_user(struct user_struct *up) { return 0; }
+static void sched_switch_user(struct task_struct *p) { }
+static inline int user_kobject_create(struct user_struct *up) { return 0; }
+static inline void uids_mutex_lock(void) { }
+static inline void uids_mutex_unlock(void) { }
+
+/* IRQs are disabled and uidhash_lock is held upon function entry.
+ * IRQ state (as stored in flags) is restored and uidhash_lock released
+ * upon function exit.
+ */
+static inline void free_user(struct user_struct *up, unsigned long flags)
+{
+ uid_hash_remove(up);
+ spin_unlock_irqrestore(&uidhash_lock, flags);
+ sched_destroy_user(up);
+ key_put(up->uid_keyring);
+ key_put(up->session_keyring);
+ kmem_cache_free(uid_cachep, up);
+}
+
+#endif /* CONFIG_FAIR_USER_SCHED */
+
/*
* Locate the user_struct for the passed UID. If found, take a ref on it. The
* caller must undo that ref with free_uid().
@@ -106,15 +308,10 @@ void free_uid(struct user_struct *up)
return;
local_irq_save(flags);
- if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
- uid_hash_remove(up);
- spin_unlock_irqrestore(&uidhash_lock, flags);
- key_put(up->uid_keyring);
- key_put(up->session_keyring);
- kmem_cache_free(uid_cachep, up);
- } else {
+ if (atomic_dec_and_lock(&up->__count, &uidhash_lock))
+ free_user(up, flags);
+ else
local_irq_restore(flags);
- }
}
struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
@@ -122,6 +319,11 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
struct hlist_head *hashent = uidhashentry(ns, uid);
struct user_struct *up;
+ /* Make uid_hash_find() + user_kobject_create() + uid_hash_insert()
+ * atomic.
+ */
+ uids_mutex_lock();
+
spin_lock_irq(&uidhash_lock);
up = uid_hash_find(uid, hashent);
spin_unlock_irq(&uidhash_lock);
@@ -150,6 +352,22 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
return NULL;
}
+ if (sched_create_user(new) < 0) {
+ key_put(new->uid_keyring);
+ key_put(new->session_keyring);
+ kmem_cache_free(uid_cachep, new);
+ return NULL;
+ }
+
+ if (user_kobject_create(new)) {
+ sched_destroy_user(new);
+ key_put(new->uid_keyring);
+ key_put(new->session_keyring);
+ kmem_cache_free(uid_cachep, new);
+ uids_mutex_unlock();
+ return NULL;
+ }
+
/*
* Before adding this, check whether we raced
* on adding the same user already..
@@ -157,6 +375,11 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
spin_lock_irq(&uidhash_lock);
up = uid_hash_find(uid, hashent);
if (up) {
+ /* This case is not possible when CONFIG_FAIR_USER_SCHED
+ * is defined, since we serialize alloc_uid() using
+ * uids_mutex. Hence no need to call
+ * sched_destroy_user() or remove_user_sysfs_dir().
+ */
key_put(new->uid_keyring);
key_put(new->session_keyring);
kmem_cache_free(uid_cachep, new);
@@ -167,6 +390,9 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
spin_unlock_irq(&uidhash_lock);
}
+
+ uids_mutex_unlock();
+
return up;
}
@@ -184,6 +410,7 @@ void switch_uid(struct user_struct *new_user)
atomic_dec(&old_user->processes);
switch_uid_keyring(new_user);
current->user = new_user;
+ sched_switch_user(current);
/*
* We need to synchronize with __sigqueue_alloc()
diff --git a/lib/Makefile b/lib/Makefile
index 4f3f3e25650..6c4ea33bb2c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
-lib-y += kobject.o kref.o kobject_uevent.o klist.o
+lib-y += kobject.o kref.o klist.o
obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o
@@ -20,6 +20,7 @@ CFLAGS_kobject.o += -DDEBUG
CFLAGS_kobject_uevent.o += -DDEBUG
endif
+lib-$(CONFIG_HOTPLUG) += kobject_uevent.o
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
diff --git a/lib/idr.c b/lib/idr.c
index d0f1acdbfa3..09cbe2b69ed 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -120,7 +120,7 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
int n, m, sh;
struct idr_layer *p, *new;
int l, id, oid;
- long bm;
+ unsigned long bm;
id = *starting_id;
restart:
diff --git a/lib/kobject.c b/lib/kobject.c
index 4b08e0ff95c..03d40360ff1 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -2,6 +2,8 @@
* kobject.c - library routines for handling generic kernel objects
*
* Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
*
* This file is released under the GPLv2.
*
@@ -44,11 +46,11 @@ static int populate_dir(struct kobject * kobj)
return error;
}
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
{
int error = 0;
if (kobject_name(kobj)) {
- error = sysfs_create_dir(kobj, shadow_parent);
+ error = sysfs_create_dir(kobj);
if (!error) {
if ((error = populate_dir(kobj)))
sysfs_remove_dir(kobj);
@@ -131,7 +133,6 @@ void kobject_init(struct kobject * kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
- init_waitqueue_head(&kobj->poll);
kobj->kset = kset_get(kobj->kset);
}
@@ -157,12 +158,11 @@ static void unlink(struct kobject * kobj)
}
/**
- * kobject_shadow_add - add an object to the hierarchy.
+ * kobject_add - add an object to the hierarchy.
* @kobj: object.
- * @shadow_parent: sysfs directory to add to.
*/
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
{
int error = 0;
struct kobject * parent;
@@ -170,7 +170,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
if (!(kobj = kobject_get(kobj)))
return -ENOENT;
if (!kobj->k_name)
- kobj->k_name = kobj->name;
+ kobject_set_name(kobj, "NO_NAME");
if (!*kobj->k_name) {
pr_debug("kobject attempted to be registered with no name!\n");
WARN_ON(1);
@@ -181,7 +181,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
pr_debug("kobject %s: registering. parent: %s, set: %s\n",
kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",
- kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
+ kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
if (kobj->kset) {
spin_lock(&kobj->kset->list_lock);
@@ -194,7 +194,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
kobj->parent = parent;
}
- error = create_dir(kobj, shadow_parent);
+ error = create_dir(kobj);
if (error) {
/* unlink does the kobject_put() for us */
unlink(kobj);
@@ -216,16 +216,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
}
/**
- * kobject_add - add an object to the hierarchy.
- * @kobj: object.
- */
-int kobject_add(struct kobject * kobj)
-{
- return kobject_shadow_add(kobj, NULL);
-}
-
-
-/**
* kobject_register - initialize and add an object.
* @kobj: object in question.
*/
@@ -255,54 +245,50 @@ int kobject_register(struct kobject * kobj)
int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
{
int error = 0;
- int limit = KOBJ_NAME_LEN;
+ int limit;
int need;
va_list args;
- char * name;
+ char *name;
- /*
- * First, try the static array
- */
- va_start(args,fmt);
- need = vsnprintf(kobj->name,limit,fmt,args);
+ /* find out how big a buffer we need */
+ name = kmalloc(1024, GFP_KERNEL);
+ if (!name) {
+ error = -ENOMEM;
+ goto done;
+ }
+ va_start(args, fmt);
+ need = vsnprintf(name, 1024, fmt, args);
va_end(args);
- if (need < limit)
- name = kobj->name;
- else {
- /*
- * Need more space? Allocate it and try again
- */
- limit = need + 1;
- name = kmalloc(limit,GFP_KERNEL);
- if (!name) {
- error = -ENOMEM;
- goto Done;
- }
- va_start(args,fmt);
- need = vsnprintf(name,limit,fmt,args);
- va_end(args);
-
- /* Still? Give up. */
- if (need >= limit) {
- kfree(name);
- error = -EFAULT;
- goto Done;
- }
+ kfree(name);
+
+ /* Allocate the new space and copy the string in */
+ limit = need + 1;
+ name = kmalloc(limit, GFP_KERNEL);
+ if (!name) {
+ error = -ENOMEM;
+ goto done;
+ }
+ va_start(args, fmt);
+ need = vsnprintf(name, limit, fmt, args);
+ va_end(args);
+
+ /* something wrong with the string we copied? */
+ if (need >= limit) {
+ kfree(name);
+ error = -EFAULT;
+ goto done;
}
/* Free the old name, if necessary. */
- if (kobj->k_name && kobj->k_name != kobj->name)
- kfree(kobj->k_name);
+ kfree(kobj->k_name);
/* Now, set the new name */
kobj->k_name = name;
- Done:
+done:
return error;
}
-
EXPORT_SYMBOL(kobject_set_name);
-
/**
* kobject_rename - change the name of an object
* @kobj: object in question.
@@ -338,7 +324,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
/* Note : if we want to send the new name alone, not the full path,
* we could probably use kobject_name(kobj); */
- error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+ error = sysfs_rename_dir(kobj, new_name);
/* This function is mostly/only used for network interface.
* Some hotplug package track interfaces by their name and
@@ -355,27 +341,6 @@ out:
}
/**
- * kobject_rename - change the name of an object
- * @kobj: object in question.
- * @new_parent: object's new parent
- * @new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
- struct sysfs_dirent *new_parent, const char *new_name)
-{
- int error = 0;
-
- kobj = kobject_get(kobj);
- if (!kobj)
- return -EINVAL;
- error = sysfs_rename_dir(kobj, new_parent, new_name);
- kobject_put(kobj);
-
- return error;
-}
-
-/**
* kobject_move - move object to another parent
* @kobj: object in question.
* @new_parent: object's new parent (can be NULL)
@@ -477,13 +442,16 @@ void kobject_cleanup(struct kobject * kobj)
struct kobj_type * t = get_ktype(kobj);
struct kset * s = kobj->kset;
struct kobject * parent = kobj->parent;
+ const char *name = kobj->k_name;
pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
- if (kobj->k_name != kobj->name)
- kfree(kobj->k_name);
- kobj->k_name = NULL;
- if (t && t->release)
+ if (t && t->release) {
t->release(kobj);
+ /* If we have a release function, we can guess that this was
+ * not a statically allocated kobject, so we should be safe to
+ * free the name */
+ kfree(name);
+ }
if (s)
kset_put(s);
kobject_put(parent);
@@ -651,11 +619,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
return ret;
}
-void subsystem_init(struct kset *s)
-{
- kset_init(s);
-}
-
int subsystem_register(struct kset *s)
{
return kset_register(s);
@@ -679,9 +642,9 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a)
if (!s || !a)
return -EINVAL;
- if (subsys_get(s)) {
+ if (kset_get(s)) {
error = sysfs_create_file(&s->kobj, &a->attr);
- subsys_put(s);
+ kset_put(s);
}
return error;
}
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index e06a8dcec0f..2e4eae5b082 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -22,31 +22,62 @@
#include <linux/kobject.h>
#include <net/sock.h>
-#define BUFFER_SIZE 2048 /* buffer for the variables */
-#define NUM_ENVP 32 /* number of env pointers */
-/* the strings here must match the enum in include/linux/kobject.h */
-const char *kobject_actions[] = {
- "add",
- "remove",
- "change",
- "move",
- "online",
- "offline",
-};
-
-#if defined(CONFIG_HOTPLUG)
u64 uevent_seqnum;
-char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
+char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
static DEFINE_SPINLOCK(sequence_lock);
#if defined(CONFIG_NET)
static struct sock *uevent_sock;
#endif
+/* the strings here must match the enum in include/linux/kobject.h */
+static const char *kobject_actions[] = {
+ [KOBJ_ADD] = "add",
+ [KOBJ_REMOVE] = "remove",
+ [KOBJ_CHANGE] = "change",
+ [KOBJ_MOVE] = "move",
+ [KOBJ_ONLINE] = "online",
+ [KOBJ_OFFLINE] = "offline",
+};
+
+/**
+ * kobject_action_type - translate action string to numeric type
+ *
+ * @buf: buffer containing the action string, newline is ignored
+ * @len: length of buffer
+ * @type: pointer to the location to store the action type
+ *
+ * Returns 0 if the action string was recognized.
+ */
+int kobject_action_type(const char *buf, size_t count,
+ enum kobject_action *type)
+{
+ enum kobject_action action;
+ int ret = -EINVAL;
+
+ if (count && buf[count-1] == '\n')
+ count--;
+
+ if (!count)
+ goto out;
+
+ for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
+ if (strncmp(kobject_actions[action], buf, count) != 0)
+ continue;
+ if (kobject_actions[action][count] != '\0')
+ continue;
+ *type = action;
+ ret = 0;
+ break;
+ }
+out:
+ return ret;
+}
+
/**
* kobject_uevent_env - send an uevent with environmental data
*
- * @action: action that is happening (usually KOBJ_MOVE)
+ * @action: action that is happening
* @kobj: struct kobject that the action is happening to
* @envp_ext: pointer to environmental data
*
@@ -54,36 +85,26 @@ static struct sock *uevent_sock;
* corresponding error when it fails.
*/
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
- char *envp_ext[])
+ char *envp_ext[])
{
- char **envp;
- char *buffer;
- char *scratch;
- const char *action_string;
+ struct kobj_uevent_env *env;
+ const char *action_string = kobject_actions[action];
const char *devpath = NULL;
const char *subsystem;
struct kobject *top_kobj;
struct kset *kset;
struct kset_uevent_ops *uevent_ops;
u64 seq;
- char *seq_buff;
int i = 0;
int retval = 0;
- int j;
pr_debug("%s\n", __FUNCTION__);
- action_string = kobject_actions[action];
- if (!action_string) {
- pr_debug("kobject attempted to send uevent without action_string!\n");
- return -EINVAL;
- }
-
/* search the kset we belong to */
top_kobj = kobj;
- while (!top_kobj->kset && top_kobj->parent) {
+ while (!top_kobj->kset && top_kobj->parent)
top_kobj = top_kobj->parent;
- }
+
if (!top_kobj->kset) {
pr_debug("kobject attempted to send uevent without kset!\n");
return -EINVAL;
@@ -92,7 +113,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
- /* skip the event, if the filter returns zero. */
+ /* skip the event, if the filter returns zero. */
if (uevent_ops && uevent_ops->filter)
if (!uevent_ops->filter(kset, kobj)) {
pr_debug("kobject filter function caused the event to drop!\n");
@@ -109,18 +130,11 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
return 0;
}
- /* environment index */
- envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
- if (!envp)
+ /* environment buffer */
+ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ if (!env)
return -ENOMEM;
- /* environment values */
- buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (!buffer) {
- retval = -ENOMEM;
- goto exit;
- }
-
/* complete object path */
devpath = kobject_get_path(kobj, GFP_KERNEL);
if (!devpath) {
@@ -128,29 +142,29 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
goto exit;
}
- /* event environemnt for helper process only */
- envp[i++] = "HOME=/";
- envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
/* default keys */
- scratch = buffer;
- envp [i++] = scratch;
- scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
- envp [i++] = scratch;
- scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
- envp [i++] = scratch;
- scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
- for (j = 0; envp_ext && envp_ext[j]; j++)
- envp[i++] = envp_ext[j];
- /* just reserve the space, overwrite it after kset call has returned */
- envp[i++] = seq_buff = scratch;
- scratch += strlen("SEQNUM=18446744073709551616") + 1;
+ retval = add_uevent_var(env, "ACTION=%s", action_string);
+ if (retval)
+ goto exit;
+ retval = add_uevent_var(env, "DEVPATH=%s", devpath);
+ if (retval)
+ goto exit;
+ retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
+ if (retval)
+ goto exit;
+
+ /* keys passed in from the caller */
+ if (envp_ext) {
+ for (i = 0; envp_ext[i]; i++) {
+ retval = add_uevent_var(env, envp_ext[i]);
+ if (retval)
+ goto exit;
+ }
+ }
/* let the kset specific function add its stuff */
if (uevent_ops && uevent_ops->uevent) {
- retval = uevent_ops->uevent(kset, kobj,
- &envp[i], NUM_ENVP - i, scratch,
- BUFFER_SIZE - (scratch - buffer));
+ retval = uevent_ops->uevent(kset, kobj, env);
if (retval) {
pr_debug ("%s - uevent() returned %d\n",
__FUNCTION__, retval);
@@ -158,11 +172,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
}
}
- /* we will send an event, request a new sequence number */
+ /* we will send an event, so request a new sequence number */
spin_lock(&sequence_lock);
seq = ++uevent_seqnum;
spin_unlock(&sequence_lock);
- sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
+ retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
+ if (retval)
+ goto exit;
#if defined(CONFIG_NET)
/* send netlink message */
@@ -172,17 +188,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
/* allocate message with the maximum possible size */
len = strlen(action_string) + strlen(devpath) + 2;
- skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
+ skb = alloc_skb(len + env->buflen, GFP_KERNEL);
if (skb) {
+ char *scratch;
+
/* add header */
scratch = skb_put(skb, len);
sprintf(scratch, "%s@%s", action_string, devpath);
/* copy keys to our continuous event payload buffer */
- for (i = 2; envp[i]; i++) {
- len = strlen(envp[i]) + 1;
+ for (i = 0; i < env->envp_idx; i++) {
+ len = strlen(env->envp[i]) + 1;
scratch = skb_put(skb, len);
- strcpy(scratch, envp[i]);
+ strcpy(scratch, env->envp[i]);
}
NETLINK_CB(skb).dst_group = 1;
@@ -198,13 +216,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
- call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
+ retval = add_uevent_var(env, "HOME=/");
+ if (retval)
+ goto exit;
+ retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+ if (retval)
+ goto exit;
+
+ call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
}
exit:
kfree(devpath);
- kfree(buffer);
- kfree(envp);
+ kfree(env);
return retval;
}
@@ -213,7 +237,7 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env);
/**
* kobject_uevent - notify userspace by ending an uevent
*
- * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
+ * @action: action that is happening
* @kobj: struct kobject that the action is happening to
*
* Returns 0 if kobject_uevent() is completed with success or the
@@ -227,52 +251,38 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action)
EXPORT_SYMBOL_GPL(kobject_uevent);
/**
- * add_uevent_var - helper for creating event variables
- * @envp: Pointer to table of environment variables, as passed into
- * uevent() method.
- * @num_envp: Number of environment variable slots available, as
- * passed into uevent() method.
- * @cur_index: Pointer to current index into @envp. It should be
- * initialized to 0 before the first call to add_uevent_var(),
- * and will be incremented on success.
- * @buffer: Pointer to buffer for environment variables, as passed
- * into uevent() method.
- * @buffer_size: Length of @buffer, as passed into uevent() method.
- * @cur_len: Pointer to current length of space used in @buffer.
- * Should be initialized to 0 before the first call to
- * add_uevent_var(), and will be incremented on success.
- * @format: Format for creating environment variable (of the form
- * "XXX=%x") for snprintf().
+ * add_uevent_var - add key value string to the environment buffer
+ * @env: environment buffer structure
+ * @format: printf format for the key=value pair
*
* Returns 0 if environment variable was added successfully or -ENOMEM
* if no space was available.
*/
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
- const char *format, ...)
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
{
va_list args;
+ int len;
- /*
- * We check against num_envp - 1 to make sure there is at
- * least one slot left after we return, since kobject_uevent()
- * needs to set the last slot to NULL.
- */
- if (*cur_index >= num_envp - 1)
+ if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
+ printk(KERN_ERR "add_uevent_var: too many keys\n");
+ WARN_ON(1);
return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ }
va_start(args, format);
- *cur_len += vsnprintf(envp[*cur_index],
- max(buffer_size - *cur_len, 0),
- format, args) + 1;
+ len = vsnprintf(&env->buf[env->buflen],
+ sizeof(env->buf) - env->buflen,
+ format, args);
va_end(args);
- if (*cur_len > buffer_size)
+ if (len >= (sizeof(env->buf) - env->buflen)) {
+ printk(KERN_ERR "add_uevent_var: buffer size too small\n");
+ WARN_ON(1);
return -ENOMEM;
+ }
- (*cur_index)++;
+ env->envp[env->envp_idx++] = &env->buf[env->buflen];
+ env->buflen += len + 1;
return 0;
}
EXPORT_SYMBOL_GPL(add_uevent_var);
@@ -293,5 +303,3 @@ static int __init kobject_uevent_init(void)
postcore_initcall(kobject_uevent_init);
#endif
-
-#endif /* CONFIG_HOTPLUG */
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index a7381d55663..30c1400e749 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -497,6 +497,7 @@ void
swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
+ WARN_ON(irqs_disabled());
if (!(vaddr >= (void *)io_tlb_start
&& vaddr < (void *)io_tlb_end))
free_pages((unsigned long) vaddr, get_order(size));
diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile
index bf065482fa6..49f8ce5774d 100644
--- a/lib/zlib_inflate/Makefile
+++ b/lib/zlib_inflate/Makefile
@@ -15,5 +15,5 @@
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o
-zlib_inflate-objs := inffast.o inflate.o \
+zlib_inflate-objs := inffast.o inflate.o infutil.o \
inftrees.o inflate_syms.o
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 0ad1ebf0094..f5ce87b0800 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -916,50 +916,3 @@ int zlib_inflateIncomp(z_stream *z)
return Z_OK;
}
-
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-/* Utility function: initialize zlib, unpack binary blob, clean up zlib,
- * return len or negative error code. */
-int zlib_inflate_blob(void *gunzip_buf, unsigned sz, const void *buf, unsigned len)
-{
- const u8 *zbuf = buf;
- struct z_stream_s *strm;
- int rc;
-
- rc = -ENOMEM;
- strm = kmalloc(sizeof(*strm), GFP_KERNEL);
- if (strm == NULL)
- goto gunzip_nomem1;
- strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (strm->workspace == NULL)
- goto gunzip_nomem2;
-
- /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename)
- * expected to be stripped from input */
-
- strm->next_in = zbuf;
- strm->avail_in = len;
- strm->next_out = gunzip_buf;
- strm->avail_out = sz;
-
- rc = zlib_inflateInit2(strm, -MAX_WBITS);
- if (rc == Z_OK) {
- rc = zlib_inflate(strm, Z_FINISH);
- /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
- if (rc == Z_STREAM_END)
- rc = sz - strm->avail_out;
- else
- rc = -EINVAL;
- zlib_inflateEnd(strm);
- } else
- rc = -EINVAL;
-
- kfree(strm->workspace);
-gunzip_nomem2:
- kfree(strm);
-gunzip_nomem1:
- return rc; /* returns Z_OK (0) if successful */
-}
diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c
new file mode 100644
index 00000000000..4824c2cc7a0
--- /dev/null
+++ b/lib/zlib_inflate/infutil.c
@@ -0,0 +1,49 @@
+#include <linux/zutil.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+/* Utility function: initialize zlib, unpack binary blob, clean up zlib,
+ * return len or negative error code.
+ */
+int zlib_inflate_blob(void *gunzip_buf, unsigned int sz,
+ const void *buf, unsigned int len)
+{
+ const u8 *zbuf = buf;
+ struct z_stream_s *strm;
+ int rc;
+
+ rc = -ENOMEM;
+ strm = kmalloc(sizeof(*strm), GFP_KERNEL);
+ if (strm == NULL)
+ goto gunzip_nomem1;
+ strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+ if (strm->workspace == NULL)
+ goto gunzip_nomem2;
+
+ /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename)
+ * expected to be stripped from input
+ */
+ strm->next_in = zbuf;
+ strm->avail_in = len;
+ strm->next_out = gunzip_buf;
+ strm->avail_out = sz;
+
+ rc = zlib_inflateInit2(strm, -MAX_WBITS);
+ if (rc == Z_OK) {
+ rc = zlib_inflate(strm, Z_FINISH);
+ /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
+ if (rc == Z_STREAM_END)
+ rc = sz - strm->avail_out;
+ else
+ rc = -EINVAL;
+ zlib_inflateEnd(strm);
+ } else
+ rc = -EINVAL;
+
+ kfree(strm->workspace);
+gunzip_nomem2:
+ kfree(strm);
+gunzip_nomem1:
+ return rc; /* returns Z_OK (0) if successful */
+}
diff --git a/mm/migrate.c b/mm/migrate.c
index e2fdbce1874..07f22d4a431 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -972,7 +972,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
* array. Return various errors if the user did something wrong.
*/
for (i = 0; i < nr_pages; i++) {
- const void *p;
+ const void __user *p;
err = -EFAULT;
if (get_user(p, pages + i))
diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c
index f094a0879c1..9ef07eda2c4 100644
--- a/net/atm/atm_sysfs.c
+++ b/net/atm/atm_sysfs.c
@@ -105,10 +105,9 @@ static struct class_device_attribute *atm_attrs[] = {
NULL
};
-static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
+static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env)
{
struct atm_dev *adev;
- int i = 0, len = 0;
if (!cdev)
return -ENODEV;
@@ -117,11 +116,9 @@ static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char
if (!adev)
return -ENODEV;
- if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
- "NAME=%s%d", adev->type, adev->number))
+ if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 848b8fa8bed..93867bb6cc9 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -23,7 +23,7 @@
#include "br_private.h"
-int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
+int (*br_should_route_hook)(struct sk_buff *skb);
static struct llc_sap *br_stp_sap;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 3a8a015c92e..3cedd4eeeed 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -126,6 +126,10 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+
if (unlikely(is_link_local(dest))) {
/* Pause frames shouldn't be passed up by driver anyway */
if (skb->protocol == htons(ETH_P_PAUSE))
@@ -145,7 +149,7 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
case BR_STATE_FORWARDING:
if (br_should_route_hook) {
- if (br_should_route_hook(&skb))
+ if (br_should_route_hook(skb))
return skb;
dest = eth_hdr(skb)->h_dest;
}
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 8245f051ccb..da22f900e89 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -503,18 +503,14 @@ inhdr_error:
* receiving device) to make netfilter happy, the REDIRECT
* target in particular. Save the original destination IP
* address to be able to detect DNAT afterwards. */
-static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
- struct sk_buff *skb = *pskb;
__u32 len = nf_bridge_encap_header_len(skb);
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
- return NF_STOLEN;
-
if (unlikely(!pskb_may_pull(skb, len)))
goto out;
@@ -584,13 +580,11 @@ out:
* took place when the packet entered the bridge), but we
* register an IPv4 PRE_ROUTING 'sabotage' hook that will
* prevent this from happening. */
-static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
-
if (skb->dst == (struct dst_entry *)&__fake_rtable) {
dst_release(skb->dst);
skb->dst = NULL;
@@ -625,12 +619,11 @@ static int br_nf_forward_finish(struct sk_buff *skb)
* but we are still able to filter on the 'real' indev/outdev
* because of the physdev module. For ARP, indev and outdev are the
* bridge ports. */
-static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
struct nf_bridge_info *nf_bridge;
struct net_device *parent;
int pf;
@@ -648,7 +641,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
else
pf = PF_INET6;
- nf_bridge_pull_encap_header(*pskb);
+ nf_bridge_pull_encap_header(skb);
nf_bridge = skb->nf_bridge;
if (skb->pkt_type == PACKET_OTHERHOST) {
@@ -666,12 +659,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
return NF_STOLEN;
}
-static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
struct net_device **d = (struct net_device **)(skb->cb);
#ifdef CONFIG_SYSCTL
@@ -682,12 +674,12 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
if (skb->protocol != htons(ETH_P_ARP)) {
if (!IS_VLAN_ARP(skb))
return NF_ACCEPT;
- nf_bridge_pull_encap_header(*pskb);
+ nf_bridge_pull_encap_header(skb);
}
if (arp_hdr(skb)->ar_pln != 4) {
if (IS_VLAN_ARP(skb))
- nf_bridge_push_encap_header(*pskb);
+ nf_bridge_push_encap_header(skb);
return NF_ACCEPT;
}
*d = (struct net_device *)in;
@@ -709,13 +701,12 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
* NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
* will be executed.
*/
-static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct net_device *realindev;
- struct sk_buff *skb = *pskb;
struct nf_bridge_info *nf_bridge;
if (!skb->nf_bridge)
@@ -752,13 +743,12 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb)
}
/* PF_BRIDGE/POST_ROUTING ********************************************/
-static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
+static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
- struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
+ struct nf_bridge_info *nf_bridge = skb->nf_bridge;
struct net_device *realoutdev = bridge_parent(skb->dev);
int pf;
@@ -828,13 +818,13 @@ print_error:
/* IP/SABOTAGE *****************************************************/
/* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
* for the second time. */
-static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
+static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- if ((*pskb)->nf_bridge &&
- !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
+ if (skb->nf_bridge &&
+ !(skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
return NF_STOP;
}
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index c65f54e0e27..3312e8f2abe 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -435,7 +435,7 @@ int br_sysfs_addbr(struct net_device *dev)
err = kobject_register(&br->ifobj);
if (err) {
pr_info("%s: can't add kobject (directory) %s/%s\n",
- __FUNCTION__, dev->name, br->ifobj.name);
+ __FUNCTION__, dev->name, kobject_name(&br->ifobj));
goto out3;
}
return 0;
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index ffe468a632e..48a80e42328 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -15,7 +15,7 @@
#include <net/arp.h>
#include <linux/module.h>
-static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
+static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *data, unsigned int datalen)
{
@@ -23,7 +23,6 @@ static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
__be32 _sip, *siptr, _dip, *diptr;
struct arphdr _ah, *ap;
unsigned char _sha[ETH_ALEN], *shp;
- struct sk_buff *skb = *pskb;
ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
if (ap == NULL)
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index 4582659dff0..74262e9a566 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -8,29 +8,22 @@
*
*/
+#include <linux/netfilter.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
#include <net/sock.h>
-static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
+static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *data, unsigned int datalen)
{
struct ebt_nat_info *info = (struct ebt_nat_info *)data;
- if (skb_shared(*pskb) || skb_cloned(*pskb)) {
- struct sk_buff *nskb;
+ if (skb_make_writable(skb, 0))
+ return NF_DROP;
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return NF_DROP;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
- memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN);
+ memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN);
return info->target;
}
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 62d23c7b25e..6cba54309c0 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -17,7 +17,7 @@
#include <linux/netfilter_bridge/ebt_mark_t.h>
#include <linux/module.h>
-static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
+static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *data, unsigned int datalen)
{
@@ -25,13 +25,13 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
int action = info->target & -16;
if (action == MARK_SET_VALUE)
- (*pskb)->mark = info->mark;
+ skb->mark = info->mark;
else if (action == MARK_OR_VALUE)
- (*pskb)->mark |= info->mark;
+ skb->mark |= info->mark;
else if (action == MARK_AND_VALUE)
- (*pskb)->mark &= info->mark;
+ skb->mark &= info->mark;
else
- (*pskb)->mark ^= info->mark;
+ skb->mark ^= info->mark;
return info->target | ~EBT_VERDICT_BITS;
}
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index 9f378eab72d..422cb834cff 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -8,35 +8,28 @@
*
*/
+#include <linux/netfilter.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_redirect.h>
#include <linux/module.h>
#include <net/sock.h>
#include "../br_private.h"
-static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
+static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *data, unsigned int datalen)
{
struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
- if (skb_shared(*pskb) || skb_cloned(*pskb)) {
- struct sk_buff *nskb;
+ if (skb_make_writable(skb, 0))
+ return NF_DROP;
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return NF_DROP;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
if (hooknr != NF_BR_BROUTING)
- memcpy(eth_hdr(*pskb)->h_dest,
+ memcpy(eth_hdr(skb)->h_dest,
in->br_port->br->dev->dev_addr, ETH_ALEN);
else
- memcpy(eth_hdr(*pskb)->h_dest, in->dev_addr, ETH_ALEN);
- (*pskb)->pkt_type = PACKET_HOST;
+ memcpy(eth_hdr(skb)->h_dest, in->dev_addr, ETH_ALEN);
+ skb->pkt_type = PACKET_HOST;
return info->target;
}
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
index a50722182bf..425ac920904 100644
--- a/net/bridge/netfilter/ebt_snat.c
+++ b/net/bridge/netfilter/ebt_snat.c
@@ -8,6 +8,7 @@
*
*/
+#include <linux/netfilter.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
@@ -15,34 +16,26 @@
#include <linux/if_arp.h>
#include <net/arp.h>
-static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
+static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
const void *data, unsigned int datalen)
{
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
- if (skb_shared(*pskb) || skb_cloned(*pskb)) {
- struct sk_buff *nskb;
+ if (skb_make_writable(skb, 0))
+ return NF_DROP;
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return NF_DROP;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
- memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
+ memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN);
if (!(info->target & NAT_ARP_BIT) &&
- eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
+ eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
struct arphdr _ah, *ap;
- ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah);
+ ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
if (ap == NULL)
return EBT_DROP;
if (ap->ar_hln != ETH_ALEN)
goto out;
- if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN))
+ if (skb_store_bits(skb, sizeof(_ah), info->mac,ETH_ALEN))
return EBT_DROP;
}
out:
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index d37ce047893..e44519ebf1d 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -51,11 +51,11 @@ static struct ebt_table broute_table =
.me = THIS_MODULE,
};
-static int ebt_broute(struct sk_buff **pskb)
+static int ebt_broute(struct sk_buff *skb)
{
int ret;
- ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL,
+ ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL,
&broute_table);
if (ret == NF_DROP)
return 1; /* route it */
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 81d84145c41..210493f99bc 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -61,10 +61,10 @@ static struct ebt_table frame_filter =
};
static unsigned int
-ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
+ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, int (*okfn)(struct sk_buff *))
{
- return ebt_do_table(hook, pskb, in, out, &frame_filter);
+ return ebt_do_table(hook, skb, in, out, &frame_filter);
}
static struct nf_hook_ops ebt_ops_filter[] = {
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 9c50488b62e..3e58c2e5ee2 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -61,17 +61,17 @@ static struct ebt_table frame_nat =
};
static unsigned int
-ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
+ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in
, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
- return ebt_do_table(hook, pskb, in, out, &frame_nat);
+ return ebt_do_table(hook, skb, in, out, &frame_nat);
}
static unsigned int
-ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
+ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in
, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
- return ebt_do_table(hook, pskb, in, out, &frame_nat);
+ return ebt_do_table(hook, skb, in, out, &frame_nat);
}
static struct nf_hook_ops ebt_ops_nat[] = {
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 6018d0e5193..d5a09eaef91 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -142,7 +142,7 @@ static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
}
/* Do some firewalling */
-unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
+unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
struct ebt_table *table)
{
@@ -172,19 +172,19 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
base = private->entries;
i = 0;
while (i < nentries) {
- if (ebt_basic_match(point, eth_hdr(*pskb), in, out))
+ if (ebt_basic_match(point, eth_hdr(skb), in, out))
goto letscontinue;
- if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
+ if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0)
goto letscontinue;
/* increase counter */
(*(counter_base + i)).pcnt++;
- (*(counter_base + i)).bcnt+=(**pskb).len;
+ (*(counter_base + i)).bcnt += skb->len;
/* these should only watch: not modify, nor tell us
what to do with the packet */
- EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,
+ EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
out);
t = (struct ebt_entry_target *)
@@ -193,7 +193,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
if (!t->u.target->target)
verdict = ((struct ebt_standard_target *)t)->verdict;
else
- verdict = t->u.target->target(pskb, hook,
+ verdict = t->u.target->target(skb, hook,
in, out, t->data, t->target_size);
if (verdict == EBT_ACCEPT) {
read_unlock_bh(&table->lock);
diff --git a/net/core/dev.c b/net/core/dev.c
index 1e169a541ce..38b03da5c1c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -557,6 +557,7 @@ __setup("netdev=", netdev_boot_setup);
/**
* __dev_get_by_name - find a device by its name
+ * @net: the applicable net namespace
* @name: name to find
*
* Find an interface by name. Must be called under RTNL semaphore
@@ -581,6 +582,7 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name)
/**
* dev_get_by_name - find a device by its name
+ * @net: the applicable net namespace
* @name: name to find
*
* Find an interface by name. This can be called from any
@@ -604,6 +606,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name)
/**
* __dev_get_by_index - find a device by its ifindex
+ * @net: the applicable net namespace
* @ifindex: index of device
*
* Search for an interface by index. Returns %NULL if the device
@@ -629,6 +632,7 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex)
/**
* dev_get_by_index - find a device by its ifindex
+ * @net: the applicable net namespace
* @ifindex: index of device
*
* Search for an interface by index. Returns NULL if the device
@@ -651,6 +655,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
/**
* dev_getbyhwaddr - find a device by its hardware address
+ * @net: the applicable net namespace
* @type: media type of device
* @ha: hardware address
*
@@ -709,6 +714,7 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
/**
* dev_get_by_flags - find any device with given flags
+ * @net: the applicable net namespace
* @if_flags: IFF_* values
* @mask: bitmask of bits in if_flags to check
*
@@ -948,6 +954,7 @@ void netdev_state_change(struct net_device *dev)
/**
* dev_load - load a network module
+ * @net: the applicable net namespace
* @name: name of interface
*
* If a network interface is not present and the process has suitable
@@ -1185,7 +1192,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
/**
* call_netdevice_notifiers - call all network notifier blocks
* @val: value passed unmodified to notifier function
- * @v: pointer passed unmodified to notifier function
+ * @dev: net_device pointer passed unmodified to notifier function
*
* Call all network notifier blocks. Parameters and return value
* are as for raw_notifier_call_chain().
@@ -1355,22 +1362,21 @@ int skb_checksum_help(struct sk_buff *skb)
goto out_set_summed;
}
- if (skb_cloned(skb)) {
+ offset = skb->csum_start - skb_headroom(skb);
+ BUG_ON(offset >= skb_headlen(skb));
+ csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+ offset += skb->csum_offset;
+ BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
+
+ if (skb_cloned(skb) &&
+ !skb_clone_writable(skb, offset + sizeof(__sum16))) {
ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (ret)
goto out;
}
- offset = skb->csum_start - skb_headroom(skb);
- BUG_ON(offset > (int)skb->len);
- csum = skb_checksum(skb, offset, skb->len-offset, 0);
-
- offset = skb_headlen(skb) - offset;
- BUG_ON(offset <= 0);
- BUG_ON(skb->csum_offset + 2 > offset);
-
- *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) =
- csum_fold(csum);
+ *(__sum16 *)(skb->data + offset) = csum_fold(csum);
out_set_summed:
skb->ip_summed = CHECKSUM_NONE;
out:
@@ -1942,27 +1948,51 @@ static int ing_filter(struct sk_buff *skb)
struct Qdisc *q;
struct net_device *dev = skb->dev;
int result = TC_ACT_OK;
+ u32 ttl = G_TC_RTTL(skb->tc_verd);
- if (dev->qdisc_ingress) {
- __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
- if (MAX_RED_LOOP < ttl++) {
- printk(KERN_WARNING "Redir loop detected Dropping packet (%d->%d)\n",
- skb->iif, skb->dev->ifindex);
- return TC_ACT_SHOT;
- }
+ if (MAX_RED_LOOP < ttl++) {
+ printk(KERN_WARNING
+ "Redir loop detected Dropping packet (%d->%d)\n",
+ skb->iif, dev->ifindex);
+ return TC_ACT_SHOT;
+ }
+
+ skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
+ skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
- skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
+ spin_lock(&dev->ingress_lock);
+ if ((q = dev->qdisc_ingress) != NULL)
+ result = q->enqueue(skb, q);
+ spin_unlock(&dev->ingress_lock);
- skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+ return result;
+}
+
+static inline struct sk_buff *handle_ing(struct sk_buff *skb,
+ struct packet_type **pt_prev,
+ int *ret, struct net_device *orig_dev)
+{
+ if (!skb->dev->qdisc_ingress)
+ goto out;
- spin_lock(&dev->ingress_lock);
- if ((q = dev->qdisc_ingress) != NULL)
- result = q->enqueue(skb, q);
- spin_unlock(&dev->ingress_lock);
+ if (*pt_prev) {
+ *ret = deliver_skb(skb, *pt_prev, orig_dev);
+ *pt_prev = NULL;
+ } else {
+ /* Huh? Why does turning on AF_PACKET affect this? */
+ skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
+ }
+ switch (ing_filter(skb)) {
+ case TC_ACT_SHOT:
+ case TC_ACT_STOLEN:
+ kfree_skb(skb);
+ return NULL;
}
- return result;
+out:
+ skb->tc_verd = 0;
+ return skb;
}
#endif
@@ -2014,21 +2044,9 @@ int netif_receive_skb(struct sk_buff *skb)
}
#ifdef CONFIG_NET_CLS_ACT
- if (pt_prev) {
- ret = deliver_skb(skb, pt_prev, orig_dev);
- pt_prev = NULL; /* noone else should process this after*/
- } else {
- skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
- }
-
- ret = ing_filter(skb);
-
- if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
- kfree_skb(skb);
+ skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+ if (!skb)
goto out;
- }
-
- skb->tc_verd = 0;
ncls:
#endif
@@ -2097,7 +2115,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
/**
* __napi_schedule - schedule for receive
- * @napi: entry to schedule
+ * @n: entry to schedule
*
* The entry's receive function will be scheduled to run
*/
@@ -3259,6 +3277,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
/**
* dev_ioctl - network device ioctl
+ * @net: the applicable net namespace
* @cmd: command to issue
* @arg: pointer to a struct ifreq in user space
*
@@ -3436,6 +3455,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
/**
* dev_new_index - allocate an ifindex
+ * @net: the applicable net namespace
*
* Returns a suitable unique value for a new device interface
* number. The caller must hold the rtnl semaphore or the
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index c52df858d0b..cd3af59b38a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -481,6 +481,8 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey,
if (!creat)
goto out;
+ ASSERT_RTNL();
+
n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
if (!n)
goto out;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 909a03d6c0e..6628e457ddc 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -396,28 +396,22 @@ static struct attribute_group wireless_group = {
#endif /* CONFIG_SYSFS */
#ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct device *d, char **envp,
- int num_envp, char *buf, int size)
+static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
{
struct net_device *dev = to_net_dev(d);
- int retval, len = 0, i = 0;
+ int retval;
/* pass interface to uevent. */
- retval = add_uevent_var(envp, num_envp, &i,
- buf, size, &len,
- "INTERFACE=%s", dev->name);
+ retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
if (retval)
goto exit;
/* pass ifindex to uevent.
* ifindex is useful as it won't change (interface name may change)
* and is what RtNetlink uses natively. */
- retval = add_uevent_var(envp, num_envp, &i,
- buf, size, &len,
- "IFINDEX=%d", dev->ifindex);
+ retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex);
exit:
- envp[i] = NULL;
return retval;
}
#endif
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 944189d9632..70d9b5da96a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -362,6 +362,97 @@ void kfree_skb(struct sk_buff *skb)
__kfree_skb(skb);
}
+static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+{
+ new->tstamp = old->tstamp;
+ new->dev = old->dev;
+ new->transport_header = old->transport_header;
+ new->network_header = old->network_header;
+ new->mac_header = old->mac_header;
+ new->dst = dst_clone(old->dst);
+#ifdef CONFIG_INET
+ new->sp = secpath_get(old->sp);
+#endif
+ memcpy(new->cb, old->cb, sizeof(old->cb));
+ new->csum_start = old->csum_start;
+ new->csum_offset = old->csum_offset;
+ new->local_df = old->local_df;
+ new->pkt_type = old->pkt_type;
+ new->ip_summed = old->ip_summed;
+ skb_copy_queue_mapping(new, old);
+ new->priority = old->priority;
+#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
+ new->ipvs_property = old->ipvs_property;
+#endif
+ new->protocol = old->protocol;
+ new->mark = old->mark;
+ __nf_copy(new, old);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ new->nf_trace = old->nf_trace;
+#endif
+#ifdef CONFIG_NET_SCHED
+ new->tc_index = old->tc_index;
+#ifdef CONFIG_NET_CLS_ACT
+ new->tc_verd = old->tc_verd;
+#endif
+#endif
+ skb_copy_secmark(new, old);
+}
+
+static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
+{
+#define C(x) n->x = skb->x
+
+ n->next = n->prev = NULL;
+ n->sk = NULL;
+ __copy_skb_header(n, skb);
+
+ C(len);
+ C(data_len);
+ C(mac_len);
+ n->cloned = 1;
+ n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
+ n->nohdr = 0;
+ n->destructor = NULL;
+#ifdef CONFIG_NET_CLS_ACT
+ /* FIXME What is this and why don't we do it in copy_skb_header? */
+ n->tc_verd = SET_TC_VERD(n->tc_verd,0);
+ n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
+ n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
+ C(iif);
+#endif
+ C(truesize);
+ atomic_set(&n->users, 1);
+ C(head);
+ C(data);
+ C(tail);
+ C(end);
+
+ atomic_inc(&(skb_shinfo(skb)->dataref));
+ skb->cloned = 1;
+
+ return n;
+#undef C
+}
+
+/**
+ * skb_morph - morph one skb into another
+ * @dst: the skb to receive the contents
+ * @src: the skb to supply the contents
+ *
+ * This is identical to skb_clone except that the target skb is
+ * supplied by the user.
+ *
+ * The target skb is returned upon exit.
+ */
+struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
+{
+ skb_release_data(dst);
+ return __skb_clone(dst, src);
+}
+EXPORT_SYMBOL_GPL(skb_morph);
+
/**
* skb_clone - duplicate an sk_buff
* @skb: buffer to clone
@@ -393,66 +484,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
n->fclone = SKB_FCLONE_UNAVAILABLE;
}
-#define C(x) n->x = skb->x
-
- n->next = n->prev = NULL;
- n->sk = NULL;
- C(tstamp);
- C(dev);
- C(transport_header);
- C(network_header);
- C(mac_header);
- C(dst);
- dst_clone(skb->dst);
- C(sp);
-#ifdef CONFIG_INET
- secpath_get(skb->sp);
-#endif
- memcpy(n->cb, skb->cb, sizeof(skb->cb));
- C(len);
- C(data_len);
- C(mac_len);
- C(csum);
- C(local_df);
- n->cloned = 1;
- n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
- n->nohdr = 0;
- C(pkt_type);
- C(ip_summed);
- skb_copy_queue_mapping(n, skb);
- C(priority);
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
- C(ipvs_property);
-#endif
- C(protocol);
- n->destructor = NULL;
- C(mark);
- __nf_copy(n, skb);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
- defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
- C(nf_trace);
-#endif
-#ifdef CONFIG_NET_SCHED
- C(tc_index);
-#ifdef CONFIG_NET_CLS_ACT
- n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
- n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
- n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
- C(iif);
-#endif
-#endif
- skb_copy_secmark(n, skb);
- C(truesize);
- atomic_set(&n->users, 1);
- C(head);
- C(data);
- C(tail);
- C(end);
-
- atomic_inc(&(skb_shinfo(skb)->dataref));
- skb->cloned = 1;
-
- return n;
+ return __skb_clone(n, skb);
}
static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
@@ -463,50 +495,15 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
*/
unsigned long offset = new->data - old->data;
#endif
- new->sk = NULL;
- new->dev = old->dev;
- skb_copy_queue_mapping(new, old);
- new->priority = old->priority;
- new->protocol = old->protocol;
- new->dst = dst_clone(old->dst);
-#ifdef CONFIG_INET
- new->sp = secpath_get(old->sp);
-#endif
- new->csum_start = old->csum_start;
- new->csum_offset = old->csum_offset;
- new->ip_summed = old->ip_summed;
- new->transport_header = old->transport_header;
- new->network_header = old->network_header;
- new->mac_header = old->mac_header;
+
+ __copy_skb_header(new, old);
+
#ifndef NET_SKBUFF_DATA_USES_OFFSET
/* {transport,network,mac}_header are relative to skb->head */
new->transport_header += offset;
new->network_header += offset;
new->mac_header += offset;
#endif
- memcpy(new->cb, old->cb, sizeof(old->cb));
- new->local_df = old->local_df;
- new->fclone = SKB_FCLONE_UNAVAILABLE;
- new->pkt_type = old->pkt_type;
- new->tstamp = old->tstamp;
- new->destructor = NULL;
- new->mark = old->mark;
- __nf_copy(new, old);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
- defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
- new->nf_trace = old->nf_trace;
-#endif
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
- new->ipvs_property = old->ipvs_property;
-#endif
-#ifdef CONFIG_NET_SCHED
-#ifdef CONFIG_NET_CLS_ACT
- new->tc_verd = old->tc_verd;
-#endif
- new->tc_index = old->tc_index;
-#endif
- skb_copy_secmark(new, old);
- atomic_set(&new->users, 1);
skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
@@ -685,7 +682,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->transport_header += off;
skb->network_header += off;
skb->mac_header += off;
- skb->csum_start += off;
+ skb->csum_start += nhead;
skb->cloned = 0;
skb->hdr_len = 0;
skb->nohdr = 0;
diff --git a/net/core/sock.c b/net/core/sock.c
index 4ed9b507c1e..d45ecdccc6a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -869,6 +869,7 @@ static inline void sock_lock_init(struct sock *sk)
/**
* sk_alloc - All socket objects are allocated here
+ * @net: the applicable net namespace
* @family: protocol family
* @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
* @prot: struct proto associated with this new sock instance
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 006a3834fbc..cac53548c2d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -767,10 +767,9 @@ discard:
return 0;
}
-static int dccp_v6_rcv(struct sk_buff **pskb)
+static int dccp_v6_rcv(struct sk_buff *skb)
{
const struct dccp_hdr *dh;
- struct sk_buff *skb = *pskb;
struct sock *sk;
int min_cov;
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index f7fba7721e6..43fcd29046d 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -88,12 +88,12 @@ static void dnrmg_send_peer(struct sk_buff *skb)
static unsigned int dnrmg_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- dnrmg_send_peer(*pskb);
+ dnrmg_send_peer(skb);
return NF_ACCEPT;
}
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index a02c36d0a13..93fe3966805 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -10,7 +10,8 @@ obj-y := route.o inetpeer.o protocol.o \
tcp_minisocks.o tcp_cong.o \
datagram.o raw.o udp.o udplite.o \
arp.o icmp.o devinet.o af_inet.o igmp.o \
- sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o \
+ inet_fragment.o
obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
new file mode 100644
index 00000000000..484cf512858
--- /dev/null
+++ b/net/ipv4/inet_fragment.c
@@ -0,0 +1,174 @@
+/*
+ * inet fragments management
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Pavel Emelyanov <xemul@openvz.org>
+ * Started as consolidation of ipv4/ip_fragment.c,
+ * ipv6/reassembly. and ipv6 nf conntrack reassembly
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+
+#include <net/inet_frag.h>
+
+static void inet_frag_secret_rebuild(unsigned long dummy)
+{
+ struct inet_frags *f = (struct inet_frags *)dummy;
+ unsigned long now = jiffies;
+ int i;
+
+ write_lock(&f->lock);
+ get_random_bytes(&f->rnd, sizeof(u32));
+ for (i = 0; i < INETFRAGS_HASHSZ; i++) {
+ struct inet_frag_queue *q;
+ struct hlist_node *p, *n;
+
+ hlist_for_each_entry_safe(q, p, n, &f->hash[i], list) {
+ unsigned int hval = f->hashfn(q);
+
+ if (hval != i) {
+ hlist_del(&q->list);
+
+ /* Relink to new hash chain. */
+ hlist_add_head(&q->list, &f->hash[hval]);
+ }
+ }
+ }
+ write_unlock(&f->lock);
+
+ mod_timer(&f->secret_timer, now + f->ctl->secret_interval);
+}
+
+void inet_frags_init(struct inet_frags *f)
+{
+ int i;
+
+ for (i = 0; i < INETFRAGS_HASHSZ; i++)
+ INIT_HLIST_HEAD(&f->hash[i]);
+
+ INIT_LIST_HEAD(&f->lru_list);
+ rwlock_init(&f->lock);
+
+ f->rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+ (jiffies ^ (jiffies >> 6)));
+
+ f->nqueues = 0;
+ atomic_set(&f->mem, 0);
+
+ init_timer(&f->secret_timer);
+ f->secret_timer.function = inet_frag_secret_rebuild;
+ f->secret_timer.data = (unsigned long)f;
+ f->secret_timer.expires = jiffies + f->ctl->secret_interval;
+ add_timer(&f->secret_timer);
+}
+EXPORT_SYMBOL(inet_frags_init);
+
+void inet_frags_fini(struct inet_frags *f)
+{
+ del_timer(&f->secret_timer);
+}
+EXPORT_SYMBOL(inet_frags_fini);
+
+static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
+{
+ write_lock(&f->lock);
+ hlist_del(&fq->list);
+ list_del(&fq->lru_list);
+ f->nqueues--;
+ write_unlock(&f->lock);
+}
+
+void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
+{
+ if (del_timer(&fq->timer))
+ atomic_dec(&fq->refcnt);
+
+ if (!(fq->last_in & COMPLETE)) {
+ fq_unlink(fq, f);
+ atomic_dec(&fq->refcnt);
+ fq->last_in |= COMPLETE;
+ }
+}
+
+EXPORT_SYMBOL(inet_frag_kill);
+
+static inline void frag_kfree_skb(struct inet_frags *f, struct sk_buff *skb,
+ int *work)
+{
+ if (work)
+ *work -= skb->truesize;
+
+ atomic_sub(skb->truesize, &f->mem);
+ if (f->skb_free)
+ f->skb_free(skb);
+ kfree_skb(skb);
+}
+
+void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
+ int *work)
+{
+ struct sk_buff *fp;
+
+ BUG_TRAP(q->last_in & COMPLETE);
+ BUG_TRAP(del_timer(&q->timer) == 0);
+
+ /* Release all fragment data. */
+ fp = q->fragments;
+ while (fp) {
+ struct sk_buff *xp = fp->next;
+
+ frag_kfree_skb(f, fp, work);
+ fp = xp;
+ }
+
+ if (work)
+ *work -= f->qsize;
+ atomic_sub(f->qsize, &f->mem);
+
+ f->destructor(q);
+
+}
+EXPORT_SYMBOL(inet_frag_destroy);
+
+int inet_frag_evictor(struct inet_frags *f)
+{
+ struct inet_frag_queue *q;
+ int work, evicted = 0;
+
+ work = atomic_read(&f->mem) - f->ctl->low_thresh;
+ while (work > 0) {
+ read_lock(&f->lock);
+ if (list_empty(&f->lru_list)) {
+ read_unlock(&f->lock);
+ break;
+ }
+
+ q = list_first_entry(&f->lru_list,
+ struct inet_frag_queue, lru_list);
+ atomic_inc(&q->refcnt);
+ read_unlock(&f->lock);
+
+ spin_lock(&q->lock);
+ if (!(q->last_in & COMPLETE))
+ inet_frag_kill(q, f);
+ spin_unlock(&q->lock);
+
+ if (atomic_dec_and_test(&q->refcnt))
+ inet_frag_destroy(q, f, &work);
+ evicted++;
+ }
+
+ return evicted;
+}
+EXPORT_SYMBOL(inet_frag_evictor);
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index 4545b64e281..ac3b1d3dba2 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -77,7 +77,7 @@ static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph,
/* check tcp options (only timestamp allowed) */
if (tcph->doff == TCPH_LEN_W_TIMESTAMP) {
- u32 *topt = (u32 *)(tcph + 1);
+ __be32 *topt = (__be32 *)(tcph + 1);
if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8)
@@ -103,14 +103,14 @@ static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
{
struct iphdr *iph = lro_desc->iph;
struct tcphdr *tcph = lro_desc->tcph;
- u32 *p;
+ __be32 *p;
__wsum tcp_hdr_csum;
tcph->ack_seq = lro_desc->tcp_ack;
tcph->window = lro_desc->tcp_window;
if (lro_desc->tcp_saw_tstamp) {
- p = (u32 *)(tcph + 1);
+ p = (__be32 *)(tcph + 1);
*(p+2) = lro_desc->tcp_rcv_tsecr;
}
@@ -150,7 +150,7 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
u16 vlan_tag, struct vlan_group *vgrp)
{
int nr_frags;
- u32 *ptr;
+ __be32 *ptr;
u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
nr_frags = skb_shinfo(skb)->nr_frags;
@@ -159,14 +159,14 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
lro_desc->iph = iph;
lro_desc->tcph = tcph;
lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
- lro_desc->tcp_ack = ntohl(tcph->ack_seq);
+ lro_desc->tcp_ack = tcph->ack_seq;
lro_desc->tcp_window = tcph->window;
lro_desc->pkt_aggr_cnt = 1;
lro_desc->ip_tot_len = ntohs(iph->tot_len);
if (tcph->doff == 8) {
- ptr = (u32 *)(tcph+1);
+ ptr = (__be32 *)(tcph+1);
lro_desc->tcp_saw_tstamp = 1;
lro_desc->tcp_rcv_tsval = *(ptr+1);
lro_desc->tcp_rcv_tsecr = *(ptr+2);
@@ -190,7 +190,7 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
struct tcphdr *tcph, int tcp_data_len)
{
struct sk_buff *parent = lro_desc->parent;
- u32 *topt;
+ __be32 *topt;
lro_desc->pkt_aggr_cnt++;
lro_desc->ip_tot_len += tcp_data_len;
@@ -200,7 +200,7 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
/* don't update tcp_rcv_tsval, would not work with PAWS */
if (lro_desc->tcp_saw_tstamp) {
- topt = (u32 *) (tcph + 1);
+ topt = (__be32 *) (tcph + 1);
lro_desc->tcp_rcv_tsecr = *(topt + 2);
}
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index afbf938836f..877da3ed52e 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -40,7 +40,7 @@
#include <net/route.h>
#include <net/xfrm.h>
-static inline int ip_forward_finish(struct sk_buff *skb)
+static int ip_forward_finish(struct sk_buff *skb)
{
struct ip_options * opt = &(IPCB(skb)->opt);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index fabb86db763..443b3f89192 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -39,6 +39,7 @@
#include <net/icmp.h>
#include <net/checksum.h>
#include <net/inetpeer.h>
+#include <net/inet_frag.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/inet.h>
@@ -49,21 +50,8 @@
* as well. Or notify me, at least. --ANK
*/
-/* Fragment cache limits. We will commit 256K at one time. Should we
- * cross that limit we will prune down to 192K. This should cope with
- * even the most extreme cases without allowing an attacker to measurably
- * harm machine performance.
- */
-int sysctl_ipfrag_high_thresh __read_mostly = 256*1024;
-int sysctl_ipfrag_low_thresh __read_mostly = 192*1024;
-
int sysctl_ipfrag_max_dist __read_mostly = 64;
-/* Important NOTE! Fragment queue must be destroyed before MSL expires.
- * RFC791 is wrong proposing to prolongate timer each fragment arrival by TTL.
- */
-int sysctl_ipfrag_time __read_mostly = IP_FRAG_TIME;
-
struct ipfrag_skb_cb
{
struct inet_skb_parm h;
@@ -74,153 +62,102 @@ struct ipfrag_skb_cb
/* Describe an entry in the "incomplete datagrams" queue. */
struct ipq {
- struct hlist_node list;
- struct list_head lru_list; /* lru list member */
+ struct inet_frag_queue q;
+
u32 user;
__be32 saddr;
__be32 daddr;
__be16 id;
u8 protocol;
- u8 last_in;
-#define COMPLETE 4
-#define FIRST_IN 2
-#define LAST_IN 1
-
- struct sk_buff *fragments; /* linked list of received fragments */
- int len; /* total length of original datagram */
- int meat;
- spinlock_t lock;
- atomic_t refcnt;
- struct timer_list timer; /* when will this queue expire? */
- ktime_t stamp;
int iif;
unsigned int rid;
struct inet_peer *peer;
};
-/* Hash table. */
+struct inet_frags_ctl ip4_frags_ctl __read_mostly = {
+ /*
+ * Fragment cache limits. We will commit 256K at one time. Should we
+ * cross that limit we will prune down to 192K. This should cope with
+ * even the most extreme cases without allowing an attacker to
+ * measurably harm machine performance.
+ */
+ .high_thresh = 256 * 1024,
+ .low_thresh = 192 * 1024,
-#define IPQ_HASHSZ 64
+ /*
+ * Important NOTE! Fragment queue must be destroyed before MSL expires.
+ * RFC791 is wrong proposing to prolongate timer each fragment arrival
+ * by TTL.
+ */
+ .timeout = IP_FRAG_TIME,
+ .secret_interval = 10 * 60 * HZ,
+};
-/* Per-bucket lock is easy to add now. */
-static struct hlist_head ipq_hash[IPQ_HASHSZ];
-static DEFINE_RWLOCK(ipfrag_lock);
-static u32 ipfrag_hash_rnd;
-static LIST_HEAD(ipq_lru_list);
-int ip_frag_nqueues = 0;
+static struct inet_frags ip4_frags;
-static __inline__ void __ipq_unlink(struct ipq *qp)
+int ip_frag_nqueues(void)
{
- hlist_del(&qp->list);
- list_del(&qp->lru_list);
- ip_frag_nqueues--;
+ return ip4_frags.nqueues;
}
-static __inline__ void ipq_unlink(struct ipq *ipq)
+int ip_frag_mem(void)
{
- write_lock(&ipfrag_lock);
- __ipq_unlink(ipq);
- write_unlock(&ipfrag_lock);
+ return atomic_read(&ip4_frags.mem);
}
+static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
+ struct net_device *dev);
+
static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
{
return jhash_3words((__force u32)id << 16 | prot,
(__force u32)saddr, (__force u32)daddr,
- ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
+ ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1);
}
-static struct timer_list ipfrag_secret_timer;
-int sysctl_ipfrag_secret_interval __read_mostly = 10 * 60 * HZ;
-
-static void ipfrag_secret_rebuild(unsigned long dummy)
+static unsigned int ip4_hashfn(struct inet_frag_queue *q)
{
- unsigned long now = jiffies;
- int i;
-
- write_lock(&ipfrag_lock);
- get_random_bytes(&ipfrag_hash_rnd, sizeof(u32));
- for (i = 0; i < IPQ_HASHSZ; i++) {
- struct ipq *q;
- struct hlist_node *p, *n;
-
- hlist_for_each_entry_safe(q, p, n, &ipq_hash[i], list) {
- unsigned int hval = ipqhashfn(q->id, q->saddr,
- q->daddr, q->protocol);
-
- if (hval != i) {
- hlist_del(&q->list);
+ struct ipq *ipq;
- /* Relink to new hash chain. */
- hlist_add_head(&q->list, &ipq_hash[hval]);
- }
- }
- }
- write_unlock(&ipfrag_lock);
-
- mod_timer(&ipfrag_secret_timer, now + sysctl_ipfrag_secret_interval);
+ ipq = container_of(q, struct ipq, q);
+ return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol);
}
-atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */
-
/* Memory Tracking Functions. */
static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)
{
if (work)
*work -= skb->truesize;
- atomic_sub(skb->truesize, &ip_frag_mem);
+ atomic_sub(skb->truesize, &ip4_frags.mem);
kfree_skb(skb);
}
-static __inline__ void frag_free_queue(struct ipq *qp, int *work)
+static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
{
- if (work)
- *work -= sizeof(struct ipq);
- atomic_sub(sizeof(struct ipq), &ip_frag_mem);
+ struct ipq *qp;
+
+ qp = container_of(q, struct ipq, q);
+ if (qp->peer)
+ inet_putpeer(qp->peer);
kfree(qp);
}
static __inline__ struct ipq *frag_alloc_queue(void)
{
- struct ipq *qp = kmalloc(sizeof(struct ipq), GFP_ATOMIC);
+ struct ipq *qp = kzalloc(sizeof(struct ipq), GFP_ATOMIC);
if (!qp)
return NULL;
- atomic_add(sizeof(struct ipq), &ip_frag_mem);
+ atomic_add(sizeof(struct ipq), &ip4_frags.mem);
return qp;
}
/* Destruction primitives. */
-/* Complete destruction of ipq. */
-static void ip_frag_destroy(struct ipq *qp, int *work)
-{
- struct sk_buff *fp;
-
- BUG_TRAP(qp->last_in&COMPLETE);
- BUG_TRAP(del_timer(&qp->timer) == 0);
-
- if (qp->peer)
- inet_putpeer(qp->peer);
-
- /* Release all fragment data. */
- fp = qp->fragments;
- while (fp) {
- struct sk_buff *xp = fp->next;
-
- frag_kfree_skb(fp, work);
- fp = xp;
- }
-
- /* Finally, release the queue descriptor itself. */
- frag_free_queue(qp, work);
-}
-
-static __inline__ void ipq_put(struct ipq *ipq, int *work)
+static __inline__ void ipq_put(struct ipq *ipq)
{
- if (atomic_dec_and_test(&ipq->refcnt))
- ip_frag_destroy(ipq, work);
+ inet_frag_put(&ipq->q, &ip4_frags);
}
/* Kill ipq entry. It is not destroyed immediately,
@@ -228,14 +165,7 @@ static __inline__ void ipq_put(struct ipq *ipq, int *work)
*/
static void ipq_kill(struct ipq *ipq)
{
- if (del_timer(&ipq->timer))
- atomic_dec(&ipq->refcnt);
-
- if (!(ipq->last_in & COMPLETE)) {
- ipq_unlink(ipq);
- atomic_dec(&ipq->refcnt);
- ipq->last_in |= COMPLETE;
- }
+ inet_frag_kill(&ipq->q, &ip4_frags);
}
/* Memory limiting on fragments. Evictor trashes the oldest
@@ -243,33 +173,11 @@ static void ipq_kill(struct ipq *ipq)
*/
static void ip_evictor(void)
{
- struct ipq *qp;
- struct list_head *tmp;
- int work;
-
- work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
- if (work <= 0)
- return;
-
- while (work > 0) {
- read_lock(&ipfrag_lock);
- if (list_empty(&ipq_lru_list)) {
- read_unlock(&ipfrag_lock);
- return;
- }
- tmp = ipq_lru_list.next;
- qp = list_entry(tmp, struct ipq, lru_list);
- atomic_inc(&qp->refcnt);
- read_unlock(&ipfrag_lock);
+ int evicted;
- spin_lock(&qp->lock);
- if (!(qp->last_in&COMPLETE))
- ipq_kill(qp);
- spin_unlock(&qp->lock);
-
- ipq_put(qp, &work);
- IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
- }
+ evicted = inet_frag_evictor(&ip4_frags);
+ if (evicted)
+ IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted);
}
/*
@@ -279,9 +187,9 @@ static void ip_expire(unsigned long arg)
{
struct ipq *qp = (struct ipq *) arg;
- spin_lock(&qp->lock);
+ spin_lock(&qp->q.lock);
- if (qp->last_in & COMPLETE)
+ if (qp->q.last_in & COMPLETE)
goto out;
ipq_kill(qp);
@@ -289,8 +197,8 @@ static void ip_expire(unsigned long arg)
IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
- if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
- struct sk_buff *head = qp->fragments;
+ if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) {
+ struct sk_buff *head = qp->q.fragments;
/* Send an ICMP "Fragment Reassembly Timeout" message. */
if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) {
icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
@@ -298,8 +206,8 @@ static void ip_expire(unsigned long arg)
}
}
out:
- spin_unlock(&qp->lock);
- ipq_put(qp, NULL);
+ spin_unlock(&qp->q.lock);
+ ipq_put(qp);
}
/* Creation primitives. */
@@ -312,7 +220,7 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
#endif
unsigned int hash;
- write_lock(&ipfrag_lock);
+ write_lock(&ip4_frags.lock);
hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr,
qp_in->protocol);
#ifdef CONFIG_SMP
@@ -320,31 +228,31 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
* such entry could be created on other cpu, while we
* promoted read lock to write lock.
*/
- hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+ hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
if (qp->id == qp_in->id &&
qp->saddr == qp_in->saddr &&
qp->daddr == qp_in->daddr &&
qp->protocol == qp_in->protocol &&
qp->user == qp_in->user) {
- atomic_inc(&qp->refcnt);
- write_unlock(&ipfrag_lock);
- qp_in->last_in |= COMPLETE;
- ipq_put(qp_in, NULL);
+ atomic_inc(&qp->q.refcnt);
+ write_unlock(&ip4_frags.lock);
+ qp_in->q.last_in |= COMPLETE;
+ ipq_put(qp_in);
return qp;
}
}
#endif
qp = qp_in;
- if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))
- atomic_inc(&qp->refcnt);
+ if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout))
+ atomic_inc(&qp->q.refcnt);
- atomic_inc(&qp->refcnt);
- hlist_add_head(&qp->list, &ipq_hash[hash]);
- INIT_LIST_HEAD(&qp->lru_list);
- list_add_tail(&qp->lru_list, &ipq_lru_list);
- ip_frag_nqueues++;
- write_unlock(&ipfrag_lock);
+ atomic_inc(&qp->q.refcnt);
+ hlist_add_head(&qp->q.list, &ip4_frags.hash[hash]);
+ INIT_LIST_HEAD(&qp->q.lru_list);
+ list_add_tail(&qp->q.lru_list, &ip4_frags.lru_list);
+ ip4_frags.nqueues++;
+ write_unlock(&ip4_frags.lock);
return qp;
}
@@ -357,23 +265,18 @@ static struct ipq *ip_frag_create(struct iphdr *iph, u32 user)
goto out_nomem;
qp->protocol = iph->protocol;
- qp->last_in = 0;
qp->id = iph->id;
qp->saddr = iph->saddr;
qp->daddr = iph->daddr;
qp->user = user;
- qp->len = 0;
- qp->meat = 0;
- qp->fragments = NULL;
- qp->iif = 0;
qp->peer = sysctl_ipfrag_max_dist ? inet_getpeer(iph->saddr, 1) : NULL;
/* Initialize a timer for this entry. */
- init_timer(&qp->timer);
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- spin_lock_init(&qp->lock);
- atomic_set(&qp->refcnt, 1);
+ init_timer(&qp->q.timer);
+ qp->q.timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->q.timer.function = ip_expire; /* expire function */
+ spin_lock_init(&qp->q.lock);
+ atomic_set(&qp->q.refcnt, 1);
return ip_frag_intern(qp);
@@ -395,20 +298,20 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
struct ipq *qp;
struct hlist_node *n;
- read_lock(&ipfrag_lock);
+ read_lock(&ip4_frags.lock);
hash = ipqhashfn(id, saddr, daddr, protocol);
- hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+ hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
if (qp->id == id &&
qp->saddr == saddr &&
qp->daddr == daddr &&
qp->protocol == protocol &&
qp->user == user) {
- atomic_inc(&qp->refcnt);
- read_unlock(&ipfrag_lock);
+ atomic_inc(&qp->q.refcnt);
+ read_unlock(&ip4_frags.lock);
return qp;
}
}
- read_unlock(&ipfrag_lock);
+ read_unlock(&ip4_frags.lock);
return ip_frag_create(iph, user);
}
@@ -429,7 +332,7 @@ static inline int ip_frag_too_far(struct ipq *qp)
end = atomic_inc_return(&peer->rid);
qp->rid = end;
- rc = qp->fragments && (end - start) > max;
+ rc = qp->q.fragments && (end - start) > max;
if (rc) {
IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
@@ -442,39 +345,42 @@ static int ip_frag_reinit(struct ipq *qp)
{
struct sk_buff *fp;
- if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time)) {
- atomic_inc(&qp->refcnt);
+ if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout)) {
+ atomic_inc(&qp->q.refcnt);
return -ETIMEDOUT;
}
- fp = qp->fragments;
+ fp = qp->q.fragments;
do {
struct sk_buff *xp = fp->next;
frag_kfree_skb(fp, NULL);
fp = xp;
} while (fp);
- qp->last_in = 0;
- qp->len = 0;
- qp->meat = 0;
- qp->fragments = NULL;
+ qp->q.last_in = 0;
+ qp->q.len = 0;
+ qp->q.meat = 0;
+ qp->q.fragments = NULL;
qp->iif = 0;
return 0;
}
/* Add new segment to existing queue. */
-static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
+static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
{
struct sk_buff *prev, *next;
+ struct net_device *dev;
int flags, offset;
int ihl, end;
+ int err = -ENOENT;
- if (qp->last_in & COMPLETE)
+ if (qp->q.last_in & COMPLETE)
goto err;
if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
- unlikely(ip_frag_too_far(qp)) && unlikely(ip_frag_reinit(qp))) {
+ unlikely(ip_frag_too_far(qp)) &&
+ unlikely(err = ip_frag_reinit(qp))) {
ipq_kill(qp);
goto err;
}
@@ -487,36 +393,40 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
/* Determine the position of this fragment. */
end = offset + skb->len - ihl;
+ err = -EINVAL;
/* Is this the final fragment? */
if ((flags & IP_MF) == 0) {
/* If we already have some bits beyond end
* or have different end, the segment is corrrupted.
*/
- if (end < qp->len ||
- ((qp->last_in & LAST_IN) && end != qp->len))
+ if (end < qp->q.len ||
+ ((qp->q.last_in & LAST_IN) && end != qp->q.len))
goto err;
- qp->last_in |= LAST_IN;
- qp->len = end;
+ qp->q.last_in |= LAST_IN;
+ qp->q.len = end;
} else {
if (end&7) {
end &= ~7;
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
skb->ip_summed = CHECKSUM_NONE;
}
- if (end > qp->len) {
+ if (end > qp->q.len) {
/* Some bits beyond end -> corruption. */
- if (qp->last_in & LAST_IN)
+ if (qp->q.last_in & LAST_IN)
goto err;
- qp->len = end;
+ qp->q.len = end;
}
}
if (end == offset)
goto err;
+ err = -ENOMEM;
if (pskb_pull(skb, ihl) == NULL)
goto err;
- if (pskb_trim_rcsum(skb, end-offset))
+
+ err = pskb_trim_rcsum(skb, end - offset);
+ if (err)
goto err;
/* Find out which fragments are in front and at the back of us
@@ -524,7 +434,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
* this fragment, right?
*/
prev = NULL;
- for (next = qp->fragments; next != NULL; next = next->next) {
+ for (next = qp->q.fragments; next != NULL; next = next->next) {
if (FRAG_CB(next)->offset >= offset)
break; /* bingo! */
prev = next;
@@ -539,8 +449,10 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
if (i > 0) {
offset += i;
+ err = -EINVAL;
if (end <= offset)
goto err;
+ err = -ENOMEM;
if (!pskb_pull(skb, i))
goto err;
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
@@ -548,6 +460,8 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
}
}
+ err = -ENOMEM;
+
while (next && FRAG_CB(next)->offset < end) {
int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */
@@ -558,7 +472,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
if (!pskb_pull(next, i))
goto err;
FRAG_CB(next)->offset += i;
- qp->meat -= i;
+ qp->q.meat -= i;
if (next->ip_summed != CHECKSUM_UNNECESSARY)
next->ip_summed = CHECKSUM_NONE;
break;
@@ -573,9 +487,9 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
if (prev)
prev->next = next;
else
- qp->fragments = next;
+ qp->q.fragments = next;
- qp->meat -= free_it->len;
+ qp->q.meat -= free_it->len;
frag_kfree_skb(free_it, NULL);
}
}
@@ -587,50 +501,77 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
if (prev)
prev->next = skb;
else
- qp->fragments = skb;
-
- if (skb->dev)
- qp->iif = skb->dev->ifindex;
- skb->dev = NULL;
- qp->stamp = skb->tstamp;
- qp->meat += skb->len;
- atomic_add(skb->truesize, &ip_frag_mem);
+ qp->q.fragments = skb;
+
+ dev = skb->dev;
+ if (dev) {
+ qp->iif = dev->ifindex;
+ skb->dev = NULL;
+ }
+ qp->q.stamp = skb->tstamp;
+ qp->q.meat += skb->len;
+ atomic_add(skb->truesize, &ip4_frags.mem);
if (offset == 0)
- qp->last_in |= FIRST_IN;
+ qp->q.last_in |= FIRST_IN;
- write_lock(&ipfrag_lock);
- list_move_tail(&qp->lru_list, &ipq_lru_list);
- write_unlock(&ipfrag_lock);
+ if (qp->q.last_in == (FIRST_IN | LAST_IN) && qp->q.meat == qp->q.len)
+ return ip_frag_reasm(qp, prev, dev);
- return;
+ write_lock(&ip4_frags.lock);
+ list_move_tail(&qp->q.lru_list, &ip4_frags.lru_list);
+ write_unlock(&ip4_frags.lock);
+ return -EINPROGRESS;
err:
kfree_skb(skb);
+ return err;
}
/* Build a new IP datagram from all its fragments. */
-static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
+static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
+ struct net_device *dev)
{
struct iphdr *iph;
- struct sk_buff *fp, *head = qp->fragments;
+ struct sk_buff *fp, *head = qp->q.fragments;
int len;
int ihlen;
+ int err;
ipq_kill(qp);
+ /* Make the one we just received the head. */
+ if (prev) {
+ head = prev->next;
+ fp = skb_clone(head, GFP_ATOMIC);
+
+ if (!fp)
+ goto out_nomem;
+
+ fp->next = head->next;
+ prev->next = fp;
+
+ skb_morph(head, qp->q.fragments);
+ head->next = qp->q.fragments->next;
+
+ kfree_skb(qp->q.fragments);
+ qp->q.fragments = head;
+ }
+
BUG_TRAP(head != NULL);
BUG_TRAP(FRAG_CB(head)->offset == 0);
/* Allocate a new buffer for the datagram. */
ihlen = ip_hdrlen(head);
- len = ihlen + qp->len;
+ len = ihlen + qp->q.len;
+ err = -E2BIG;
if (len > 65535)
goto out_oversize;
/* Head of list must not be cloned. */
+ err = -ENOMEM;
if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
goto out_nomem;
@@ -654,12 +595,12 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
- atomic_add(clone->truesize, &ip_frag_mem);
+ atomic_add(clone->truesize, &ip4_frags.mem);
}
skb_shinfo(head)->frag_list = head->next;
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &ip_frag_mem);
+ atomic_sub(head->truesize, &ip4_frags.mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -669,19 +610,19 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &ip_frag_mem);
+ atomic_sub(fp->truesize, &ip4_frags.mem);
}
head->next = NULL;
head->dev = dev;
- head->tstamp = qp->stamp;
+ head->tstamp = qp->q.stamp;
iph = ip_hdr(head);
iph->frag_off = 0;
iph->tot_len = htons(len);
IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
- qp->fragments = NULL;
- return head;
+ qp->q.fragments = NULL;
+ return 0;
out_nomem:
LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
@@ -694,54 +635,46 @@ out_oversize:
NIPQUAD(qp->saddr));
out_fail:
IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
- return NULL;
+ return err;
}
/* Process an incoming IP datagram fragment. */
-struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
+int ip_defrag(struct sk_buff *skb, u32 user)
{
struct ipq *qp;
- struct net_device *dev;
IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
/* Start by cleaning up the memory. */
- if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
+ if (atomic_read(&ip4_frags.mem) > ip4_frags_ctl.high_thresh)
ip_evictor();
- dev = skb->dev;
-
/* Lookup (or create) queue header */
if ((qp = ip_find(ip_hdr(skb), user)) != NULL) {
- struct sk_buff *ret = NULL;
-
- spin_lock(&qp->lock);
+ int ret;
- ip_frag_queue(qp, skb);
+ spin_lock(&qp->q.lock);
- if (qp->last_in == (FIRST_IN|LAST_IN) &&
- qp->meat == qp->len)
- ret = ip_frag_reasm(qp, dev);
+ ret = ip_frag_queue(qp, skb);
- spin_unlock(&qp->lock);
- ipq_put(qp, NULL);
+ spin_unlock(&qp->q.lock);
+ ipq_put(qp);
return ret;
}
IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
- return NULL;
+ return -ENOMEM;
}
void __init ipfrag_init(void)
{
- ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
- (jiffies ^ (jiffies >> 6)));
-
- init_timer(&ipfrag_secret_timer);
- ipfrag_secret_timer.function = ipfrag_secret_rebuild;
- ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
- add_timer(&ipfrag_secret_timer);
+ ip4_frags.ctl = &ip4_frags_ctl;
+ ip4_frags.hashfn = ip4_hashfn;
+ ip4_frags.destructor = ip4_frag_free;
+ ip4_frags.skb_free = NULL;
+ ip4_frags.qsize = sizeof(struct ipq);
+ inet_frags_init(&ip4_frags);
}
EXPORT_SYMBOL(ip_defrag);
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 41d8964591e..168c871fcd7 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -172,8 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
(!sk->sk_bound_dev_if ||
sk->sk_bound_dev_if == skb->dev->ifindex)) {
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN);
- if (skb == NULL) {
+ if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
read_unlock(&ip_ra_lock);
return 1;
}
@@ -196,7 +195,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
return 0;
}
-static inline int ip_local_deliver_finish(struct sk_buff *skb)
+static int ip_local_deliver_finish(struct sk_buff *skb)
{
__skb_pull(skb, ip_hdrlen(skb));
@@ -265,8 +264,7 @@ int ip_local_deliver(struct sk_buff *skb)
*/
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);
- if (!skb)
+ if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER))
return 0;
}
@@ -326,7 +324,7 @@ drop:
return -1;
}
-static inline int ip_rcv_finish(struct sk_buff *skb)
+static int ip_rcv_finish(struct sk_buff *skb)
{
const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 699f06781fd..f508835ba71 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -202,7 +202,7 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb)
skb->dst->dev->mtu : dst_mtu(skb->dst);
}
-static inline int ip_finish_output(struct sk_buff *skb)
+static int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
/* Policy lookup after SNAT yielded a new policy */
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 341474eefa5..664cb8e97c1 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -25,6 +25,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/netfilter.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/tcp.h>
@@ -328,18 +329,18 @@ static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
spin_unlock(&cp->lock);
}
-static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb,
+static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
struct ip_vs_app *app)
{
int diff;
- const unsigned int tcp_offset = ip_hdrlen(*pskb);
+ const unsigned int tcp_offset = ip_hdrlen(skb);
struct tcphdr *th;
__u32 seq;
- if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th)))
+ if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
return 0;
- th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset);
+ th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
/*
* Remember seq number in case this pkt gets resized
@@ -360,7 +361,7 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb,
if (app->pkt_out == NULL)
return 1;
- if (!app->pkt_out(app, cp, pskb, &diff))
+ if (!app->pkt_out(app, cp, skb, &diff))
return 0;
/*
@@ -378,7 +379,7 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb,
* called by ipvs packet handler, assumes previously checked cp!=NULL
* returns false if it can't handle packet (oom)
*/
-int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb)
+int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb)
{
struct ip_vs_app *app;
@@ -391,7 +392,7 @@ int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb)
/* TCP is complicated */
if (cp->protocol == IPPROTO_TCP)
- return app_tcp_pkt_out(cp, pskb, app);
+ return app_tcp_pkt_out(cp, skb, app);
/*
* Call private output hook function
@@ -399,22 +400,22 @@ int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb)
if (app->pkt_out == NULL)
return 1;
- return app->pkt_out(app, cp, pskb, NULL);
+ return app->pkt_out(app, cp, skb, NULL);
}
-static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb,
+static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
struct ip_vs_app *app)
{
int diff;
- const unsigned int tcp_offset = ip_hdrlen(*pskb);
+ const unsigned int tcp_offset = ip_hdrlen(skb);
struct tcphdr *th;
__u32 seq;
- if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th)))
+ if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
return 0;
- th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset);
+ th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
/*
* Remember seq number in case this pkt gets resized
@@ -435,7 +436,7 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb,
if (app->pkt_in == NULL)
return 1;
- if (!app->pkt_in(app, cp, pskb, &diff))
+ if (!app->pkt_in(app, cp, skb, &diff))
return 0;
/*
@@ -453,7 +454,7 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb,
* called by ipvs packet handler, assumes previously checked cp!=NULL.
* returns false if can't handle packet (oom).
*/
-int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb)
+int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb)
{
struct ip_vs_app *app;
@@ -466,7 +467,7 @@ int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb)
/* TCP is complicated */
if (cp->protocol == IPPROTO_TCP)
- return app_tcp_pkt_in(cp, pskb, app);
+ return app_tcp_pkt_in(cp, skb, app);
/*
* Call private input hook function
@@ -474,7 +475,7 @@ int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb)
if (app->pkt_in == NULL)
return 1;
- return app->pkt_in(app, cp, pskb, NULL);
+ return app->pkt_in(app, cp, skb, NULL);
}
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index fbca2a2ff29..c6ed7654e83 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -58,7 +58,6 @@ EXPORT_SYMBOL(ip_vs_conn_put);
#ifdef CONFIG_IP_VS_DEBUG
EXPORT_SYMBOL(ip_vs_get_debug_level);
#endif
-EXPORT_SYMBOL(ip_vs_make_skb_writable);
/* ID used in ICMP lookups */
@@ -163,42 +162,6 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction,
}
-int ip_vs_make_skb_writable(struct sk_buff **pskb, int writable_len)
-{
- struct sk_buff *skb = *pskb;
-
- /* skb is already used, better copy skb and its payload */
- if (unlikely(skb_shared(skb) || skb->sk))
- goto copy_skb;
-
- /* skb data is already used, copy it */
- if (unlikely(skb_cloned(skb)))
- goto copy_data;
-
- return pskb_may_pull(skb, writable_len);
-
- copy_data:
- if (unlikely(writable_len > skb->len))
- return 0;
- return !pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-
- copy_skb:
- if (unlikely(writable_len > skb->len))
- return 0;
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb)
- return 0;
- BUG_ON(skb_is_nonlinear(skb));
-
- /* Rest of kernel will get very unhappy if we pass it a
- suddenly-orphaned skbuff */
- if ((*pskb)->sk)
- skb_set_owner_w(skb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = skb;
- return 1;
-}
-
/*
* IPVS persistent scheduling function
* It creates a connection entry according to its template if exists,
@@ -525,12 +488,12 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
* for VS/NAT.
*/
static unsigned int ip_vs_post_routing(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- if (!((*pskb)->ipvs_property))
+ if (!skb->ipvs_property)
return NF_ACCEPT;
/* The packet was sent from IPVS, exit this chain */
return NF_STOP;
@@ -541,13 +504,14 @@ __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
}
-static inline struct sk_buff *
-ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
+static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
{
- skb = ip_defrag(skb, user);
- if (skb)
+ int err = ip_defrag(skb, user);
+
+ if (!err)
ip_send_check(ip_hdr(skb));
- return skb;
+
+ return err;
}
/*
@@ -605,9 +569,8 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
* Currently handles error types - unreachable, quench, ttl exceeded.
* (Only used in VS/NAT)
*/
-static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
+static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
{
- struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
@@ -619,10 +582,8 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
/* reassemble IP fragments */
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
- if (!skb)
+ if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
return NF_STOLEN;
- *pskb = skb;
}
iph = ip_hdr(skb);
@@ -690,9 +651,8 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
offset += 2 * sizeof(__u16);
- if (!ip_vs_make_skb_writable(pskb, offset))
+ if (!skb_make_writable(skb, offset))
goto out;
- skb = *pskb;
ip_vs_nat_icmp(skb, pp, cp, 1);
@@ -724,11 +684,10 @@ static inline int is_tcp_reset(const struct sk_buff *skb)
* rewrite addresses of the packet and send it on its way...
*/
static unsigned int
-ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
+ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
@@ -741,11 +700,10 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
iph = ip_hdr(skb);
if (unlikely(iph->protocol == IPPROTO_ICMP)) {
- int related, verdict = ip_vs_out_icmp(pskb, &related);
+ int related, verdict = ip_vs_out_icmp(skb, &related);
if (related)
return verdict;
- skb = *pskb;
iph = ip_hdr(skb);
}
@@ -756,11 +714,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
/* reassemble IP fragments */
if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) &&
!pp->dont_defrag)) {
- skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
- if (!skb)
+ if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
return NF_STOLEN;
iph = ip_hdr(skb);
- *pskb = skb;
}
ihl = iph->ihl << 2;
@@ -802,13 +758,12 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
- if (!ip_vs_make_skb_writable(pskb, ihl))
+ if (!skb_make_writable(skb, ihl))
goto drop;
/* mangle the packet */
- if (pp->snat_handler && !pp->snat_handler(pskb, pp, cp))
+ if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
goto drop;
- skb = *pskb;
ip_hdr(skb)->saddr = cp->vaddr;
ip_send_check(ip_hdr(skb));
@@ -818,9 +773,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
* if it came from this machine itself. So re-compute
* the routing information.
*/
- if (ip_route_me_harder(pskb, RTN_LOCAL) != 0)
+ if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
goto drop;
- skb = *pskb;
IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
@@ -835,7 +789,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
drop:
ip_vs_conn_put(cp);
- kfree_skb(*pskb);
+ kfree_skb(skb);
return NF_STOLEN;
}
@@ -847,9 +801,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
* Currently handles error types - unreachable, quench, ttl exceeded.
*/
static int
-ip_vs_in_icmp(struct sk_buff **pskb, int *related, unsigned int hooknum)
+ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
{
- struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
@@ -861,12 +814,9 @@ ip_vs_in_icmp(struct sk_buff **pskb, int *related, unsigned int hooknum)
/* reassemble IP fragments */
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- skb = ip_vs_gather_frags(skb,
- hooknum == NF_IP_LOCAL_IN ?
- IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD);
- if (!skb)
+ if (ip_vs_gather_frags(skb, hooknum == NF_IP_LOCAL_IN ?
+ IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD))
return NF_STOLEN;
- *pskb = skb;
}
iph = ip_hdr(skb);
@@ -945,11 +895,10 @@ ip_vs_in_icmp(struct sk_buff **pskb, int *related, unsigned int hooknum)
* and send it on its way...
*/
static unsigned int
-ip_vs_in(unsigned int hooknum, struct sk_buff **pskb,
+ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
@@ -971,11 +920,10 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb,
iph = ip_hdr(skb);
if (unlikely(iph->protocol == IPPROTO_ICMP)) {
- int related, verdict = ip_vs_in_icmp(pskb, &related, hooknum);
+ int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
if (related)
return verdict;
- skb = *pskb;
iph = ip_hdr(skb);
}
@@ -1056,16 +1004,16 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb,
* and send them to ip_vs_in_icmp.
*/
static unsigned int
-ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff **pskb,
+ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
int r;
- if (ip_hdr(*pskb)->protocol != IPPROTO_ICMP)
+ if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
return NF_ACCEPT;
- return ip_vs_in_icmp(pskb, &r, hooknum);
+ return ip_vs_in_icmp(skb, &r, hooknum);
}
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 344ddbbdc75..59aa166b767 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -30,6 +30,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/netfilter.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <asm/unaligned.h>
@@ -135,7 +136,7 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
* xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
*/
static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
- struct sk_buff **pskb, int *diff)
+ struct sk_buff *skb, int *diff)
{
struct iphdr *iph;
struct tcphdr *th;
@@ -155,14 +156,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
return 1;
/* Linear packets are much easier to deal with. */
- if (!ip_vs_make_skb_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return 0;
if (cp->app_data == &ip_vs_ftp_pasv) {
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
data = (char *)th + (th->doff << 2);
- data_limit = skb_tail_pointer(*pskb);
+ data_limit = skb_tail_pointer(skb);
if (ip_vs_ftp_get_addrport(data, data_limit,
SERVER_STRING,
@@ -213,7 +214,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
memcpy(start, buf, buf_len);
ret = 1;
} else {
- ret = !ip_vs_skb_replace(*pskb, GFP_ATOMIC, start,
+ ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start,
end-start, buf, buf_len);
}
@@ -238,7 +239,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
* the client.
*/
static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
- struct sk_buff **pskb, int *diff)
+ struct sk_buff *skb, int *diff)
{
struct iphdr *iph;
struct tcphdr *th;
@@ -256,20 +257,20 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
return 1;
/* Linear packets are much easier to deal with. */
- if (!ip_vs_make_skb_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return 0;
/*
* Detecting whether it is passive
*/
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
/* Since there may be OPTIONS in the TCP packet and the HLEN is
the length of the header in 32-bit multiples, it is accurate
to calculate data address by th+HLEN*4 */
data = data_start = (char *)th + (th->doff << 2);
- data_limit = skb_tail_pointer(*pskb);
+ data_limit = skb_tail_pointer(skb);
while (data <= data_limit - 6) {
if (strnicmp(data, "PASV\r\n", 6) == 0) {
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index e65577a7700..12dc0d640b6 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -20,6 +20,7 @@
#include <linux/tcp.h> /* for tcphdr */
#include <net/ip.h>
#include <net/tcp.h> /* for csum_tcpudp_magic */
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <net/ip_vs.h>
@@ -122,27 +123,27 @@ tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
static int
-tcp_snat_handler(struct sk_buff **pskb,
+tcp_snat_handler(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
struct tcphdr *tcph;
- const unsigned int tcphoff = ip_hdrlen(*pskb);
+ const unsigned int tcphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */
- if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph)))
+ if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
return 0;
if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */
- if (pp->csum_check && !pp->csum_check(*pskb, pp))
+ if (pp->csum_check && !pp->csum_check(skb, pp))
return 0;
/* Call application helper if needed */
- if (!ip_vs_app_pkt_out(cp, pskb))
+ if (!ip_vs_app_pkt_out(cp, skb))
return 0;
}
- tcph = (void *)ip_hdr(*pskb) + tcphoff;
+ tcph = (void *)ip_hdr(skb) + tcphoff;
tcph->source = cp->vport;
/* Adjust TCP checksums */
@@ -150,17 +151,15 @@ tcp_snat_handler(struct sk_buff **pskb,
/* Only port and addr are changed, do fast csum update */
tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
cp->dport, cp->vport);
- if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
- (*pskb)->ip_summed = CHECKSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
} else {
/* full checksum calculation */
tcph->check = 0;
- (*pskb)->csum = skb_checksum(*pskb, tcphoff,
- (*pskb)->len - tcphoff, 0);
+ skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
- (*pskb)->len - tcphoff,
- cp->protocol,
- (*pskb)->csum);
+ skb->len - tcphoff,
+ cp->protocol, skb->csum);
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, tcph->check,
(char*)&(tcph->check) - (char*)tcph);
@@ -170,30 +169,30 @@ tcp_snat_handler(struct sk_buff **pskb,
static int
-tcp_dnat_handler(struct sk_buff **pskb,
+tcp_dnat_handler(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
struct tcphdr *tcph;
- const unsigned int tcphoff = ip_hdrlen(*pskb);
+ const unsigned int tcphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */
- if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph)))
+ if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
return 0;
if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */
- if (pp->csum_check && !pp->csum_check(*pskb, pp))
+ if (pp->csum_check && !pp->csum_check(skb, pp))
return 0;
/*
* Attempt ip_vs_app call.
* It will fix ip_vs_conn and iph ack_seq stuff
*/
- if (!ip_vs_app_pkt_in(cp, pskb))
+ if (!ip_vs_app_pkt_in(cp, skb))
return 0;
}
- tcph = (void *)ip_hdr(*pskb) + tcphoff;
+ tcph = (void *)ip_hdr(skb) + tcphoff;
tcph->dest = cp->dport;
/*
@@ -203,18 +202,16 @@ tcp_dnat_handler(struct sk_buff **pskb,
/* Only port and addr are changed, do fast csum update */
tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
cp->vport, cp->dport);
- if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
- (*pskb)->ip_summed = CHECKSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
} else {
/* full checksum calculation */
tcph->check = 0;
- (*pskb)->csum = skb_checksum(*pskb, tcphoff,
- (*pskb)->len - tcphoff, 0);
+ skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
- (*pskb)->len - tcphoff,
- cp->protocol,
- (*pskb)->csum);
- (*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->len - tcphoff,
+ cp->protocol, skb->csum);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
return 1;
}
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 8ee5fe6a101..1fa7b330b9a 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -18,6 +18,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/kernel.h>
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/udp.h>
@@ -129,29 +130,29 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
}
static int
-udp_snat_handler(struct sk_buff **pskb,
+udp_snat_handler(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
struct udphdr *udph;
- const unsigned int udphoff = ip_hdrlen(*pskb);
+ const unsigned int udphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */
- if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph)))
+ if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
return 0;
if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */
- if (pp->csum_check && !pp->csum_check(*pskb, pp))
+ if (pp->csum_check && !pp->csum_check(skb, pp))
return 0;
/*
* Call application helper if needed
*/
- if (!ip_vs_app_pkt_out(cp, pskb))
+ if (!ip_vs_app_pkt_out(cp, skb))
return 0;
}
- udph = (void *)ip_hdr(*pskb) + udphoff;
+ udph = (void *)ip_hdr(skb) + udphoff;
udph->source = cp->vport;
/*
@@ -161,17 +162,15 @@ udp_snat_handler(struct sk_buff **pskb,
/* Only port and addr are changed, do fast csum update */
udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
cp->dport, cp->vport);
- if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
- (*pskb)->ip_summed = CHECKSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
} else {
/* full checksum calculation */
udph->check = 0;
- (*pskb)->csum = skb_checksum(*pskb, udphoff,
- (*pskb)->len - udphoff, 0);
+ skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
- (*pskb)->len - udphoff,
- cp->protocol,
- (*pskb)->csum);
+ skb->len - udphoff,
+ cp->protocol, skb->csum);
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
@@ -183,30 +182,30 @@ udp_snat_handler(struct sk_buff **pskb,
static int
-udp_dnat_handler(struct sk_buff **pskb,
+udp_dnat_handler(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
struct udphdr *udph;
- unsigned int udphoff = ip_hdrlen(*pskb);
+ unsigned int udphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */
- if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph)))
+ if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
return 0;
if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */
- if (pp->csum_check && !pp->csum_check(*pskb, pp))
+ if (pp->csum_check && !pp->csum_check(skb, pp))
return 0;
/*
* Attempt ip_vs_app call.
* It will fix ip_vs_conn
*/
- if (!ip_vs_app_pkt_in(cp, pskb))
+ if (!ip_vs_app_pkt_in(cp, skb))
return 0;
}
- udph = (void *)ip_hdr(*pskb) + udphoff;
+ udph = (void *)ip_hdr(skb) + udphoff;
udph->dest = cp->dport;
/*
@@ -216,20 +215,18 @@ udp_dnat_handler(struct sk_buff **pskb,
/* Only port and addr are changed, do fast csum update */
udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
cp->vport, cp->dport);
- if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
- (*pskb)->ip_summed = CHECKSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
} else {
/* full checksum calculation */
udph->check = 0;
- (*pskb)->csum = skb_checksum(*pskb, udphoff,
- (*pskb)->len - udphoff, 0);
+ skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
- (*pskb)->len - udphoff,
- cp->protocol,
- (*pskb)->csum);
+ skb->len - udphoff,
+ cp->protocol, skb->csum);
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
- (*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
return 1;
}
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 666e080a74a..d0a92dec105 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -253,7 +253,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
}
/* copy-on-write the packet before mangling it */
- if (!ip_vs_make_skb_writable(&skb, sizeof(struct iphdr)))
+ if (!skb_make_writable(skb, sizeof(struct iphdr)))
goto tx_error_put;
if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
@@ -264,7 +264,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dst = &rt->u.dst;
/* mangle the packet */
- if (pp->dnat_handler && !pp->dnat_handler(&skb, pp, cp))
+ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
goto tx_error;
ip_hdr(skb)->daddr = cp->daddr;
ip_send_check(ip_hdr(skb));
@@ -529,7 +529,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
}
/* copy-on-write the packet before mangling it */
- if (!ip_vs_make_skb_writable(&skb, offset))
+ if (!skb_make_writable(skb, offset))
goto tx_error_put;
if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index b44192924f9..5539debf497 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -3,14 +3,15 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
+#include <linux/skbuff.h>
#include <net/route.h>
#include <net/xfrm.h>
#include <net/ip.h>
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
-int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
+int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
{
- const struct iphdr *iph = ip_hdr(*pskb);
+ const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
struct flowi fl = {};
struct dst_entry *odst;
@@ -29,14 +30,14 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
if (type == RTN_LOCAL)
fl.nl_u.ip4_u.saddr = iph->saddr;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
- fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
- fl.mark = (*pskb)->mark;
+ fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
+ fl.mark = skb->mark;
if (ip_route_output_key(&rt, &fl) != 0)
return -1;
/* Drop old route. */
- dst_release((*pskb)->dst);
- (*pskb)->dst = &rt->u.dst;
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
} else {
/* non-local src, find valid iif to satisfy
* rp-filter when calling ip_route_input. */
@@ -44,8 +45,8 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
if (ip_route_output_key(&rt, &fl) != 0)
return -1;
- odst = (*pskb)->dst;
- if (ip_route_input(*pskb, iph->daddr, iph->saddr,
+ odst = skb->dst;
+ if (ip_route_input(skb, iph->daddr, iph->saddr,
RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
dst_release(&rt->u.dst);
return -1;
@@ -54,70 +55,54 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
dst_release(odst);
}
- if ((*pskb)->dst->error)
+ if (skb->dst->error)
return -1;
#ifdef CONFIG_XFRM
- if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) &&
- xfrm_decode_session(*pskb, &fl, AF_INET) == 0)
- if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0))
+ if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
+ xfrm_decode_session(skb, &fl, AF_INET) == 0)
+ if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
return -1;
#endif
/* Change in oif may mean change in hh_len. */
- hh_len = (*pskb)->dst->dev->hard_header_len;
- if (skb_headroom(*pskb) < hh_len) {
- struct sk_buff *nskb;
-
- nskb = skb_realloc_headroom(*pskb, hh_len);
- if (!nskb)
- return -1;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
+ hh_len = skb->dst->dev->hard_header_len;
+ if (skb_headroom(skb) < hh_len &&
+ pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
+ return -1;
return 0;
}
EXPORT_SYMBOL(ip_route_me_harder);
#ifdef CONFIG_XFRM
-int ip_xfrm_me_harder(struct sk_buff **pskb)
+int ip_xfrm_me_harder(struct sk_buff *skb)
{
struct flowi fl;
unsigned int hh_len;
struct dst_entry *dst;
- if (IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED)
+ if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
return 0;
- if (xfrm_decode_session(*pskb, &fl, AF_INET) < 0)
+ if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
return -1;
- dst = (*pskb)->dst;
+ dst = skb->dst;
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
dst_hold(dst);
- if (xfrm_lookup(&dst, &fl, (*pskb)->sk, 0) < 0)
+ if (xfrm_lookup(&dst, &fl, skb->sk, 0) < 0)
return -1;
- dst_release((*pskb)->dst);
- (*pskb)->dst = dst;
+ dst_release(skb->dst);
+ skb->dst = dst;
/* Change in oif may mean change in hh_len. */
- hh_len = (*pskb)->dst->dev->hard_header_len;
- if (skb_headroom(*pskb) < hh_len) {
- struct sk_buff *nskb;
-
- nskb = skb_realloc_headroom(*pskb, hh_len);
- if (!nskb)
- return -1;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
+ hh_len = skb->dst->dev->hard_header_len;
+ if (skb_headroom(skb) < hh_len &&
+ pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
+ return -1;
return 0;
}
EXPORT_SYMBOL(ip_xfrm_me_harder);
@@ -150,17 +135,17 @@ static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info)
}
}
-static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
+static int nf_ip_reroute(struct sk_buff *skb, const struct nf_info *info)
{
const struct ip_rt_info *rt_info = nf_info_reroute(info);
if (info->hook == NF_IP_LOCAL_OUT) {
- const struct iphdr *iph = ip_hdr(*pskb);
+ const struct iphdr *iph = ip_hdr(skb);
if (!(iph->tos == rt_info->tos
&& iph->daddr == rt_info->daddr
&& iph->saddr == rt_info->saddr))
- return ip_route_me_harder(pskb, RTN_UNSPEC);
+ return ip_route_me_harder(skb, RTN_UNSPEC);
}
return 0;
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 29114a9ccd1..2909c92ecd9 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -197,7 +197,7 @@ static inline int arp_checkentry(const struct arpt_arp *arp)
return 1;
}
-static unsigned int arpt_error(struct sk_buff **pskb,
+static unsigned int arpt_error(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -215,7 +215,7 @@ static inline struct arpt_entry *get_entry(void *base, unsigned int offset)
return (struct arpt_entry *)(base + offset);
}
-unsigned int arpt_do_table(struct sk_buff **pskb,
+unsigned int arpt_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
@@ -231,9 +231,9 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
struct xt_table_info *private;
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */
- if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) +
- (2 * (*pskb)->dev->addr_len) +
- (2 * sizeof(u32)))))
+ if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+ (2 * skb->dev->addr_len) +
+ (2 * sizeof(u32)))))
return NF_DROP;
indev = in ? in->name : nulldevname;
@@ -245,14 +245,14 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
e = get_entry(table_base, private->hook_entry[hook]);
back = get_entry(table_base, private->underflow[hook]);
- arp = arp_hdr(*pskb);
+ arp = arp_hdr(skb);
do {
- if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) {
+ if (arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
struct arpt_entry_target *t;
int hdr_len;
hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
- (2 * (*pskb)->dev->addr_len);
+ (2 * skb->dev->addr_len);
ADD_COUNTER(e->counters, hdr_len, 1);
t = arpt_get_target(e);
@@ -290,14 +290,14 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
/* Targets which reenter must return
* abs. verdicts
*/
- verdict = t->u.kernel.target->target(pskb,
+ verdict = t->u.kernel.target->target(skb,
in, out,
hook,
t->u.kernel.target,
t->data);
/* Target might have changed stuff. */
- arp = arp_hdr(*pskb);
+ arp = arp_hdr(skb);
if (verdict == ARPT_CONTINUE)
e = (void *)e + e->next_offset;
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index c4bdab47597..45fa4e20094 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -1,5 +1,6 @@
/* module that allows mangling of the arp payload */
#include <linux/module.h>
+#include <linux/netfilter.h>
#include <linux/netfilter_arp/arpt_mangle.h>
#include <net/sock.h>
@@ -8,7 +9,7 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
MODULE_DESCRIPTION("arptables arp payload mangle target");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
unsigned int hooknum, const struct xt_target *target,
const void *targinfo)
@@ -18,47 +19,38 @@ target(struct sk_buff **pskb,
unsigned char *arpptr;
int pln, hln;
- if (skb_shared(*pskb) || skb_cloned(*pskb)) {
- struct sk_buff *nskb;
+ if (skb_make_writable(skb, skb->len))
+ return NF_DROP;
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return NF_DROP;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
-
- arp = arp_hdr(*pskb);
- arpptr = skb_network_header(*pskb) + sizeof(*arp);
+ arp = arp_hdr(skb);
+ arpptr = skb_network_header(skb) + sizeof(*arp);
pln = arp->ar_pln;
hln = arp->ar_hln;
/* We assume that pln and hln were checked in the match */
if (mangle->flags & ARPT_MANGLE_SDEV) {
if (ARPT_DEV_ADDR_LEN_MAX < hln ||
- (arpptr + hln > skb_tail_pointer(*pskb)))
+ (arpptr + hln > skb_tail_pointer(skb)))
return NF_DROP;
memcpy(arpptr, mangle->src_devaddr, hln);
}
arpptr += hln;
if (mangle->flags & ARPT_MANGLE_SIP) {
if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
- (arpptr + pln > skb_tail_pointer(*pskb)))
+ (arpptr + pln > skb_tail_pointer(skb)))
return NF_DROP;
memcpy(arpptr, &mangle->u_s.src_ip, pln);
}
arpptr += pln;
if (mangle->flags & ARPT_MANGLE_TDEV) {
if (ARPT_DEV_ADDR_LEN_MAX < hln ||
- (arpptr + hln > skb_tail_pointer(*pskb)))
+ (arpptr + hln > skb_tail_pointer(skb)))
return NF_DROP;
memcpy(arpptr, mangle->tgt_devaddr, hln);
}
arpptr += hln;
if (mangle->flags & ARPT_MANGLE_TIP) {
if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
- (arpptr + pln > skb_tail_pointer(*pskb)))
+ (arpptr + pln > skb_tail_pointer(skb)))
return NF_DROP;
memcpy(arpptr, &mangle->u_t.tgt_ip, pln);
}
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 75c02306253..302d3da5f69 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -56,12 +56,12 @@ static struct arpt_table packet_filter = {
/* The work comes in here from netfilter.c */
static unsigned int arpt_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return arpt_do_table(pskb, hook, in, out, &packet_filter);
+ return arpt_do_table(skb, hook, in, out, &packet_filter);
}
static struct nf_hook_ops arpt_ops[] = {
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 23cbfc7c80f..10a2ce09fd8 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -335,6 +335,7 @@ static int
ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
{
int diff;
+ int err;
struct iphdr *user_iph = (struct iphdr *)v->payload;
if (v->data_len < sizeof(*user_iph))
@@ -347,25 +348,18 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- struct sk_buff *newskb;
-
- newskb = skb_copy_expand(e->skb,
- skb_headroom(e->skb),
- diff,
- GFP_ATOMIC);
- if (newskb == NULL) {
- printk(KERN_WARNING "ip_queue: OOM "
- "in mangle, dropping packet\n");
- return -ENOMEM;
+ err = pskb_expand_head(e->skb, 0,
+ diff - skb_tailroom(e->skb),
+ GFP_ATOMIC);
+ if (err) {
+ printk(KERN_WARNING "ip_queue: error "
+ "in mangle, dropping packet: %d\n", -err);
+ return err;
}
- if (e->skb->sk)
- skb_set_owner_w(newskb, e->skb->sk);
- kfree_skb(e->skb);
- e->skb = newskb;
}
skb_put(e->skb, diff);
}
- if (!skb_make_writable(&e->skb, v->data_len))
+ if (!skb_make_writable(e->skb, v->data_len))
return -ENOMEM;
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
e->skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 6486894f450..4b10b98640a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -169,7 +169,7 @@ ip_checkentry(const struct ipt_ip *ip)
}
static unsigned int
-ipt_error(struct sk_buff **pskb,
+ipt_error(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -312,7 +312,7 @@ static void trace_packet(struct sk_buff *skb,
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
-ipt_do_table(struct sk_buff **pskb,
+ipt_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
@@ -331,8 +331,8 @@ ipt_do_table(struct sk_buff **pskb,
struct xt_table_info *private;
/* Initialization */
- ip = ip_hdr(*pskb);
- datalen = (*pskb)->len - ip->ihl * 4;
+ ip = ip_hdr(skb);
+ datalen = skb->len - ip->ihl * 4;
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
/* We handle fragments by dealing with the first fragment as
@@ -359,7 +359,7 @@ ipt_do_table(struct sk_buff **pskb,
struct ipt_entry_target *t;
if (IPT_MATCH_ITERATE(e, do_match,
- *pskb, in, out,
+ skb, in, out,
offset, &hotdrop) != 0)
goto no_match;
@@ -371,8 +371,8 @@ ipt_do_table(struct sk_buff **pskb,
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* The packet is traced: log it */
- if (unlikely((*pskb)->nf_trace))
- trace_packet(*pskb, hook, in, out,
+ if (unlikely(skb->nf_trace))
+ trace_packet(skb, hook, in, out,
table->name, private, e);
#endif
/* Standard target? */
@@ -410,7 +410,7 @@ ipt_do_table(struct sk_buff **pskb,
((struct ipt_entry *)table_base)->comefrom
= 0xeeeeeeec;
#endif
- verdict = t->u.kernel.target->target(pskb,
+ verdict = t->u.kernel.target->target(skb,
in, out,
hook,
t->u.kernel.target,
@@ -428,8 +428,8 @@ ipt_do_table(struct sk_buff **pskb,
= 0x57acc001;
#endif
/* Target might have changed stuff. */
- ip = ip_hdr(*pskb);
- datalen = (*pskb)->len - ip->ihl * 4;
+ ip = ip_hdr(skb);
+ datalen = skb->len - ip->ihl * 4;
if (verdict == IPT_CONTINUE)
e = (void *)e + e->next_offset;
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 27f14e1ebd8..2f544dac72d 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -289,7 +289,7 @@ clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
***********************************************************************/
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -305,7 +305,7 @@ target(struct sk_buff **pskb,
* is only decremented by destroy() - and ip_tables guarantees
* that the ->target() function isn't called after ->destroy() */
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL) {
printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
/* FIXME: need to drop invalid ones, since replies
@@ -316,7 +316,7 @@ target(struct sk_buff **pskb,
/* special case: ICMP error handling. conntrack distinguishes between
* error messages (RELATED) and information requests (see below) */
- if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP
+ if (ip_hdr(skb)->protocol == IPPROTO_ICMP
&& (ctinfo == IP_CT_RELATED
|| ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY))
return XT_CONTINUE;
@@ -325,7 +325,7 @@ target(struct sk_buff **pskb,
* TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
* on, which all have an ID field [relevant for hashing]. */
- hash = clusterip_hashfn(*pskb, cipinfo->config);
+ hash = clusterip_hashfn(skb, cipinfo->config);
switch (ctinfo) {
case IP_CT_NEW:
@@ -355,7 +355,7 @@ target(struct sk_buff **pskb,
/* despite being received via linklayer multicast, this is
* actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
- (*pskb)->pkt_type = PACKET_HOST;
+ skb->pkt_type = PACKET_HOST;
return XT_CONTINUE;
}
@@ -505,12 +505,12 @@ static void arp_print(struct arp_payload *payload)
static unsigned int
arp_mangle(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct arphdr *arp = arp_hdr(*pskb);
+ struct arphdr *arp = arp_hdr(skb);
struct arp_payload *payload;
struct clusterip_config *c;
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index f1253bd3837..add110060a2 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -26,15 +26,15 @@ MODULE_DESCRIPTION("iptables ECN modification module");
/* set ECT codepoint from IP header.
* return false if there was an error. */
static inline bool
-set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
+set_ect_ip(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
{
- struct iphdr *iph = ip_hdr(*pskb);
+ struct iphdr *iph = ip_hdr(skb);
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
__u8 oldtos;
- if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ if (!skb_make_writable(skb, sizeof(struct iphdr)))
return false;
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
@@ -45,14 +45,13 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
/* Return false if there was an error. */
static inline bool
-set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
+set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
{
struct tcphdr _tcph, *tcph;
__be16 oldval;
/* Not enought header? */
- tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
- sizeof(_tcph), &_tcph);
+ tcph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (!tcph)
return false;
@@ -62,9 +61,9 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
tcph->cwr == einfo->proto.tcp.cwr))
return true;
- if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
+ if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
return false;
- tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb);
+ tcph = (void *)ip_hdr(skb) + ip_hdrlen(skb);
oldval = ((__be16 *)tcph)[6];
if (einfo->operation & IPT_ECN_OP_SET_ECE)
@@ -72,13 +71,13 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph->cwr = einfo->proto.tcp.cwr;
- nf_proto_csum_replace2(&tcph->check, *pskb,
+ nf_proto_csum_replace2(&tcph->check, skb,
oldval, ((__be16 *)tcph)[6], 0);
return true;
}
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -88,12 +87,12 @@ target(struct sk_buff **pskb,
const struct ipt_ECN_info *einfo = targinfo;
if (einfo->operation & IPT_ECN_OP_SET_IP)
- if (!set_ect_ip(pskb, einfo))
+ if (!set_ect_ip(skb, einfo))
return NF_DROP;
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
- && ip_hdr(*pskb)->protocol == IPPROTO_TCP)
- if (!set_ect_tcp(pskb, einfo))
+ && ip_hdr(skb)->protocol == IPPROTO_TCP)
+ if (!set_ect_tcp(skb, einfo))
return NF_DROP;
return XT_CONTINUE;
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 127a5e89bf1..4b5e8216a4e 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -418,7 +418,7 @@ ipt_log_packet(unsigned int pf,
}
static unsigned int
-ipt_log_target(struct sk_buff **pskb,
+ipt_log_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -432,7 +432,7 @@ ipt_log_target(struct sk_buff **pskb,
li.u.log.level = loginfo->level;
li.u.log.logflags = loginfo->logflags;
- ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
+ ipt_log_packet(PF_INET, hooknum, skb, in, out, &li,
loginfo->prefix);
return XT_CONTINUE;
}
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 3e0b562b2db..44b516e7cb7 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -52,7 +52,7 @@ masquerade_check(const char *tablename,
}
static unsigned int
-masquerade_target(struct sk_buff **pskb,
+masquerade_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -69,7 +69,7 @@ masquerade_target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
nat = nfct_nat(ct);
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
@@ -82,7 +82,7 @@ masquerade_target(struct sk_buff **pskb,
return NF_ACCEPT;
mr = targinfo;
- rt = (struct rtable *)(*pskb)->dst;
+ rt = (struct rtable *)skb->dst;
newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
if (!newsrc) {
printk("MASQUERADE: %s ate my IP address\n", out->name);
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index 41a011d5a06..f8699291e33 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -43,7 +43,7 @@ check(const char *tablename,
}
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -59,14 +59,14 @@ target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
|| hooknum == NF_IP_POST_ROUTING
|| hooknum == NF_IP_LOCAL_OUT);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT)
- new_ip = ip_hdr(*pskb)->daddr & ~netmask;
+ new_ip = ip_hdr(skb)->daddr & ~netmask;
else
- new_ip = ip_hdr(*pskb)->saddr & ~netmask;
+ new_ip = ip_hdr(skb)->saddr & ~netmask;
new_ip |= mr->range[0].min_ip & netmask;
newrange = ((struct nf_nat_range)
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 6ac7a237331..f7cf7d61a2d 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -47,7 +47,7 @@ redirect_check(const char *tablename,
}
static unsigned int
-redirect_target(struct sk_buff **pskb,
+redirect_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -63,7 +63,7 @@ redirect_target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
|| hooknum == NF_IP_LOCAL_OUT);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
/* Local packets: make them go to loopback */
@@ -76,7 +76,7 @@ redirect_target(struct sk_buff **pskb,
newdst = 0;
rcu_read_lock();
- indev = __in_dev_get_rcu((*pskb)->dev);
+ indev = __in_dev_get_rcu(skb->dev);
if (indev && (ifa = indev->ifa_list))
newdst = ifa->ifa_local;
rcu_read_unlock();
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index cb038c8fbc9..dcf4d21d511 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -131,7 +131,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
)
addr_type = RTN_LOCAL;
- if (ip_route_me_harder(&nskb, addr_type))
+ if (ip_route_me_harder(nskb, addr_type))
goto free_nskb;
nskb->ip_summed = CHECKSUM_NONE;
@@ -162,7 +162,7 @@ static inline void send_unreach(struct sk_buff *skb_in, int code)
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
}
-static unsigned int reject(struct sk_buff **pskb,
+static unsigned int reject(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -173,7 +173,7 @@ static unsigned int reject(struct sk_buff **pskb,
/* Our naive response construction doesn't deal with IP
options, and probably shouldn't try. */
- if (ip_hdrlen(*pskb) != sizeof(struct iphdr))
+ if (ip_hdrlen(skb) != sizeof(struct iphdr))
return NF_DROP;
/* WARNING: This code causes reentry within iptables.
@@ -181,28 +181,28 @@ static unsigned int reject(struct sk_buff **pskb,
must return an absolute verdict. --RR */
switch (reject->with) {
case IPT_ICMP_NET_UNREACHABLE:
- send_unreach(*pskb, ICMP_NET_UNREACH);
+ send_unreach(skb, ICMP_NET_UNREACH);
break;
case IPT_ICMP_HOST_UNREACHABLE:
- send_unreach(*pskb, ICMP_HOST_UNREACH);
+ send_unreach(skb, ICMP_HOST_UNREACH);
break;
case IPT_ICMP_PROT_UNREACHABLE:
- send_unreach(*pskb, ICMP_PROT_UNREACH);
+ send_unreach(skb, ICMP_PROT_UNREACH);
break;
case IPT_ICMP_PORT_UNREACHABLE:
- send_unreach(*pskb, ICMP_PORT_UNREACH);
+ send_unreach(skb, ICMP_PORT_UNREACH);
break;
case IPT_ICMP_NET_PROHIBITED:
- send_unreach(*pskb, ICMP_NET_ANO);
+ send_unreach(skb, ICMP_NET_ANO);
break;
case IPT_ICMP_HOST_PROHIBITED:
- send_unreach(*pskb, ICMP_HOST_ANO);
+ send_unreach(skb, ICMP_HOST_ANO);
break;
case IPT_ICMP_ADMIN_PROHIBITED:
- send_unreach(*pskb, ICMP_PKT_FILTERED);
+ send_unreach(skb, ICMP_PKT_FILTERED);
break;
case IPT_TCP_RESET:
- send_reset(*pskb, hooknum);
+ send_reset(skb, hooknum);
case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */
break;
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 97641f1a97f..8988571436b 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -104,7 +104,7 @@ same_destroy(const struct xt_target *target, void *targinfo)
}
static unsigned int
-same_target(struct sk_buff **pskb,
+same_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -121,7 +121,7 @@ same_target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_POST_ROUTING);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 25f5d0b3906..d4573baa7f2 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -21,7 +21,7 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables TOS mangling module");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -29,13 +29,13 @@ target(struct sk_buff **pskb,
const void *targinfo)
{
const struct ipt_tos_target_info *tosinfo = targinfo;
- struct iphdr *iph = ip_hdr(*pskb);
+ struct iphdr *iph = ip_hdr(skb);
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
__u8 oldtos;
- if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
oldtos = iph->tos;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index 2b54e7b0cfe..c620a052766 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -20,7 +20,7 @@ MODULE_DESCRIPTION("IP tables TTL modification module");
MODULE_LICENSE("GPL");
static unsigned int
-ipt_ttl_target(struct sk_buff **pskb,
+ipt_ttl_target(struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
unsigned int hooknum, const struct xt_target *target,
const void *targinfo)
@@ -29,10 +29,10 @@ ipt_ttl_target(struct sk_buff **pskb,
const struct ipt_TTL_info *info = targinfo;
int new_ttl;
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return NF_DROP;
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
switch (info->mode) {
case IPT_TTL_SET:
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index c636d6d6357..212b830765a 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -279,7 +279,7 @@ alloc_failure:
spin_unlock_bh(&ulog_lock);
}
-static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+static unsigned int ipt_ulog_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -288,7 +288,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
{
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
- ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
+ ipt_ulog_packet(hooknum, skb, in, out, loginfo, NULL);
return XT_CONTINUE;
}
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 4f51c1d7d2d..ba3262c6043 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -62,31 +62,31 @@ static struct xt_table packet_filter = {
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ipt_do_table(pskb, hook, in, out, &packet_filter);
+ return ipt_do_table(skb, hook, in, out, &packet_filter);
}
static unsigned int
ipt_local_out_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr)
- || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("iptable_filter: ignoring short SOCK_RAW "
"packet.\n");
return NF_ACCEPT;
}
- return ipt_do_table(pskb, hook, in, out, &packet_filter);
+ return ipt_do_table(skb, hook, in, out, &packet_filter);
}
static struct nf_hook_ops ipt_ops[] = {
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 902446f7cbc..b4360a69d5c 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -75,17 +75,17 @@ static struct xt_table packet_mangler = {
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_route_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ipt_do_table(pskb, hook, in, out, &packet_mangler);
+ return ipt_do_table(skb, hook, in, out, &packet_mangler);
}
static unsigned int
ipt_local_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -97,8 +97,8 @@ ipt_local_hook(unsigned int hook,
u_int32_t mark;
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr)
- || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr)
+ || ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("iptable_mangle: ignoring short SOCK_RAW "
"packet.\n");
@@ -106,22 +106,22 @@ ipt_local_hook(unsigned int hook,
}
/* Save things which could affect route */
- mark = (*pskb)->mark;
- iph = ip_hdr(*pskb);
+ mark = skb->mark;
+ iph = ip_hdr(skb);
saddr = iph->saddr;
daddr = iph->daddr;
tos = iph->tos;
- ret = ipt_do_table(pskb, hook, in, out, &packet_mangler);
+ ret = ipt_do_table(skb, hook, in, out, &packet_mangler);
/* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
if (iph->saddr != saddr ||
iph->daddr != daddr ||
- (*pskb)->mark != mark ||
+ skb->mark != mark ||
iph->tos != tos)
- if (ip_route_me_harder(pskb, RTN_UNSPEC))
+ if (ip_route_me_harder(skb, RTN_UNSPEC))
ret = NF_DROP;
}
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index d6e50339568..5de6e57ac55 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -47,30 +47,30 @@ static struct xt_table packet_raw = {
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ipt_do_table(pskb, hook, in, out, &packet_raw);
+ return ipt_do_table(skb, hook, in, out, &packet_raw);
}
static unsigned int
ipt_local_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr) ||
- ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("iptable_raw: ignoring short SOCK_RAW"
"packet.\n");
return NF_ACCEPT;
}
- return ipt_do_table(pskb, hook, in, out, &packet_raw);
+ return ipt_do_table(skb, hook, in, out, &packet_raw);
}
/* 'raw' is the very first table. */
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 2fcb9249a8d..831e9b29806 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -63,19 +63,20 @@ static int ipv4_print_conntrack(struct seq_file *s,
}
/* Returns new sk_buff, or NULL */
-static struct sk_buff *
-nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
+static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
{
+ int err;
+
skb_orphan(skb);
local_bh_disable();
- skb = ip_defrag(skb, user);
+ err = ip_defrag(skb, user);
local_bh_enable();
- if (skb)
+ if (!err)
ip_send_check(ip_hdr(skb));
- return skb;
+ return err;
}
static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
@@ -99,17 +100,17 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
}
static unsigned int ipv4_confirm(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* We've seen it coming out the other side: confirm it */
- return nf_conntrack_confirm(pskb);
+ return nf_conntrack_confirm(skb);
}
static unsigned int ipv4_conntrack_help(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -120,7 +121,7 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
struct nf_conntrack_helper *helper;
/* This is where we call the helper: as the packet goes out. */
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
return NF_ACCEPT;
@@ -131,56 +132,55 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
helper = rcu_dereference(help->helper);
if (!helper)
return NF_ACCEPT;
- return helper->help(pskb, skb_network_offset(*pskb) + ip_hdrlen(*pskb),
+ return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
ct, ctinfo);
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* Previously seen (loopback)? Ignore. Do this before
fragment check. */
- if ((*pskb)->nfct)
+ if (skb->nfct)
return NF_ACCEPT;
/* Gather fragments. */
- if (ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- *pskb = nf_ct_ipv4_gather_frags(*pskb,
- hooknum == NF_IP_PRE_ROUTING ?
- IP_DEFRAG_CONNTRACK_IN :
- IP_DEFRAG_CONNTRACK_OUT);
- if (!*pskb)
+ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
+ if (nf_ct_ipv4_gather_frags(skb,
+ hooknum == NF_IP_PRE_ROUTING ?
+ IP_DEFRAG_CONNTRACK_IN :
+ IP_DEFRAG_CONNTRACK_OUT))
return NF_STOLEN;
}
return NF_ACCEPT;
}
static unsigned int ipv4_conntrack_in(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return nf_conntrack_in(PF_INET, hooknum, pskb);
+ return nf_conntrack_in(PF_INET, hooknum, skb);
}
static unsigned int ipv4_conntrack_local(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr)
- || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ipt_hook: happy cracking.\n");
return NF_ACCEPT;
}
- return nf_conntrack_in(PF_INET, hooknum, pskb);
+ return nf_conntrack_in(PF_INET, hooknum, skb);
}
/* Connection tracking may drop packets, but never alters them, so
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index bd93a1d7105..35a5aa69cd9 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -24,7 +24,7 @@ MODULE_DESCRIPTION("Amanda NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_amanda");
-static unsigned int help(struct sk_buff **pskb,
+static unsigned int help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
@@ -53,7 +53,7 @@ static unsigned int help(struct sk_buff **pskb,
return NF_DROP;
sprintf(buffer, "%u", port);
- ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
+ ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
matchoff, matchlen,
buffer, strlen(buffer));
if (ret != NF_ACCEPT)
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 7221aa20e6f..56e93f692e8 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -349,7 +349,7 @@ EXPORT_SYMBOL(nf_nat_setup_info);
/* Returns true if succeeded. */
static int
manip_pkt(u_int16_t proto,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *target,
enum nf_nat_manip_type maniptype)
@@ -357,19 +357,19 @@ manip_pkt(u_int16_t proto,
struct iphdr *iph;
struct nf_nat_protocol *p;
- if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
+ if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
return 0;
- iph = (void *)(*pskb)->data + iphdroff;
+ iph = (void *)skb->data + iphdroff;
/* Manipulate protcol part. */
/* rcu_read_lock()ed by nf_hook_slow */
p = __nf_nat_proto_find(proto);
- if (!p->manip_pkt(pskb, iphdroff, target, maniptype))
+ if (!p->manip_pkt(skb, iphdroff, target, maniptype))
return 0;
- iph = (void *)(*pskb)->data + iphdroff;
+ iph = (void *)skb->data + iphdroff;
if (maniptype == IP_NAT_MANIP_SRC) {
nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
@@ -385,7 +385,7 @@ manip_pkt(u_int16_t proto,
unsigned int nf_nat_packet(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
- struct sk_buff **pskb)
+ struct sk_buff *skb)
{
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
@@ -407,7 +407,7 @@ unsigned int nf_nat_packet(struct nf_conn *ct,
/* We are aiming to look like inverse of other direction. */
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
- if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
+ if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype))
return NF_DROP;
}
return NF_ACCEPT;
@@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(nf_nat_packet);
int nf_nat_icmp_reply_translation(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
- struct sk_buff **pskb)
+ struct sk_buff *skb)
{
struct {
struct icmphdr icmp;
@@ -426,24 +426,24 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
} *inside;
struct nf_conntrack_l4proto *l4proto;
struct nf_conntrack_tuple inner, target;
- int hdrlen = ip_hdrlen(*pskb);
+ int hdrlen = ip_hdrlen(skb);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
- if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
+ if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
return 0;
- inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
+ inside = (void *)skb->data + ip_hdrlen(skb);
/* We're actually going to mangle it beyond trivial checksum
adjustment, so make sure the current checksum is correct. */
- if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
+ if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
return 0;
/* Must be RELATED */
- NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
- (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
+ NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||
+ skb->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
/* Redirects on non-null nats must be dropped, else they'll
start talking to each other without our translation, and be
@@ -458,15 +458,15 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
}
pr_debug("icmp_reply_translation: translating error %p manip %u "
- "dir %s\n", *pskb, manip,
+ "dir %s\n", skb, manip,
dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
/* rcu_read_lock()ed by nf_hook_slow */
l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
- if (!nf_ct_get_tuple(*pskb,
- ip_hdrlen(*pskb) + sizeof(struct icmphdr),
- (ip_hdrlen(*pskb) +
+ if (!nf_ct_get_tuple(skb,
+ ip_hdrlen(skb) + sizeof(struct icmphdr),
+ (ip_hdrlen(skb) +
sizeof(struct icmphdr) + inside->ip.ihl * 4),
(u_int16_t)AF_INET,
inside->ip.protocol,
@@ -478,19 +478,19 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
pass all hooks (locally-generated ICMP). Consider incoming
packet: PREROUTING (DST manip), routing produces ICMP, goes
through POSTROUTING (which must correct the DST manip). */
- if (!manip_pkt(inside->ip.protocol, pskb,
- ip_hdrlen(*pskb) + sizeof(inside->icmp),
+ if (!manip_pkt(inside->ip.protocol, skb,
+ ip_hdrlen(skb) + sizeof(inside->icmp),
&ct->tuplehash[!dir].tuple,
!manip))
return 0;
- if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
/* Reloading "inside" here since manip_pkt inner. */
- inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
+ inside = (void *)skb->data + ip_hdrlen(skb);
inside->icmp.checksum = 0;
inside->icmp.checksum =
- csum_fold(skb_checksum(*pskb, hdrlen,
- (*pskb)->len - hdrlen, 0));
+ csum_fold(skb_checksum(skb, hdrlen,
+ skb->len - hdrlen, 0));
}
/* Change outer to look the reply to an incoming packet
@@ -506,7 +506,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
if (ct->status & statusbit) {
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
- if (!manip_pkt(0, pskb, 0, &target, manip))
+ if (!manip_pkt(0, skb, 0, &target, manip))
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
index 3663bd879c3..e1a16d3ea4c 100644
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -28,7 +28,7 @@ MODULE_ALIAS("ip_nat_ftp");
/* FIXME: Time out? --RR */
static int
-mangle_rfc959_packet(struct sk_buff **pskb,
+mangle_rfc959_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
@@ -43,13 +43,13 @@ mangle_rfc959_packet(struct sk_buff **pskb,
pr_debug("calling nf_nat_mangle_tcp_packet\n");
- return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
+ return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}
/* |1|132.235.1.2|6275| */
static int
-mangle_eprt_packet(struct sk_buff **pskb,
+mangle_eprt_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
@@ -63,13 +63,13 @@ mangle_eprt_packet(struct sk_buff **pskb,
pr_debug("calling nf_nat_mangle_tcp_packet\n");
- return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
+ return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}
/* |1|132.235.1.2|6275| */
static int
-mangle_epsv_packet(struct sk_buff **pskb,
+mangle_epsv_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
@@ -83,11 +83,11 @@ mangle_epsv_packet(struct sk_buff **pskb,
pr_debug("calling nf_nat_mangle_tcp_packet\n");
- return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
+ return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}
-static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
+static int (*mangle[])(struct sk_buff *, __be32, u_int16_t,
unsigned int, unsigned int, struct nf_conn *,
enum ip_conntrack_info)
= {
@@ -99,7 +99,7 @@ static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
-static unsigned int nf_nat_ftp(struct sk_buff **pskb,
+static unsigned int nf_nat_ftp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
enum nf_ct_ftp_type type,
unsigned int matchoff,
@@ -132,7 +132,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb,
if (port == 0)
return NF_DROP;
- if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo)) {
+ if (!mangle[type](skb, newip, port, matchoff, matchlen, ct, ctinfo)) {
nf_ct_unexpect_related(exp);
return NF_DROP;
}
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index c1b059a7370..a868c8c4132 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -22,12 +22,12 @@
#include <linux/netfilter/nf_conntrack_h323.h>
/****************************************************************************/
-static int set_addr(struct sk_buff **pskb,
+static int set_addr(struct sk_buff *skb,
unsigned char **data, int dataoff,
unsigned int addroff, __be32 ip, __be16 port)
{
enum ip_conntrack_info ctinfo;
- struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo);
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
struct {
__be32 ip;
__be16 port;
@@ -38,8 +38,8 @@ static int set_addr(struct sk_buff **pskb,
buf.port = port;
addroff += dataoff;
- if (ip_hdr(*pskb)->protocol == IPPROTO_TCP) {
- if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
+ if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
addroff, sizeof(buf),
(char *) &buf, sizeof(buf))) {
if (net_ratelimit())
@@ -49,14 +49,13 @@ static int set_addr(struct sk_buff **pskb,
}
/* Relocate data pointer */
- th = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
+ th = skb_header_pointer(skb, ip_hdrlen(skb),
sizeof(_tcph), &_tcph);
if (th == NULL)
return -1;
- *data = (*pskb)->data + ip_hdrlen(*pskb) +
- th->doff * 4 + dataoff;
+ *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
} else {
- if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
addroff, sizeof(buf),
(char *) &buf, sizeof(buf))) {
if (net_ratelimit())
@@ -67,36 +66,35 @@ static int set_addr(struct sk_buff **pskb,
/* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
* or pull everything in a linear buffer, so we can safely
* use the skb pointers now */
- *data = ((*pskb)->data + ip_hdrlen(*pskb) +
- sizeof(struct udphdr));
+ *data = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
}
return 0;
}
/****************************************************************************/
-static int set_h225_addr(struct sk_buff **pskb,
+static int set_h225_addr(struct sk_buff *skb,
unsigned char **data, int dataoff,
TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
{
- return set_addr(pskb, data, dataoff, taddr->ipAddress.ip,
+ return set_addr(skb, data, dataoff, taddr->ipAddress.ip,
addr->ip, port);
}
/****************************************************************************/
-static int set_h245_addr(struct sk_buff **pskb,
+static int set_h245_addr(struct sk_buff *skb,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
{
- return set_addr(pskb, data, dataoff,
+ return set_addr(skb, data, dataoff,
taddr->unicastAddress.iPAddress.network,
addr->ip, port);
}
/****************************************************************************/
-static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
+static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count)
@@ -125,7 +123,7 @@ static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
NIPQUAD(addr.ip), port,
NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
info->sig_port[!dir]);
- return set_h225_addr(pskb, data, 0, &taddr[i],
+ return set_h225_addr(skb, data, 0, &taddr[i],
&ct->tuplehash[!dir].
tuple.dst.u3,
info->sig_port[!dir]);
@@ -137,7 +135,7 @@ static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
NIPQUAD(addr.ip), port,
NIPQUAD(ct->tuplehash[!dir].tuple.src.u3.ip),
info->sig_port[!dir]);
- return set_h225_addr(pskb, data, 0, &taddr[i],
+ return set_h225_addr(skb, data, 0, &taddr[i],
&ct->tuplehash[!dir].
tuple.src.u3,
info->sig_port[!dir]);
@@ -149,7 +147,7 @@ static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
+static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count)
@@ -168,7 +166,7 @@ static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
NIPQUAD(addr.ip), ntohs(port),
NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
- return set_h225_addr(pskb, data, 0, &taddr[i],
+ return set_h225_addr(skb, data, 0, &taddr[i],
&ct->tuplehash[!dir].tuple.dst.u3,
ct->tuplehash[!dir].tuple.
dst.u.udp.port);
@@ -179,7 +177,7 @@ static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
+static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
@@ -244,7 +242,7 @@ static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Modify signal */
- if (set_h245_addr(pskb, data, dataoff, taddr,
+ if (set_h245_addr(skb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons((port & htons(1)) ? nated_port + 1 :
nated_port)) == 0) {
@@ -273,7 +271,7 @@ static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
+static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr, __be16 port,
@@ -301,7 +299,7 @@ static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Modify signal */
- if (set_h245_addr(pskb, data, dataoff, taddr,
+ if (set_h245_addr(skb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) < 0) {
nf_ct_unexpect_related(exp);
@@ -318,7 +316,7 @@ static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
+static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
@@ -351,7 +349,7 @@ static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Modify signal */
- if (set_h225_addr(pskb, data, dataoff, taddr,
+ if (set_h225_addr(skb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
/* Save ports */
@@ -406,7 +404,7 @@ static void ip_nat_q931_expect(struct nf_conn *new,
}
/****************************************************************************/
-static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
+static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, TransportAddress *taddr, int idx,
__be16 port, struct nf_conntrack_expect *exp)
@@ -439,7 +437,7 @@ static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Modify signal */
- if (set_h225_addr(pskb, data, 0, &taddr[idx],
+ if (set_h225_addr(skb, data, 0, &taddr[idx],
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
/* Save ports */
@@ -450,7 +448,7 @@ static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
if (idx > 0 &&
get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
(ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
- set_h225_addr(pskb, data, 0, &taddr[0],
+ set_h225_addr(skb, data, 0, &taddr[0],
&ct->tuplehash[!dir].tuple.dst.u3,
info->sig_port[!dir]);
}
@@ -495,7 +493,7 @@ static void ip_nat_callforwarding_expect(struct nf_conn *new,
}
/****************************************************************************/
-static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
+static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
@@ -525,7 +523,7 @@ static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Modify signal */
- if (!set_h225_addr(pskb, data, dataoff, taddr,
+ if (!set_h225_addr(skb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
nf_ct_unexpect_related(exp);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 93d8a0a8f03..8718da00ef2 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -111,22 +111,14 @@ static void mangle_contents(struct sk_buff *skb,
}
/* Unusual, but possible case. */
-static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
+static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
{
- struct sk_buff *nskb;
-
- if ((*pskb)->len + extra > 65535)
+ if (skb->len + extra > 65535)
return 0;
- nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
- if (!nskb)
+ if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))
return 0;
- /* Transfer socket to new skb. */
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
return 1;
}
@@ -139,7 +131,7 @@ static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
*
* */
int
-nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
+nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
@@ -147,37 +139,37 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
const char *rep_buffer,
unsigned int rep_len)
{
- struct rtable *rt = (struct rtable *)(*pskb)->dst;
+ struct rtable *rt = (struct rtable *)skb->dst;
struct iphdr *iph;
struct tcphdr *tcph;
int oldlen, datalen;
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return 0;
if (rep_len > match_len &&
- rep_len - match_len > skb_tailroom(*pskb) &&
- !enlarge_skb(pskb, rep_len - match_len))
+ rep_len - match_len > skb_tailroom(skb) &&
+ !enlarge_skb(skb, rep_len - match_len))
return 0;
- SKB_LINEAR_ASSERT(*pskb);
+ SKB_LINEAR_ASSERT(skb);
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
tcph = (void *)iph + iph->ihl*4;
- oldlen = (*pskb)->len - iph->ihl*4;
- mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+ oldlen = skb->len - iph->ihl*4;
+ mangle_contents(skb, iph->ihl*4 + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len);
- datalen = (*pskb)->len - iph->ihl*4;
- if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+ datalen = skb->len - iph->ihl*4;
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
- (*pskb)->dev->features & NETIF_F_V4_CSUM) {
- (*pskb)->ip_summed = CHECKSUM_PARTIAL;
- (*pskb)->csum_start = skb_headroom(*pskb) +
- skb_network_offset(*pskb) +
- iph->ihl * 4;
- (*pskb)->csum_offset = offsetof(struct tcphdr, check);
+ skb->dev->features & NETIF_F_V4_CSUM) {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_headroom(skb) +
+ skb_network_offset(skb) +
+ iph->ihl * 4;
+ skb->csum_offset = offsetof(struct tcphdr, check);
tcph->check = ~tcp_v4_check(datalen,
iph->saddr, iph->daddr, 0);
} else {
@@ -188,7 +180,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen, 0));
}
} else
- nf_proto_csum_replace2(&tcph->check, *pskb,
+ nf_proto_csum_replace2(&tcph->check, skb,
htons(oldlen), htons(datalen), 1);
if (rep_len != match_len) {
@@ -197,7 +189,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
(int)rep_len - (int)match_len,
ct, ctinfo);
/* Tell TCP window tracking about seq change */
- nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb),
+ nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
ct, CTINFO2DIR(ctinfo));
}
return 1;
@@ -215,7 +207,7 @@ EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
* should be fairly easy to do.
*/
int
-nf_nat_mangle_udp_packet(struct sk_buff **pskb,
+nf_nat_mangle_udp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
@@ -223,48 +215,48 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
const char *rep_buffer,
unsigned int rep_len)
{
- struct rtable *rt = (struct rtable *)(*pskb)->dst;
+ struct rtable *rt = (struct rtable *)skb->dst;
struct iphdr *iph;
struct udphdr *udph;
int datalen, oldlen;
/* UDP helpers might accidentally mangle the wrong packet */
- iph = ip_hdr(*pskb);
- if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
+ iph = ip_hdr(skb);
+ if (skb->len < iph->ihl*4 + sizeof(*udph) +
match_offset + match_len)
return 0;
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return 0;
if (rep_len > match_len &&
- rep_len - match_len > skb_tailroom(*pskb) &&
- !enlarge_skb(pskb, rep_len - match_len))
+ rep_len - match_len > skb_tailroom(skb) &&
+ !enlarge_skb(skb, rep_len - match_len))
return 0;
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
udph = (void *)iph + iph->ihl*4;
- oldlen = (*pskb)->len - iph->ihl*4;
- mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
+ oldlen = skb->len - iph->ihl*4;
+ mangle_contents(skb, iph->ihl*4 + sizeof(*udph),
match_offset, match_len, rep_buffer, rep_len);
/* update the length of the UDP packet */
- datalen = (*pskb)->len - iph->ihl*4;
+ datalen = skb->len - iph->ihl*4;
udph->len = htons(datalen);
/* fix udp checksum if udp checksum was previously calculated */
- if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
+ if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
return 1;
- if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
- (*pskb)->dev->features & NETIF_F_V4_CSUM) {
- (*pskb)->ip_summed = CHECKSUM_PARTIAL;
- (*pskb)->csum_start = skb_headroom(*pskb) +
- skb_network_offset(*pskb) +
- iph->ihl * 4;
- (*pskb)->csum_offset = offsetof(struct udphdr, check);
+ skb->dev->features & NETIF_F_V4_CSUM) {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_headroom(skb) +
+ skb_network_offset(skb) +
+ iph->ihl * 4;
+ skb->csum_offset = offsetof(struct udphdr, check);
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP,
0);
@@ -278,7 +270,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
udph->check = CSUM_MANGLED_0;
}
} else
- nf_proto_csum_replace2(&udph->check, *pskb,
+ nf_proto_csum_replace2(&udph->check, skb,
htons(oldlen), htons(datalen), 1);
return 1;
@@ -330,7 +322,7 @@ sack_adjust(struct sk_buff *skb,
/* TCP SACK sequence number adjustment */
static inline unsigned int
-nf_nat_sack_adjust(struct sk_buff **pskb,
+nf_nat_sack_adjust(struct sk_buff *skb,
struct tcphdr *tcph,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -338,17 +330,17 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
unsigned int dir, optoff, optend;
struct nf_conn_nat *nat = nfct_nat(ct);
- optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
- optend = ip_hdrlen(*pskb) + tcph->doff * 4;
+ optoff = ip_hdrlen(skb) + sizeof(struct tcphdr);
+ optend = ip_hdrlen(skb) + tcph->doff * 4;
- if (!skb_make_writable(pskb, optend))
+ if (!skb_make_writable(skb, optend))
return 0;
dir = CTINFO2DIR(ctinfo);
while (optoff < optend) {
/* Usually: option, length. */
- unsigned char *op = (*pskb)->data + optoff;
+ unsigned char *op = skb->data + optoff;
switch (op[0]) {
case TCPOPT_EOL:
@@ -365,7 +357,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
if (op[0] == TCPOPT_SACK &&
op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
- sack_adjust(*pskb, tcph, optoff+2,
+ sack_adjust(skb, tcph, optoff+2,
optoff+op[1], &nat->seq[!dir]);
optoff += op[1];
}
@@ -375,7 +367,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
int
-nf_nat_seq_adjust(struct sk_buff **pskb,
+nf_nat_seq_adjust(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
@@ -390,10 +382,10 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
this_way = &nat->seq[dir];
other_way = &nat->seq[!dir];
- if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
+ if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
return 0;
- tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
+ tcph = (void *)skb->data + ip_hdrlen(skb);
if (after(ntohl(tcph->seq), this_way->correction_pos))
newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
else
@@ -405,8 +397,8 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
else
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
- nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
- nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
+ nf_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
+ nf_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
@@ -415,10 +407,10 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
tcph->seq = newseq;
tcph->ack_seq = newack;
- if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
+ if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo))
return 0;
- nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir);
+ nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir);
return 1;
}
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index bcf274bba60..766e2c16c6b 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("IRC (DCC) NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_irc");
-static unsigned int help(struct sk_buff **pskb,
+static unsigned int help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
@@ -58,7 +58,7 @@ static unsigned int help(struct sk_buff **pskb,
pr_debug("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
buffer, NIPQUAD(ip), port);
- ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
+ ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
matchoff, matchlen, buffer,
strlen(buffer));
if (ret != NF_ACCEPT)
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 984ec8308b2..e1385a09907 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -110,7 +110,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
/* outbound packets == from PNS to PAC */
static int
-pptp_outbound_pkt(struct sk_buff **pskb,
+pptp_outbound_pkt(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
@@ -175,7 +175,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
/* mangle packet */
- if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
cid_off + sizeof(struct pptp_pkt_hdr) +
sizeof(struct PptpControlHeader),
sizeof(new_callid), (char *)&new_callid,
@@ -213,7 +213,7 @@ pptp_exp_gre(struct nf_conntrack_expect *expect_orig,
/* inbound packets == from PAC to PNS */
static int
-pptp_inbound_pkt(struct sk_buff **pskb,
+pptp_inbound_pkt(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
@@ -268,7 +268,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
pr_debug("altering peer call id from 0x%04x to 0x%04x\n",
ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
- if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
pcid_off + sizeof(struct pptp_pkt_hdr) +
sizeof(struct PptpControlHeader),
sizeof(new_pcid), (char *)&new_pcid,
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index d562290b182..b820f996035 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -98,21 +98,21 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
/* manipulate a GRE packet according to maniptype */
static int
-gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff,
+gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
struct gre_hdr *greh;
struct gre_hdr_pptp *pgreh;
- struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
unsigned int hdroff = iphdroff + iph->ihl * 4;
/* pgreh includes two optional 32bit fields which are not required
* to be there. That's where the magic '8' comes from */
- if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8))
+ if (!skb_make_writable(skb, hdroff + sizeof(*pgreh) - 8))
return 0;
- greh = (void *)(*pskb)->data + hdroff;
+ greh = (void *)skb->data + hdroff;
pgreh = (struct gre_hdr_pptp *)greh;
/* we only have destination manip of a packet, since 'source key'
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index 898d7377115..b9fc724388f 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -52,20 +52,20 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
}
static int
-icmp_manip_pkt(struct sk_buff **pskb,
+icmp_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
- struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
struct icmphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
- if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
+ if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
return 0;
- hdr = (struct icmphdr *)((*pskb)->data + hdroff);
- nf_proto_csum_replace2(&hdr->checksum, *pskb,
+ hdr = (struct icmphdr *)(skb->data + hdroff);
+ nf_proto_csum_replace2(&hdr->checksum, skb,
hdr->un.echo.id, tuple->src.u.icmp.id, 0);
hdr->un.echo.id = tuple->src.u.icmp.id;
return 1;
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 5bbbb2acdc7..6bab2e18445 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -88,12 +88,12 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
}
static int
-tcp_manip_pkt(struct sk_buff **pskb,
+tcp_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
- struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
struct tcphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
__be32 oldip, newip;
@@ -103,14 +103,14 @@ tcp_manip_pkt(struct sk_buff **pskb,
/* this could be a inner header returned in icmp packet; in such
cases we cannot update the checksum field since it is outside of
the 8 bytes of transport layer headers we are guaranteed */
- if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
+ if (skb->len >= hdroff + sizeof(struct tcphdr))
hdrsize = sizeof(struct tcphdr);
- if (!skb_make_writable(pskb, hdroff + hdrsize))
+ if (!skb_make_writable(skb, hdroff + hdrsize))
return 0;
- iph = (struct iphdr *)((*pskb)->data + iphdroff);
- hdr = (struct tcphdr *)((*pskb)->data + hdroff);
+ iph = (struct iphdr *)(skb->data + iphdroff);
+ hdr = (struct tcphdr *)(skb->data + hdroff);
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
@@ -132,8 +132,8 @@ tcp_manip_pkt(struct sk_buff **pskb,
if (hdrsize < sizeof(*hdr))
return 1;
- nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
- nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
+ nf_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
+ nf_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
return 1;
}
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index a0af4fd9558..cbf1a61e290 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -86,22 +86,22 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple,
}
static int
-udp_manip_pkt(struct sk_buff **pskb,
+udp_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
- struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
struct udphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
__be32 oldip, newip;
__be16 *portptr, newport;
- if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
+ if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
return 0;
- iph = (struct iphdr *)((*pskb)->data + iphdroff);
- hdr = (struct udphdr *)((*pskb)->data + hdroff);
+ iph = (struct iphdr *)(skb->data + iphdroff);
+ hdr = (struct udphdr *)(skb->data + hdroff);
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
@@ -116,9 +116,9 @@ udp_manip_pkt(struct sk_buff **pskb,
newport = tuple->dst.u.udp.port;
portptr = &hdr->dest;
}
- if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
- nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
- nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport,
+ if (hdr->check || skb->ip_summed == CHECKSUM_PARTIAL) {
+ nf_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
+ nf_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
0);
if (!hdr->check)
hdr->check = CSUM_MANGLED_0;
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
index f50d0203f9c..cfd2742e970 100644
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c
@@ -37,7 +37,7 @@ static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
}
static int
-unknown_manip_pkt(struct sk_buff **pskb,
+unknown_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 76ec59ae524..46b25ab5f78 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -65,7 +65,7 @@ static struct xt_table nat_table = {
};
/* Source NAT */
-static unsigned int ipt_snat_target(struct sk_buff **pskb,
+static unsigned int ipt_snat_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -78,7 +78,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
@@ -107,7 +107,7 @@ static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
ip_rt_put(rt);
}
-static unsigned int ipt_dnat_target(struct sk_buff **pskb,
+static unsigned int ipt_dnat_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -121,14 +121,14 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_LOCAL_OUT);
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
if (hooknum == NF_IP_LOCAL_OUT &&
mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
- warn_if_extra_mangle(ip_hdr(*pskb)->daddr,
+ warn_if_extra_mangle(ip_hdr(skb)->daddr,
mr->range[0].min_ip);
return nf_nat_setup_info(ct, &mr->range[0], hooknum);
@@ -204,7 +204,7 @@ alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
return nf_nat_setup_info(ct, &range, hooknum);
}
-int nf_nat_rule_find(struct sk_buff **pskb,
+int nf_nat_rule_find(struct sk_buff *skb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
@@ -212,7 +212,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
{
int ret;
- ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
+ ret = ipt_do_table(skb, hooknum, in, out, &nat_table);
if (ret == NF_ACCEPT) {
if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index e14d41976c2..ce9edbcc01e 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -60,7 +60,7 @@ static void addr_map_init(struct nf_conn *ct, struct addr_map *map)
}
}
-static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
+static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
struct nf_conn *ct, const char **dptr, size_t dlen,
enum sip_header_pos pos, struct addr_map *map)
{
@@ -84,15 +84,15 @@ static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
} else
return 1;
- if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
matchoff, matchlen, addr, addrlen))
return 0;
- *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
+ *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
return 1;
}
-static unsigned int ip_nat_sip(struct sk_buff **pskb,
+static unsigned int ip_nat_sip(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char **dptr)
@@ -101,8 +101,8 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb,
struct addr_map map;
int dataoff, datalen;
- dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
- datalen = (*pskb)->len - dataoff;
+ dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
+ datalen = skb->len - dataoff;
if (datalen < sizeof("SIP/2.0") - 1)
return NF_ACCEPT;
@@ -121,19 +121,19 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb,
else
pos = POS_REQ_URI;
- if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map))
+ if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map))
return NF_DROP;
}
- if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
- !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
- !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
- !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
+ if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
+ !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
+ !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
+ !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
return NF_DROP;
return NF_ACCEPT;
}
-static unsigned int mangle_sip_packet(struct sk_buff **pskb,
+static unsigned int mangle_sip_packet(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char **dptr, size_t dlen,
@@ -145,16 +145,16 @@ static unsigned int mangle_sip_packet(struct sk_buff **pskb,
if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
return 0;
- if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
matchoff, matchlen, buffer, bufflen))
return 0;
/* We need to reload this. Thanks Patrick. */
- *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
+ *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
return 1;
}
-static int mangle_content_len(struct sk_buff **pskb,
+static int mangle_content_len(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char *dptr)
@@ -163,22 +163,22 @@ static int mangle_content_len(struct sk_buff **pskb,
char buffer[sizeof("65536")];
int bufflen;
- dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
+ dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
/* Get actual SDP lenght */
- if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff,
+ if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
&matchlen, POS_SDP_HEADER) > 0) {
/* since ct_sip_get_info() give us a pointer passing 'v='
we need to add 2 bytes in this count. */
- int c_len = (*pskb)->len - dataoff - matchoff + 2;
+ int c_len = skb->len - dataoff - matchoff + 2;
/* Now, update SDP length */
- if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff,
+ if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
&matchlen, POS_CONTENT) > 0) {
bufflen = sprintf(buffer, "%u", c_len);
- return nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ return nf_nat_mangle_udp_packet(skb, ct, ctinfo,
matchoff, matchlen,
buffer, bufflen);
}
@@ -186,7 +186,7 @@ static int mangle_content_len(struct sk_buff **pskb,
return 0;
}
-static unsigned int mangle_sdp(struct sk_buff **pskb,
+static unsigned int mangle_sdp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
__be32 newip, u_int16_t port,
@@ -195,25 +195,25 @@ static unsigned int mangle_sdp(struct sk_buff **pskb,
char buffer[sizeof("nnn.nnn.nnn.nnn")];
unsigned int dataoff, bufflen;
- dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
+ dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
/* Mangle owner and contact info. */
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
- if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
buffer, bufflen, POS_OWNER_IP4))
return 0;
- if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
buffer, bufflen, POS_CONNECTION_IP4))
return 0;
/* Mangle media port. */
bufflen = sprintf(buffer, "%u", port);
- if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
buffer, bufflen, POS_MEDIA))
return 0;
- return mangle_content_len(pskb, ctinfo, ct, dptr);
+ return mangle_content_len(skb, ctinfo, ct, dptr);
}
static void ip_nat_sdp_expect(struct nf_conn *ct,
@@ -241,7 +241,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
-static unsigned int ip_nat_sdp(struct sk_buff **pskb,
+static unsigned int ip_nat_sdp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
const char *dptr)
@@ -277,7 +277,7 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
if (port == 0)
return NF_DROP;
- if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
+ if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) {
nf_ct_unexpect_related(exp);
return NF_DROP;
}
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 6bfcd3a90f0..03709d6b4b0 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -1188,9 +1188,9 @@ static int snmp_parse_mangle(unsigned char *msg,
*/
static int snmp_translate(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
- struct sk_buff **pskb)
+ struct sk_buff *skb)
{
- struct iphdr *iph = ip_hdr(*pskb);
+ struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
u_int16_t udplen = ntohs(udph->len);
u_int16_t paylen = udplen - sizeof(struct udphdr);
@@ -1225,13 +1225,13 @@ static int snmp_translate(struct nf_conn *ct,
/* We don't actually set up expectations, just adjust internal IP
* addresses if this is being NATted */
-static int help(struct sk_buff **pskb, unsigned int protoff,
+static int help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
int dir = CTINFO2DIR(ctinfo);
unsigned int ret;
- struct iphdr *iph = ip_hdr(*pskb);
+ struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
/* SNMP replies and originating SNMP traps get mangled */
@@ -1250,7 +1250,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
* enough room for a UDP header. Just verify the UDP length field so we
* can mess around with the payload.
*/
- if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) {
+ if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) {
if (net_ratelimit())
printk(KERN_WARNING "SNMP: dropping malformed packet "
"src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
@@ -1258,11 +1258,11 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
return NF_DROP;
}
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return NF_DROP;
spin_lock_bh(&snmp_lock);
- ret = snmp_translate(ct, ctinfo, pskb);
+ ret = snmp_translate(ct, ctinfo, skb);
spin_unlock_bh(&snmp_lock);
return ret;
}
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 46cc99def16..7db76ea9af9 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -67,7 +67,7 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
static unsigned int
nf_nat_fn(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -80,9 +80,9 @@ nf_nat_fn(unsigned int hooknum,
/* We never see fragments: conntrack defrags on pre-routing
and local-out, and nf_nat_out protects post-routing. */
- NF_CT_ASSERT(!(ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)));
+ NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
/* Can't track? It's not due to stress, or conntrack would
have dropped it. Hence it's the user's responsibilty to
packet filter it out, or implement conntrack/NAT for that
@@ -91,10 +91,10 @@ nf_nat_fn(unsigned int hooknum,
/* Exception: ICMP redirect to new connection (not in
hash table yet). We must not let this through, in
case we're doing NAT to the same network. */
- if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
+ if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
struct icmphdr _hdr, *hp;
- hp = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
+ hp = skb_header_pointer(skb, ip_hdrlen(skb),
sizeof(_hdr), &_hdr);
if (hp != NULL &&
hp->type == ICMP_REDIRECT)
@@ -119,9 +119,9 @@ nf_nat_fn(unsigned int hooknum,
switch (ctinfo) {
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
- if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
+ if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
if (!nf_nat_icmp_reply_translation(ct, ctinfo,
- hooknum, pskb))
+ hooknum, skb))
return NF_DROP;
else
return NF_ACCEPT;
@@ -141,7 +141,7 @@ nf_nat_fn(unsigned int hooknum,
/* LOCAL_IN hook doesn't have a chain! */
ret = alloc_null_binding(ct, hooknum);
else
- ret = nf_nat_rule_find(pskb, hooknum, in, out,
+ ret = nf_nat_rule_find(skb, hooknum, in, out,
ct);
if (ret != NF_ACCEPT) {
@@ -159,31 +159,31 @@ nf_nat_fn(unsigned int hooknum,
ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
}
- return nf_nat_packet(ct, ctinfo, hooknum, pskb);
+ return nf_nat_packet(ct, ctinfo, hooknum, skb);
}
static unsigned int
nf_nat_in(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
unsigned int ret;
- __be32 daddr = ip_hdr(*pskb)->daddr;
+ __be32 daddr = ip_hdr(skb)->daddr;
- ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
+ ret = nf_nat_fn(hooknum, skb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
- daddr != ip_hdr(*pskb)->daddr) {
- dst_release((*pskb)->dst);
- (*pskb)->dst = NULL;
+ daddr != ip_hdr(skb)->daddr) {
+ dst_release(skb->dst);
+ skb->dst = NULL;
}
return ret;
}
static unsigned int
nf_nat_out(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -195,14 +195,14 @@ nf_nat_out(unsigned int hooknum,
unsigned int ret;
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr) ||
- ip_hdrlen(*pskb) < sizeof(struct iphdr))
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
- ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
+ ret = nf_nat_fn(hooknum, skb, in, out, okfn);
#ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN &&
- (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) {
+ (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (ct->tuplehash[dir].tuple.src.u3.ip !=
@@ -210,7 +210,7 @@ nf_nat_out(unsigned int hooknum,
|| ct->tuplehash[dir].tuple.src.u.all !=
ct->tuplehash[!dir].tuple.dst.u.all
)
- return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP;
+ return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP;
}
#endif
return ret;
@@ -218,7 +218,7 @@ nf_nat_out(unsigned int hooknum,
static unsigned int
nf_nat_local_fn(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -228,24 +228,24 @@ nf_nat_local_fn(unsigned int hooknum,
unsigned int ret;
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr) ||
- ip_hdrlen(*pskb) < sizeof(struct iphdr))
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
- ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
+ ret = nf_nat_fn(hooknum, skb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
- (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) {
+ (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (ct->tuplehash[dir].tuple.dst.u3.ip !=
ct->tuplehash[!dir].tuple.src.u3.ip) {
- if (ip_route_me_harder(pskb, RTN_UNSPEC))
+ if (ip_route_me_harder(skb, RTN_UNSPEC))
ret = NF_DROP;
}
#ifdef CONFIG_XFRM
else if (ct->tuplehash[dir].tuple.dst.u.all !=
ct->tuplehash[!dir].tuple.src.u.all)
- if (ip_xfrm_me_harder(pskb))
+ if (ip_xfrm_me_harder(skb))
ret = NF_DROP;
#endif
}
@@ -254,7 +254,7 @@ nf_nat_local_fn(unsigned int hooknum,
static unsigned int
nf_nat_adjust(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -262,10 +262,10 @@ nf_nat_adjust(unsigned int hooknum,
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
pr_debug("nf_nat_standalone: adjusting sequence number\n");
- if (!nf_nat_seq_adjust(pskb, ct, ctinfo))
+ if (!nf_nat_seq_adjust(skb, ct, ctinfo))
return NF_DROP;
}
return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
index 04dfeaefec0..0ecec701cb4 100644
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -20,7 +20,7 @@ MODULE_DESCRIPTION("TFTP NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_tftp");
-static unsigned int help(struct sk_buff **pskb,
+static unsigned int help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp)
{
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index e5b05b03910..fd16cb8f8ab 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -70,8 +70,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
- seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
- atomic_read(&ip_frag_mem));
+ seq_printf(seq, "FRAG: inuse %d memory %d\n",
+ ip_frag_nqueues(), ip_frag_mem());
return 0;
}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index eb286abcf5d..c98ef16effd 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -19,6 +19,7 @@
#include <net/route.h>
#include <net/tcp.h>
#include <net/cipso_ipv4.h>
+#include <net/inet_frag.h>
/* From af_inet.c */
extern int sysctl_ip_nonlocal_bind;
@@ -357,7 +358,7 @@ ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH,
.procname = "ipfrag_high_thresh",
- .data = &sysctl_ipfrag_high_thresh,
+ .data = &ip4_frags_ctl.high_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
@@ -365,7 +366,7 @@ ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_LOW_THRESH,
.procname = "ipfrag_low_thresh",
- .data = &sysctl_ipfrag_low_thresh,
+ .data = &ip4_frags_ctl.low_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
@@ -381,7 +382,7 @@ ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_TIME,
.procname = "ipfrag_time",
- .data = &sysctl_ipfrag_time,
+ .data = &ip4_frags_ctl.timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
@@ -732,7 +733,7 @@ ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL,
.procname = "ipfrag_secret_interval",
- .data = &sysctl_ipfrag_secret_interval,
+ .data = &ip4_frags_ctl.secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 0a42e934034..0f00966b178 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1995,8 +1995,7 @@ static void tcp_verify_retransmit_hint(struct tcp_sock *tp,
}
/* Mark head of queue up as lost. */
-static void tcp_mark_head_lost(struct sock *sk,
- int packets, u32 high_seq)
+static void tcp_mark_head_lost(struct sock *sk, int packets)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
@@ -2019,7 +2018,7 @@ static void tcp_mark_head_lost(struct sock *sk,
tp->lost_skb_hint = skb;
tp->lost_cnt_hint = cnt;
cnt += tcp_skb_pcount(skb);
- if (cnt > packets || after(TCP_SKB_CB(skb)->end_seq, high_seq))
+ if (cnt > packets || after(TCP_SKB_CB(skb)->end_seq, tp->high_seq))
break;
if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) {
TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
@@ -2040,9 +2039,9 @@ static void tcp_update_scoreboard(struct sock *sk)
int lost = tp->fackets_out - tp->reordering;
if (lost <= 0)
lost = 1;
- tcp_mark_head_lost(sk, lost, tp->high_seq);
+ tcp_mark_head_lost(sk, lost);
} else {
- tcp_mark_head_lost(sk, 1, tp->high_seq);
+ tcp_mark_head_lost(sk, 1);
}
/* New heuristics: it is possible only after we switched
@@ -2381,7 +2380,7 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
before(tp->snd_una, tp->high_seq) &&
icsk->icsk_ca_state != TCP_CA_Open &&
tp->fackets_out > tp->reordering) {
- tcp_mark_head_lost(sk, tp->fackets_out-tp->reordering, tp->high_seq);
+ tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering);
NET_INC_STATS_BH(LINUX_MIB_TCPLOSS);
}
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 434ef302ba8..a4edd666318 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -78,7 +78,7 @@ static int xfrm4_output_finish2(struct sk_buff *skb)
while (likely((err = xfrm4_output_one(skb)) == 0)) {
nf_reset(skb);
- err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL,
+ err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
skb->dst->dev, dst_output);
if (unlikely(err != 1))
break;
@@ -86,7 +86,7 @@ static int xfrm4_output_finish2(struct sk_buff *skb)
if (!skb->dst->xfrm)
return dst_output(skb);
- err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
+ err = nf_hook(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
skb->dst->dev, xfrm4_output_finish2);
if (unlikely(err != 1))
break;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index c82d4d49f71..1e89efd38a0 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(ipv6_find_tlv);
struct tlvtype_proc {
int type;
- int (*func)(struct sk_buff **skbp, int offset);
+ int (*func)(struct sk_buff *skb, int offset);
};
/*********************
@@ -111,10 +111,8 @@ struct tlvtype_proc {
/* An unknown option is detected, decide what to do */
-static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
+static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
{
- struct sk_buff *skb = *skbp;
-
switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
case 0: /* ignore */
return 1;
@@ -139,9 +137,8 @@ static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
/* Parse tlv encoded option header (hop-by-hop or destination) */
-static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
+static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
struct tlvtype_proc *curr;
const unsigned char *nh = skb_network_header(skb);
int off = skb_network_header_len(skb);
@@ -172,13 +169,13 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
/* type specific length/alignment
checks will be performed in the
func(). */
- if (curr->func(skbp, off) == 0)
+ if (curr->func(skb, off) == 0)
return 0;
break;
}
}
if (curr->type < 0) {
- if (ip6_tlvopt_unknown(skbp, off) == 0)
+ if (ip6_tlvopt_unknown(skb, off) == 0)
return 0;
}
break;
@@ -198,9 +195,8 @@ bad:
*****************************/
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
+static int ipv6_dest_hao(struct sk_buff *skb, int optoff)
{
- struct sk_buff *skb = *skbp;
struct ipv6_destopt_hao *hao;
struct inet6_skb_parm *opt = IP6CB(skb);
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
@@ -234,22 +230,13 @@ static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
goto discard;
if (skb_cloned(skb)) {
- struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
- struct inet6_skb_parm *opt2;
-
- if (skb2 == NULL)
+ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto discard;
- opt2 = IP6CB(skb2);
- memcpy(opt2, opt, sizeof(*opt2));
-
- kfree_skb(skb);
-
/* update all variable using below by copied skbuff */
- *skbp = skb = skb2;
- hao = (struct ipv6_destopt_hao *)(skb_network_header(skb2) +
+ hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
optoff);
- ipv6h = ipv6_hdr(skb2);
+ ipv6h = ipv6_hdr(skb);
}
if (skb->ip_summed == CHECKSUM_COMPLETE)
@@ -280,9 +267,8 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
{-1, NULL}
};
-static int ipv6_destopt_rcv(struct sk_buff **skbp)
+static int ipv6_destopt_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
__u16 dstbuf;
@@ -304,9 +290,8 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
#endif
dst = dst_clone(skb->dst);
- if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
+ if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
dst_release(dst);
- skb = *skbp;
skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
opt = IP6CB(skb);
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
@@ -337,10 +322,8 @@ void __init ipv6_destopt_init(void)
NONE header. No data in packet.
********************************/
-static int ipv6_nodata_rcv(struct sk_buff **skbp)
+static int ipv6_nodata_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
-
kfree_skb(skb);
return 0;
}
@@ -360,9 +343,8 @@ void __init ipv6_nodata_init(void)
Routing header.
********************************/
-static int ipv6_rthdr_rcv(struct sk_buff **skbp)
+static int ipv6_rthdr_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
struct in6_addr *addr = NULL;
struct in6_addr daddr;
@@ -464,18 +446,14 @@ looped_back:
Do not damage packets queued somewhere.
*/
if (skb_cloned(skb)) {
- struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
/* the copy is a forwarded packet */
- if (skb2 == NULL) {
+ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return -1;
}
- kfree_skb(skb);
- *skbp = skb = skb2;
- opt = IP6CB(skb2);
- hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb2);
+ hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
}
if (skb->ip_summed == CHECKSUM_COMPLETE)
@@ -578,9 +556,8 @@ static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
/* Router Alert as of RFC 2711 */
-static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
+static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
{
- struct sk_buff *skb = *skbp;
const unsigned char *nh = skb_network_header(skb);
if (nh[optoff + 1] == 2) {
@@ -595,9 +572,8 @@ static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
/* Jumbo payload */
-static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
+static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
{
- struct sk_buff *skb = *skbp;
const unsigned char *nh = skb_network_header(skb);
u32 pkt_len;
@@ -648,9 +624,8 @@ static struct tlvtype_proc tlvprochopopt_lst[] = {
{ -1, }
};
-int ipv6_parse_hopopts(struct sk_buff **skbp)
+int ipv6_parse_hopopts(struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
/*
@@ -667,8 +642,7 @@ int ipv6_parse_hopopts(struct sk_buff **skbp)
}
opt->hop = sizeof(struct ipv6hdr);
- if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
- skb = *skbp;
+ if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
opt = IP6CB(skb);
opt->nhoff = sizeof(struct ipv6hdr);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 47b8ce232e8..9bb031fa1c2 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(icmpv6msg_statistics);
static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
#define icmpv6_socket __get_cpu_var(__icmpv6_socket)
-static int icmpv6_rcv(struct sk_buff **pskb);
+static int icmpv6_rcv(struct sk_buff *skb);
static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
@@ -614,9 +614,8 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
* Handle icmp messages
*/
-static int icmpv6_rcv(struct sk_buff **pskb)
+static int icmpv6_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *pskb;
struct net_device *dev = skb->dev;
struct inet6_dev *idev = __in6_dev_get(dev);
struct in6_addr *saddr, *daddr;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 25b93170974..78de42ada84 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -146,7 +146,7 @@ void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
__ip6_dst_store(sk, dst, daddr, saddr);
#ifdef CONFIG_XFRM
- if (dst) {
+ {
struct rt6_info *rt = (struct rt6_info *)dst;
rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid);
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 9149fc23975..fac6f7f9dd7 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -125,7 +125,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
}
if (hdr->nexthdr == NEXTHDR_HOP) {
- if (ipv6_parse_hopopts(&skb) < 0) {
+ if (ipv6_parse_hopopts(skb) < 0) {
IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
rcu_read_unlock();
return 0;
@@ -149,7 +149,7 @@ out:
*/
-static inline int ip6_input_finish(struct sk_buff *skb)
+static int ip6_input_finish(struct sk_buff *skb)
{
struct inet6_protocol *ipprot;
struct sock *raw_sk;
@@ -199,7 +199,7 @@ resubmit:
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard;
- ret = ipprot->handler(&skb);
+ ret = ipprot->handler(skb);
if (ret > 0)
goto resubmit;
else if (ret == 0)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 011082ed921..13565dfb1b4 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -70,7 +70,7 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
spin_unlock_bh(&ip6_id_lock);
}
-static inline int ip6_output_finish(struct sk_buff *skb)
+static int ip6_output_finish(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 38b14961391..b1326c2bf8a 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -68,15 +68,15 @@ static void nf_ip6_saveroute(const struct sk_buff *skb, struct nf_info *info)
}
}
-static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info)
+static int nf_ip6_reroute(struct sk_buff *skb, const struct nf_info *info)
{
struct ip6_rt_info *rt_info = nf_info_reroute(info);
if (info->hook == NF_IP6_LOCAL_OUT) {
- struct ipv6hdr *iph = ipv6_hdr(*pskb);
+ struct ipv6hdr *iph = ipv6_hdr(skb);
if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
!ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
- return ip6_route_me_harder(*pskb);
+ return ip6_route_me_harder(skb);
}
return 0;
}
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 0473145ac53..6413a30d9f6 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -332,6 +332,7 @@ static int
ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
{
int diff;
+ int err;
struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
if (v->data_len < sizeof(*user_iph))
@@ -344,25 +345,18 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- struct sk_buff *newskb;
-
- newskb = skb_copy_expand(e->skb,
- skb_headroom(e->skb),
- diff,
- GFP_ATOMIC);
- if (newskb == NULL) {
+ err = pskb_expand_head(e->skb, 0,
+ diff - skb_tailroom(e->skb),
+ GFP_ATOMIC);
+ if (err) {
printk(KERN_WARNING "ip6_queue: OOM "
"in mangle, dropping packet\n");
- return -ENOMEM;
+ return err;
}
- if (e->skb->sk)
- skb_set_owner_w(newskb, e->skb->sk);
- kfree_skb(e->skb);
- e->skb = newskb;
}
skb_put(e->skb, diff);
}
- if (!skb_make_writable(&e->skb, v->data_len))
+ if (!skb_make_writable(e->skb, v->data_len))
return -ENOMEM;
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
e->skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index cd9df02bb85..acaba153793 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -205,7 +205,7 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
}
static unsigned int
-ip6t_error(struct sk_buff **pskb,
+ip6t_error(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -350,7 +350,7 @@ static void trace_packet(struct sk_buff *skb,
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
-ip6t_do_table(struct sk_buff **pskb,
+ip6t_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
@@ -389,17 +389,17 @@ ip6t_do_table(struct sk_buff **pskb,
do {
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
- if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+ if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
&protoff, &offset, &hotdrop)) {
struct ip6t_entry_target *t;
if (IP6T_MATCH_ITERATE(e, do_match,
- *pskb, in, out,
+ skb, in, out,
offset, protoff, &hotdrop) != 0)
goto no_match;
ADD_COUNTER(e->counters,
- ntohs(ipv6_hdr(*pskb)->payload_len)
+ ntohs(ipv6_hdr(skb)->payload_len)
+ IPV6_HDR_LEN,
1);
@@ -409,8 +409,8 @@ ip6t_do_table(struct sk_buff **pskb,
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* The packet is traced: log it */
- if (unlikely((*pskb)->nf_trace))
- trace_packet(*pskb, hook, in, out,
+ if (unlikely(skb->nf_trace))
+ trace_packet(skb, hook, in, out,
table->name, private, e);
#endif
/* Standard target? */
@@ -448,7 +448,7 @@ ip6t_do_table(struct sk_buff **pskb,
((struct ip6t_entry *)table_base)->comefrom
= 0xeeeeeeec;
#endif
- verdict = t->u.kernel.target->target(pskb,
+ verdict = t->u.kernel.target->target(skb,
in, out,
hook,
t->u.kernel.target,
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index ad4d94310b8..9afc836fd45 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -18,7 +18,7 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("IP6 tables Hop Limit modification module");
MODULE_LICENSE("GPL");
-static unsigned int ip6t_hl_target(struct sk_buff **pskb,
+static unsigned int ip6t_hl_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -29,10 +29,10 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
const struct ip6t_HL_info *info = targinfo;
int new_hl;
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return NF_DROP;
- ip6h = ipv6_hdr(*pskb);
+ ip6h = ipv6_hdr(skb);
switch (info->mode) {
case IP6T_HL_SET:
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 6ab99001dcc..7a48c342df4 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -431,7 +431,7 @@ ip6t_log_packet(unsigned int pf,
}
static unsigned int
-ip6t_log_target(struct sk_buff **pskb,
+ip6t_log_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -445,8 +445,7 @@ ip6t_log_target(struct sk_buff **pskb,
li.u.log.level = loginfo->level;
li.u.log.logflags = loginfo->logflags;
- ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li,
- loginfo->prefix);
+ ip6t_log_packet(PF_INET6, hooknum, skb, in, out, &li, loginfo->prefix);
return XT_CONTINUE;
}
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 3fd08d5567a..1a7d2917545 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -172,7 +172,7 @@ send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum)
icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL);
}
-static unsigned int reject6_target(struct sk_buff **pskb,
+static unsigned int reject6_target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -187,25 +187,25 @@ static unsigned int reject6_target(struct sk_buff **pskb,
must return an absolute verdict. --RR */
switch (reject->with) {
case IP6T_ICMP6_NO_ROUTE:
- send_unreach(*pskb, ICMPV6_NOROUTE, hooknum);
+ send_unreach(skb, ICMPV6_NOROUTE, hooknum);
break;
case IP6T_ICMP6_ADM_PROHIBITED:
- send_unreach(*pskb, ICMPV6_ADM_PROHIBITED, hooknum);
+ send_unreach(skb, ICMPV6_ADM_PROHIBITED, hooknum);
break;
case IP6T_ICMP6_NOT_NEIGHBOUR:
- send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR, hooknum);
+ send_unreach(skb, ICMPV6_NOT_NEIGHBOUR, hooknum);
break;
case IP6T_ICMP6_ADDR_UNREACH:
- send_unreach(*pskb, ICMPV6_ADDR_UNREACH, hooknum);
+ send_unreach(skb, ICMPV6_ADDR_UNREACH, hooknum);
break;
case IP6T_ICMP6_PORT_UNREACH:
- send_unreach(*pskb, ICMPV6_PORT_UNREACH, hooknum);
+ send_unreach(skb, ICMPV6_PORT_UNREACH, hooknum);
break;
case IP6T_ICMP6_ECHOREPLY:
/* Do nothing */
break;
case IP6T_TCP_RESET:
- send_reset(*pskb);
+ send_reset(skb);
break;
default:
if (net_ratelimit())
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 7e32e2aaf7f..1d26b202bf3 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -60,32 +60,32 @@ static struct xt_table packet_filter = {
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip6t_do_table(pskb, hook, in, out, &packet_filter);
+ return ip6t_do_table(skb, hook, in, out, &packet_filter);
}
static unsigned int
ip6t_local_out_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#if 0
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr)
- || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr)
+ || ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ip6t_hook: happy cracking.\n");
return NF_ACCEPT;
}
#endif
- return ip6t_do_table(pskb, hook, in, out, &packet_filter);
+ return ip6t_do_table(skb, hook, in, out, &packet_filter);
}
static struct nf_hook_ops ip6t_ops[] = {
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index f0a9efa67fb..a0b6381f1e8 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -68,17 +68,17 @@ static struct xt_table packet_mangler = {
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_route_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip6t_do_table(pskb, hook, in, out, &packet_mangler);
+ return ip6t_do_table(skb, hook, in, out, &packet_mangler);
}
static unsigned int
ip6t_local_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -91,8 +91,8 @@ ip6t_local_hook(unsigned int hook,
#if 0
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct iphdr)
- || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr)
+ || ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ip6t_hook: happy cracking.\n");
return NF_ACCEPT;
@@ -100,22 +100,22 @@ ip6t_local_hook(unsigned int hook,
#endif
/* save source/dest address, mark, hoplimit, flowlabel, priority, */
- memcpy(&saddr, &ipv6_hdr(*pskb)->saddr, sizeof(saddr));
- memcpy(&daddr, &ipv6_hdr(*pskb)->daddr, sizeof(daddr));
- mark = (*pskb)->mark;
- hop_limit = ipv6_hdr(*pskb)->hop_limit;
+ memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
+ memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
+ mark = skb->mark;
+ hop_limit = ipv6_hdr(skb)->hop_limit;
/* flowlabel and prio (includes version, which shouldn't change either */
- flowlabel = *((u_int32_t *)ipv6_hdr(*pskb));
+ flowlabel = *((u_int32_t *)ipv6_hdr(skb));
- ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler);
+ ret = ip6t_do_table(skb, hook, in, out, &packet_mangler);
if (ret != NF_DROP && ret != NF_STOLEN
- && (memcmp(&ipv6_hdr(*pskb)->saddr, &saddr, sizeof(saddr))
- || memcmp(&ipv6_hdr(*pskb)->daddr, &daddr, sizeof(daddr))
- || (*pskb)->mark != mark
- || ipv6_hdr(*pskb)->hop_limit != hop_limit))
- return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+ && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr))
+ || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr))
+ || skb->mark != mark
+ || ipv6_hdr(skb)->hop_limit != hop_limit))
+ return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
return ret;
}
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index ec290e4ebdd..8f7109f991e 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -46,12 +46,12 @@ static struct xt_table packet_raw = {
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_hook(unsigned int hook,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip6t_do_table(pskb, hook, in, out, &packet_raw);
+ return ip6t_do_table(skb, hook, in, out, &packet_raw);
}
static struct nf_hook_ops ip6t_ops[] = {
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 37a3db92695..0e40948f4fc 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -18,6 +18,7 @@
#include <linux/icmp.h>
#include <linux/sysctl.h>
#include <net/ipv6.h>
+#include <net/inet_frag.h>
#include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_conntrack.h>
@@ -145,7 +146,7 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
}
static unsigned int ipv6_confirm(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -155,12 +156,12 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
struct nf_conntrack_helper *helper;
enum ip_conntrack_info ctinfo;
unsigned int ret, protoff;
- unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
- unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;
+ unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
+ unsigned char pnum = ipv6_hdr(skb)->nexthdr;
/* This is where we call the helper: as the packet goes out. */
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
goto out;
@@ -172,23 +173,23 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
if (!helper)
goto out;
- protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
- (*pskb)->len - extoff);
- if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) {
+ protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum,
+ skb->len - extoff);
+ if (protoff > skb->len || pnum == NEXTHDR_FRAGMENT) {
pr_debug("proto header not found\n");
return NF_ACCEPT;
}
- ret = helper->help(pskb, protoff, ct, ctinfo);
+ ret = helper->help(skb, protoff, ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;
out:
/* We've seen it coming out the other side: confirm it */
- return nf_conntrack_confirm(pskb);
+ return nf_conntrack_confirm(skb);
}
static unsigned int ipv6_defrag(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
@@ -196,17 +197,17 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
struct sk_buff *reasm;
/* Previously seen (loopback)? */
- if ((*pskb)->nfct)
+ if (skb->nfct)
return NF_ACCEPT;
- reasm = nf_ct_frag6_gather(*pskb);
+ reasm = nf_ct_frag6_gather(skb);
/* queued */
if (reasm == NULL)
return NF_STOLEN;
/* error occured or not fragmented */
- if (reasm == *pskb)
+ if (reasm == skb)
return NF_ACCEPT;
nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in,
@@ -216,12 +217,12 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
}
static unsigned int ipv6_conntrack_in(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct sk_buff *reasm = (*pskb)->nfct_reasm;
+ struct sk_buff *reasm = skb->nfct_reasm;
/* This packet is fragmented and has reassembled packet. */
if (reasm) {
@@ -229,32 +230,32 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
if (!reasm->nfct) {
unsigned int ret;
- ret = nf_conntrack_in(PF_INET6, hooknum, &reasm);
+ ret = nf_conntrack_in(PF_INET6, hooknum, reasm);
if (ret != NF_ACCEPT)
return ret;
}
nf_conntrack_get(reasm->nfct);
- (*pskb)->nfct = reasm->nfct;
- (*pskb)->nfctinfo = reasm->nfctinfo;
+ skb->nfct = reasm->nfct;
+ skb->nfctinfo = reasm->nfctinfo;
return NF_ACCEPT;
}
- return nf_conntrack_in(PF_INET6, hooknum, pskb);
+ return nf_conntrack_in(PF_INET6, hooknum, skb);
}
static unsigned int ipv6_conntrack_local(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
- if ((*pskb)->len < sizeof(struct ipv6hdr)) {
+ if (skb->len < sizeof(struct ipv6hdr)) {
if (net_ratelimit())
printk("ipv6_conntrack_local: packet too short\n");
return NF_ACCEPT;
}
- return ipv6_conntrack_in(hooknum, pskb, in, out, okfn);
+ return ipv6_conntrack_in(hooknum, skb, in, out, okfn);
}
static struct nf_hook_ops ipv6_conntrack_ops[] = {
@@ -307,7 +308,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
{
.ctl_name = NET_NF_CONNTRACK_FRAG6_TIMEOUT,
.procname = "nf_conntrack_frag6_timeout",
- .data = &nf_ct_frag6_timeout,
+ .data = &nf_frags_ctl.timeout,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
@@ -315,7 +316,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
{
.ctl_name = NET_NF_CONNTRACK_FRAG6_LOW_THRESH,
.procname = "nf_conntrack_frag6_low_thresh",
- .data = &nf_ct_frag6_low_thresh,
+ .data = &nf_frags_ctl.low_thresh,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec,
@@ -323,7 +324,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
{
.ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
.procname = "nf_conntrack_frag6_high_thresh",
- .data = &nf_ct_frag6_high_thresh,
+ .data = &nf_frags_ctl.high_thresh,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec,
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 25442a8c1ba..726fafd4196 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -31,6 +31,7 @@
#include <net/sock.h>
#include <net/snmp.h>
+#include <net/inet_frag.h>
#include <net/ipv6.h>
#include <net/protocol.h>
@@ -48,10 +49,6 @@
#define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */
#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
-unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024;
-unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024;
-unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT;
-
struct nf_ct_frag6_skb_cb
{
struct inet6_skb_parm h;
@@ -63,51 +60,24 @@ struct nf_ct_frag6_skb_cb
struct nf_ct_frag6_queue
{
- struct hlist_node list;
- struct list_head lru_list; /* lru list member */
+ struct inet_frag_queue q;
__be32 id; /* fragment id */
struct in6_addr saddr;
struct in6_addr daddr;
- spinlock_t lock;
- atomic_t refcnt;
- struct timer_list timer; /* expire timer */
- struct sk_buff *fragments;
- int len;
- int meat;
- ktime_t stamp;
unsigned int csum;
- __u8 last_in; /* has first/last segment arrived? */
-#define COMPLETE 4
-#define FIRST_IN 2
-#define LAST_IN 1
__u16 nhoffset;
};
-/* Hash table. */
-
-#define FRAG6Q_HASHSZ 64
-
-static struct hlist_head nf_ct_frag6_hash[FRAG6Q_HASHSZ];
-static DEFINE_RWLOCK(nf_ct_frag6_lock);
-static u32 nf_ct_frag6_hash_rnd;
-static LIST_HEAD(nf_ct_frag6_lru_list);
-int nf_ct_frag6_nqueues = 0;
-
-static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
-{
- hlist_del(&fq->list);
- list_del(&fq->lru_list);
- nf_ct_frag6_nqueues--;
-}
+struct inet_frags_ctl nf_frags_ctl __read_mostly = {
+ .high_thresh = 256 * 1024,
+ .low_thresh = 192 * 1024,
+ .timeout = IPV6_FRAG_TIMEOUT,
+ .secret_interval = 10 * 60 * HZ,
+};
-static __inline__ void fq_unlink(struct nf_ct_frag6_queue *fq)
-{
- write_lock(&nf_ct_frag6_lock);
- __fq_unlink(fq);
- write_unlock(&nf_ct_frag6_lock);
-}
+static struct inet_frags nf_frags;
static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
struct in6_addr *daddr)
@@ -120,7 +90,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
- c += nf_ct_frag6_hash_rnd;
+ c += nf_frags.rnd;
__jhash_mix(a, b, c);
a += (__force u32)saddr->s6_addr32[3];
@@ -133,100 +103,54 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
c += (__force u32)id;
__jhash_mix(a, b, c);
- return c & (FRAG6Q_HASHSZ - 1);
+ return c & (INETFRAGS_HASHSZ - 1);
}
-static struct timer_list nf_ct_frag6_secret_timer;
-int nf_ct_frag6_secret_interval = 10 * 60 * HZ;
-
-static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
+static unsigned int nf_hashfn(struct inet_frag_queue *q)
{
- unsigned long now = jiffies;
- int i;
-
- write_lock(&nf_ct_frag6_lock);
- get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
- for (i = 0; i < FRAG6Q_HASHSZ; i++) {
- struct nf_ct_frag6_queue *q;
- struct hlist_node *p, *n;
-
- hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], list) {
- unsigned int hval = ip6qhashfn(q->id,
- &q->saddr,
- &q->daddr);
- if (hval != i) {
- hlist_del(&q->list);
- /* Relink to new hash chain. */
- hlist_add_head(&q->list,
- &nf_ct_frag6_hash[hval]);
- }
- }
- }
- write_unlock(&nf_ct_frag6_lock);
+ struct nf_ct_frag6_queue *nq;
- mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval);
+ nq = container_of(q, struct nf_ct_frag6_queue, q);
+ return ip6qhashfn(nq->id, &nq->saddr, &nq->daddr);
}
-atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0);
+static void nf_skb_free(struct sk_buff *skb)
+{
+ if (NFCT_FRAG6_CB(skb)->orig)
+ kfree_skb(NFCT_FRAG6_CB(skb)->orig);
+}
/* Memory Tracking Functions. */
static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
{
if (work)
*work -= skb->truesize;
- atomic_sub(skb->truesize, &nf_ct_frag6_mem);
- if (NFCT_FRAG6_CB(skb)->orig)
- kfree_skb(NFCT_FRAG6_CB(skb)->orig);
-
+ atomic_sub(skb->truesize, &nf_frags.mem);
+ nf_skb_free(skb);
kfree_skb(skb);
}
-static inline void frag_free_queue(struct nf_ct_frag6_queue *fq,
- unsigned int *work)
+static void nf_frag_free(struct inet_frag_queue *q)
{
- if (work)
- *work -= sizeof(struct nf_ct_frag6_queue);
- atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
- kfree(fq);
+ kfree(container_of(q, struct nf_ct_frag6_queue, q));
}
static inline struct nf_ct_frag6_queue *frag_alloc_queue(void)
{
- struct nf_ct_frag6_queue *fq = kmalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC);
+ struct nf_ct_frag6_queue *fq;
- if (!fq)
+ fq = kzalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC);
+ if (fq == NULL)
return NULL;
- atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+ atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_frags.mem);
return fq;
}
/* Destruction primitives. */
-/* Complete destruction of fq. */
-static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq,
- unsigned int *work)
+static __inline__ void fq_put(struct nf_ct_frag6_queue *fq)
{
- struct sk_buff *fp;
-
- BUG_TRAP(fq->last_in&COMPLETE);
- BUG_TRAP(del_timer(&fq->timer) == 0);
-
- /* Release all fragment data. */
- fp = fq->fragments;
- while (fp) {
- struct sk_buff *xp = fp->next;
-
- frag_kfree_skb(fp, work);
- fp = xp;
- }
-
- frag_free_queue(fq, work);
-}
-
-static __inline__ void fq_put(struct nf_ct_frag6_queue *fq, unsigned int *work)
-{
- if (atomic_dec_and_test(&fq->refcnt))
- nf_ct_frag6_destroy(fq, work);
+ inet_frag_put(&fq->q, &nf_frags);
}
/* Kill fq entry. It is not destroyed immediately,
@@ -234,62 +158,28 @@ static __inline__ void fq_put(struct nf_ct_frag6_queue *fq, unsigned int *work)
*/
static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
{
- if (del_timer(&fq->timer))
- atomic_dec(&fq->refcnt);
-
- if (!(fq->last_in & COMPLETE)) {
- fq_unlink(fq);
- atomic_dec(&fq->refcnt);
- fq->last_in |= COMPLETE;
- }
+ inet_frag_kill(&fq->q, &nf_frags);
}
static void nf_ct_frag6_evictor(void)
{
- struct nf_ct_frag6_queue *fq;
- struct list_head *tmp;
- unsigned int work;
-
- work = atomic_read(&nf_ct_frag6_mem);
- if (work <= nf_ct_frag6_low_thresh)
- return;
-
- work -= nf_ct_frag6_low_thresh;
- while (work > 0) {
- read_lock(&nf_ct_frag6_lock);
- if (list_empty(&nf_ct_frag6_lru_list)) {
- read_unlock(&nf_ct_frag6_lock);
- return;
- }
- tmp = nf_ct_frag6_lru_list.next;
- BUG_ON(tmp == NULL);
- fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list);
- atomic_inc(&fq->refcnt);
- read_unlock(&nf_ct_frag6_lock);
-
- spin_lock(&fq->lock);
- if (!(fq->last_in&COMPLETE))
- fq_kill(fq);
- spin_unlock(&fq->lock);
-
- fq_put(fq, &work);
- }
+ inet_frag_evictor(&nf_frags);
}
static void nf_ct_frag6_expire(unsigned long data)
{
struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data;
- spin_lock(&fq->lock);
+ spin_lock(&fq->q.lock);
- if (fq->last_in & COMPLETE)
+ if (fq->q.last_in & COMPLETE)
goto out;
fq_kill(fq);
out:
- spin_unlock(&fq->lock);
- fq_put(fq, NULL);
+ spin_unlock(&fq->q.lock);
+ fq_put(fq);
}
/* Creation primitives. */
@@ -302,31 +192,31 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
struct hlist_node *n;
#endif
- write_lock(&nf_ct_frag6_lock);
+ write_lock(&nf_frags.lock);
#ifdef CONFIG_SMP
- hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
+ hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) {
if (fq->id == fq_in->id &&
ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
- atomic_inc(&fq->refcnt);
- write_unlock(&nf_ct_frag6_lock);
- fq_in->last_in |= COMPLETE;
- fq_put(fq_in, NULL);
+ atomic_inc(&fq->q.refcnt);
+ write_unlock(&nf_frags.lock);
+ fq_in->q.last_in |= COMPLETE;
+ fq_put(fq_in);
return fq;
}
}
#endif
fq = fq_in;
- if (!mod_timer(&fq->timer, jiffies + nf_ct_frag6_timeout))
- atomic_inc(&fq->refcnt);
+ if (!mod_timer(&fq->q.timer, jiffies + nf_frags_ctl.timeout))
+ atomic_inc(&fq->q.refcnt);
- atomic_inc(&fq->refcnt);
- hlist_add_head(&fq->list, &nf_ct_frag6_hash[hash]);
- INIT_LIST_HEAD(&fq->lru_list);
- list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
- nf_ct_frag6_nqueues++;
- write_unlock(&nf_ct_frag6_lock);
+ atomic_inc(&fq->q.refcnt);
+ hlist_add_head(&fq->q.list, &nf_frags.hash[hash]);
+ INIT_LIST_HEAD(&fq->q.lru_list);
+ list_add_tail(&fq->q.lru_list, &nf_frags.lru_list);
+ nf_frags.nqueues++;
+ write_unlock(&nf_frags.lock);
return fq;
}
@@ -341,15 +231,13 @@ nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src, str
goto oom;
}
- memset(fq, 0, sizeof(struct nf_ct_frag6_queue));
-
fq->id = id;
ipv6_addr_copy(&fq->saddr, src);
ipv6_addr_copy(&fq->daddr, dst);
- setup_timer(&fq->timer, nf_ct_frag6_expire, (unsigned long)fq);
- spin_lock_init(&fq->lock);
- atomic_set(&fq->refcnt, 1);
+ setup_timer(&fq->q.timer, nf_ct_frag6_expire, (unsigned long)fq);
+ spin_lock_init(&fq->q.lock);
+ atomic_set(&fq->q.refcnt, 1);
return nf_ct_frag6_intern(hash, fq);
@@ -364,17 +252,17 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
struct hlist_node *n;
unsigned int hash = ip6qhashfn(id, src, dst);
- read_lock(&nf_ct_frag6_lock);
- hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
+ read_lock(&nf_frags.lock);
+ hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) {
if (fq->id == id &&
ipv6_addr_equal(src, &fq->saddr) &&
ipv6_addr_equal(dst, &fq->daddr)) {
- atomic_inc(&fq->refcnt);
- read_unlock(&nf_ct_frag6_lock);
+ atomic_inc(&fq->q.refcnt);
+ read_unlock(&nf_frags.lock);
return fq;
}
}
- read_unlock(&nf_ct_frag6_lock);
+ read_unlock(&nf_frags.lock);
return nf_ct_frag6_create(hash, id, src, dst);
}
@@ -386,7 +274,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
struct sk_buff *prev, *next;
int offset, end;
- if (fq->last_in & COMPLETE) {
+ if (fq->q.last_in & COMPLETE) {
pr_debug("Allready completed\n");
goto err;
}
@@ -412,13 +300,13 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* If we already have some bits beyond end
* or have different end, the segment is corrupted.
*/
- if (end < fq->len ||
- ((fq->last_in & LAST_IN) && end != fq->len)) {
+ if (end < fq->q.len ||
+ ((fq->q.last_in & LAST_IN) && end != fq->q.len)) {
pr_debug("already received last fragment\n");
goto err;
}
- fq->last_in |= LAST_IN;
- fq->len = end;
+ fq->q.last_in |= LAST_IN;
+ fq->q.len = end;
} else {
/* Check if the fragment is rounded to 8 bytes.
* Required by the RFC.
@@ -430,13 +318,13 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
pr_debug("end of fragment not rounded to 8 bytes.\n");
return -1;
}
- if (end > fq->len) {
+ if (end > fq->q.len) {
/* Some bits beyond end -> corruption. */
- if (fq->last_in & LAST_IN) {
+ if (fq->q.last_in & LAST_IN) {
pr_debug("last packet already reached.\n");
goto err;
}
- fq->len = end;
+ fq->q.len = end;
}
}
@@ -458,7 +346,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
* this fragment, right?
*/
prev = NULL;
- for (next = fq->fragments; next != NULL; next = next->next) {
+ for (next = fq->q.fragments; next != NULL; next = next->next) {
if (NFCT_FRAG6_CB(next)->offset >= offset)
break; /* bingo! */
prev = next;
@@ -503,7 +391,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* next fragment */
NFCT_FRAG6_CB(next)->offset += i;
- fq->meat -= i;
+ fq->q.meat -= i;
if (next->ip_summed != CHECKSUM_UNNECESSARY)
next->ip_summed = CHECKSUM_NONE;
break;
@@ -518,9 +406,9 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
if (prev)
prev->next = next;
else
- fq->fragments = next;
+ fq->q.fragments = next;
- fq->meat -= free_it->len;
+ fq->q.meat -= free_it->len;
frag_kfree_skb(free_it, NULL);
}
}
@@ -532,23 +420,23 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
if (prev)
prev->next = skb;
else
- fq->fragments = skb;
+ fq->q.fragments = skb;
skb->dev = NULL;
- fq->stamp = skb->tstamp;
- fq->meat += skb->len;
- atomic_add(skb->truesize, &nf_ct_frag6_mem);
+ fq->q.stamp = skb->tstamp;
+ fq->q.meat += skb->len;
+ atomic_add(skb->truesize, &nf_frags.mem);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
*/
if (offset == 0) {
fq->nhoffset = nhoff;
- fq->last_in |= FIRST_IN;
+ fq->q.last_in |= FIRST_IN;
}
- write_lock(&nf_ct_frag6_lock);
- list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
- write_unlock(&nf_ct_frag6_lock);
+ write_lock(&nf_frags.lock);
+ list_move_tail(&fq->q.lru_list, &nf_frags.lru_list);
+ write_unlock(&nf_frags.lock);
return 0;
err:
@@ -567,7 +455,7 @@ err:
static struct sk_buff *
nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
{
- struct sk_buff *fp, *op, *head = fq->fragments;
+ struct sk_buff *fp, *op, *head = fq->q.fragments;
int payload_len;
fq_kill(fq);
@@ -577,7 +465,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
/* Unfragmented part is taken from the first segment. */
payload_len = ((head->data - skb_network_header(head)) -
- sizeof(struct ipv6hdr) + fq->len -
+ sizeof(struct ipv6hdr) + fq->q.len -
sizeof(struct frag_hdr));
if (payload_len > IPV6_MAXPLEN) {
pr_debug("payload len is too large.\n");
@@ -614,7 +502,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
clone->ip_summed = head->ip_summed;
NFCT_FRAG6_CB(clone)->orig = NULL;
- atomic_add(clone->truesize, &nf_ct_frag6_mem);
+ atomic_add(clone->truesize, &nf_frags.mem);
}
/* We have to remove fragment header from datagram and to relocate
@@ -628,7 +516,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &nf_ct_frag6_mem);
+ atomic_sub(head->truesize, &nf_frags.mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -638,12 +526,12 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &nf_ct_frag6_mem);
+ atomic_sub(fp->truesize, &nf_frags.mem);
}
head->next = NULL;
head->dev = dev;
- head->tstamp = fq->stamp;
+ head->tstamp = fq->q.stamp;
ipv6_hdr(head)->payload_len = htons(payload_len);
/* Yes, and fold redundant checksum back. 8) */
@@ -652,7 +540,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
skb_network_header_len(head),
head->csum);
- fq->fragments = NULL;
+ fq->q.fragments = NULL;
/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
fp = skb_shinfo(head)->frag_list;
@@ -788,7 +676,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
goto ret_orig;
}
- if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh)
+ if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh)
nf_ct_frag6_evictor();
fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
@@ -797,23 +685,23 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
goto ret_orig;
}
- spin_lock(&fq->lock);
+ spin_lock(&fq->q.lock);
if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
- spin_unlock(&fq->lock);
+ spin_unlock(&fq->q.lock);
pr_debug("Can't insert skb to queue\n");
- fq_put(fq, NULL);
+ fq_put(fq);
goto ret_orig;
}
- if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {
+ if (fq->q.last_in == (FIRST_IN|LAST_IN) && fq->q.meat == fq->q.len) {
ret_skb = nf_ct_frag6_reasm(fq, dev);
if (ret_skb == NULL)
pr_debug("Can't reassemble fragmented packets\n");
}
- spin_unlock(&fq->lock);
+ spin_unlock(&fq->q.lock);
- fq_put(fq, NULL);
+ fq_put(fq);
return ret_skb;
ret_orig:
@@ -859,20 +747,20 @@ int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
int nf_ct_frag6_init(void)
{
- nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
- (jiffies ^ (jiffies >> 6)));
-
- setup_timer(&nf_ct_frag6_secret_timer, nf_ct_frag6_secret_rebuild, 0);
- nf_ct_frag6_secret_timer.expires = jiffies
- + nf_ct_frag6_secret_interval;
- add_timer(&nf_ct_frag6_secret_timer);
+ nf_frags.ctl = &nf_frags_ctl;
+ nf_frags.hashfn = nf_hashfn;
+ nf_frags.destructor = nf_frag_free;
+ nf_frags.skb_free = nf_skb_free;
+ nf_frags.qsize = sizeof(struct nf_ct_frag6_queue);
+ inet_frags_init(&nf_frags);
return 0;
}
void nf_ct_frag6_cleanup(void)
{
- del_timer(&nf_ct_frag6_secret_timer);
- nf_ct_frag6_low_thresh = 0;
+ inet_frags_fini(&nf_frags);
+
+ nf_frags_ctl.low_thresh = 0;
nf_ct_frag6_evictor();
}
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index db945018579..be526ad9254 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -54,7 +54,7 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "RAW6: inuse %d\n",
fold_prot_inuse(&rawv6_prot));
seq_printf(seq, "FRAG6: inuse %d memory %d\n",
- ip6_frag_nqueues, atomic_read(&ip6_frag_mem));
+ ip6_frag_nqueues(), ip6_frag_mem());
return 0;
}
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 31601c99354..6ad19cfc202 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -42,6 +42,7 @@
#include <linux/icmpv6.h>
#include <linux/random.h>
#include <linux/jhash.h>
+#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -53,11 +54,7 @@
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
-
-int sysctl_ip6frag_high_thresh __read_mostly = 256*1024;
-int sysctl_ip6frag_low_thresh __read_mostly = 192*1024;
-
-int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT;
+#include <net/inet_frag.h>
struct ip6frag_skb_cb
{
@@ -74,53 +71,39 @@ struct ip6frag_skb_cb
struct frag_queue
{
- struct hlist_node list;
- struct list_head lru_list; /* lru list member */
+ struct inet_frag_queue q;
__be32 id; /* fragment id */
struct in6_addr saddr;
struct in6_addr daddr;
- spinlock_t lock;
- atomic_t refcnt;
- struct timer_list timer; /* expire timer */
- struct sk_buff *fragments;
- int len;
- int meat;
int iif;
- ktime_t stamp;
unsigned int csum;
- __u8 last_in; /* has first/last segment arrived? */
-#define COMPLETE 4
-#define FIRST_IN 2
-#define LAST_IN 1
__u16 nhoffset;
};
-/* Hash table. */
-
-#define IP6Q_HASHSZ 64
+struct inet_frags_ctl ip6_frags_ctl __read_mostly = {
+ .high_thresh = 256 * 1024,
+ .low_thresh = 192 * 1024,
+ .timeout = IPV6_FRAG_TIMEOUT,
+ .secret_interval = 10 * 60 * HZ,
+};
-static struct hlist_head ip6_frag_hash[IP6Q_HASHSZ];
-static DEFINE_RWLOCK(ip6_frag_lock);
-static u32 ip6_frag_hash_rnd;
-static LIST_HEAD(ip6_frag_lru_list);
-int ip6_frag_nqueues = 0;
+static struct inet_frags ip6_frags;
-static __inline__ void __fq_unlink(struct frag_queue *fq)
+int ip6_frag_nqueues(void)
{
- hlist_del(&fq->list);
- list_del(&fq->lru_list);
- ip6_frag_nqueues--;
+ return ip6_frags.nqueues;
}
-static __inline__ void fq_unlink(struct frag_queue *fq)
+int ip6_frag_mem(void)
{
- write_lock(&ip6_frag_lock);
- __fq_unlink(fq);
- write_unlock(&ip6_frag_lock);
+ return atomic_read(&ip6_frags.mem);
}
+static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
+ struct net_device *dev);
+
/*
* callers should be careful not to use the hash value outside the ipfrag_lock
* as doing so could race with ipfrag_hash_rnd being recalculated.
@@ -136,7 +119,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
- c += ip6_frag_hash_rnd;
+ c += ip6_frags.rnd;
__jhash_mix(a, b, c);
a += (__force u32)saddr->s6_addr32[3];
@@ -149,60 +132,29 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
c += (__force u32)id;
__jhash_mix(a, b, c);
- return c & (IP6Q_HASHSZ - 1);
+ return c & (INETFRAGS_HASHSZ - 1);
}
-static struct timer_list ip6_frag_secret_timer;
-int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ;
-
-static void ip6_frag_secret_rebuild(unsigned long dummy)
+static unsigned int ip6_hashfn(struct inet_frag_queue *q)
{
- unsigned long now = jiffies;
- int i;
-
- write_lock(&ip6_frag_lock);
- get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32));
- for (i = 0; i < IP6Q_HASHSZ; i++) {
- struct frag_queue *q;
- struct hlist_node *p, *n;
-
- hlist_for_each_entry_safe(q, p, n, &ip6_frag_hash[i], list) {
- unsigned int hval = ip6qhashfn(q->id,
- &q->saddr,
- &q->daddr);
-
- if (hval != i) {
- hlist_del(&q->list);
-
- /* Relink to new hash chain. */
- hlist_add_head(&q->list,
- &ip6_frag_hash[hval]);
-
- }
- }
- }
- write_unlock(&ip6_frag_lock);
+ struct frag_queue *fq;
- mod_timer(&ip6_frag_secret_timer, now + sysctl_ip6frag_secret_interval);
+ fq = container_of(q, struct frag_queue, q);
+ return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr);
}
-atomic_t ip6_frag_mem = ATOMIC_INIT(0);
-
/* Memory Tracking Functions. */
static inline void frag_kfree_skb(struct sk_buff *skb, int *work)
{
if (work)
*work -= skb->truesize;
- atomic_sub(skb->truesize, &ip6_frag_mem);
+ atomic_sub(skb->truesize, &ip6_frags.mem);
kfree_skb(skb);
}
-static inline void frag_free_queue(struct frag_queue *fq, int *work)
+static void ip6_frag_free(struct inet_frag_queue *fq)
{
- if (work)
- *work -= sizeof(struct frag_queue);
- atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
- kfree(fq);
+ kfree(container_of(fq, struct frag_queue, q));
}
static inline struct frag_queue *frag_alloc_queue(void)
@@ -211,36 +163,15 @@ static inline struct frag_queue *frag_alloc_queue(void)
if(!fq)
return NULL;
- atomic_add(sizeof(struct frag_queue), &ip6_frag_mem);
+ atomic_add(sizeof(struct frag_queue), &ip6_frags.mem);
return fq;
}
/* Destruction primitives. */
-/* Complete destruction of fq. */
-static void ip6_frag_destroy(struct frag_queue *fq, int *work)
-{
- struct sk_buff *fp;
-
- BUG_TRAP(fq->last_in&COMPLETE);
- BUG_TRAP(del_timer(&fq->timer) == 0);
-
- /* Release all fragment data. */
- fp = fq->fragments;
- while (fp) {
- struct sk_buff *xp = fp->next;
-
- frag_kfree_skb(fp, work);
- fp = xp;
- }
-
- frag_free_queue(fq, work);
-}
-
-static __inline__ void fq_put(struct frag_queue *fq, int *work)
+static __inline__ void fq_put(struct frag_queue *fq)
{
- if (atomic_dec_and_test(&fq->refcnt))
- ip6_frag_destroy(fq, work);
+ inet_frag_put(&fq->q, &ip6_frags);
}
/* Kill fq entry. It is not destroyed immediately,
@@ -248,45 +179,16 @@ static __inline__ void fq_put(struct frag_queue *fq, int *work)
*/
static __inline__ void fq_kill(struct frag_queue *fq)
{
- if (del_timer(&fq->timer))
- atomic_dec(&fq->refcnt);
-
- if (!(fq->last_in & COMPLETE)) {
- fq_unlink(fq);
- atomic_dec(&fq->refcnt);
- fq->last_in |= COMPLETE;
- }
+ inet_frag_kill(&fq->q, &ip6_frags);
}
static void ip6_evictor(struct inet6_dev *idev)
{
- struct frag_queue *fq;
- struct list_head *tmp;
- int work;
-
- work = atomic_read(&ip6_frag_mem) - sysctl_ip6frag_low_thresh;
- if (work <= 0)
- return;
-
- while(work > 0) {
- read_lock(&ip6_frag_lock);
- if (list_empty(&ip6_frag_lru_list)) {
- read_unlock(&ip6_frag_lock);
- return;
- }
- tmp = ip6_frag_lru_list.next;
- fq = list_entry(tmp, struct frag_queue, lru_list);
- atomic_inc(&fq->refcnt);
- read_unlock(&ip6_frag_lock);
-
- spin_lock(&fq->lock);
- if (!(fq->last_in&COMPLETE))
- fq_kill(fq);
- spin_unlock(&fq->lock);
-
- fq_put(fq, &work);
- IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
- }
+ int evicted;
+
+ evicted = inet_frag_evictor(&ip6_frags);
+ if (evicted)
+ IP6_ADD_STATS_BH(idev, IPSTATS_MIB_REASMFAILS, evicted);
}
static void ip6_frag_expire(unsigned long data)
@@ -294,9 +196,9 @@ static void ip6_frag_expire(unsigned long data)
struct frag_queue *fq = (struct frag_queue *) data;
struct net_device *dev = NULL;
- spin_lock(&fq->lock);
+ spin_lock(&fq->q.lock);
- if (fq->last_in & COMPLETE)
+ if (fq->q.last_in & COMPLETE)
goto out;
fq_kill(fq);
@@ -311,7 +213,7 @@ static void ip6_frag_expire(unsigned long data)
rcu_read_unlock();
/* Don't send error if the first segment did not arrive. */
- if (!(fq->last_in&FIRST_IN) || !fq->fragments)
+ if (!(fq->q.last_in&FIRST_IN) || !fq->q.fragments)
goto out;
/*
@@ -319,13 +221,13 @@ static void ip6_frag_expire(unsigned long data)
segment was received. And do not use fq->dev
pointer directly, device might already disappeared.
*/
- fq->fragments->dev = dev;
- icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
+ fq->q.fragments->dev = dev;
+ icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
out:
if (dev)
dev_put(dev);
- spin_unlock(&fq->lock);
- fq_put(fq, NULL);
+ spin_unlock(&fq->q.lock);
+ fq_put(fq);
}
/* Creation primitives. */
@@ -339,32 +241,32 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
struct hlist_node *n;
#endif
- write_lock(&ip6_frag_lock);
+ write_lock(&ip6_frags.lock);
hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr);
#ifdef CONFIG_SMP
- hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
+ hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) {
if (fq->id == fq_in->id &&
ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
- atomic_inc(&fq->refcnt);
- write_unlock(&ip6_frag_lock);
- fq_in->last_in |= COMPLETE;
- fq_put(fq_in, NULL);
+ atomic_inc(&fq->q.refcnt);
+ write_unlock(&ip6_frags.lock);
+ fq_in->q.last_in |= COMPLETE;
+ fq_put(fq_in);
return fq;
}
}
#endif
fq = fq_in;
- if (!mod_timer(&fq->timer, jiffies + sysctl_ip6frag_time))
- atomic_inc(&fq->refcnt);
+ if (!mod_timer(&fq->q.timer, jiffies + ip6_frags_ctl.timeout))
+ atomic_inc(&fq->q.refcnt);
- atomic_inc(&fq->refcnt);
- hlist_add_head(&fq->list, &ip6_frag_hash[hash]);
- INIT_LIST_HEAD(&fq->lru_list);
- list_add_tail(&fq->lru_list, &ip6_frag_lru_list);
- ip6_frag_nqueues++;
- write_unlock(&ip6_frag_lock);
+ atomic_inc(&fq->q.refcnt);
+ hlist_add_head(&fq->q.list, &ip6_frags.hash[hash]);
+ INIT_LIST_HEAD(&fq->q.lru_list);
+ list_add_tail(&fq->q.lru_list, &ip6_frags.lru_list);
+ ip6_frags.nqueues++;
+ write_unlock(&ip6_frags.lock);
return fq;
}
@@ -382,11 +284,11 @@ ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst,
ipv6_addr_copy(&fq->saddr, src);
ipv6_addr_copy(&fq->daddr, dst);
- init_timer(&fq->timer);
- fq->timer.function = ip6_frag_expire;
- fq->timer.data = (long) fq;
- spin_lock_init(&fq->lock);
- atomic_set(&fq->refcnt, 1);
+ init_timer(&fq->q.timer);
+ fq->q.timer.function = ip6_frag_expire;
+ fq->q.timer.data = (long) fq;
+ spin_lock_init(&fq->q.lock);
+ atomic_set(&fq->q.refcnt, 1);
return ip6_frag_intern(fq);
@@ -403,30 +305,31 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst,
struct hlist_node *n;
unsigned int hash;
- read_lock(&ip6_frag_lock);
+ read_lock(&ip6_frags.lock);
hash = ip6qhashfn(id, src, dst);
- hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
+ hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) {
if (fq->id == id &&
ipv6_addr_equal(src, &fq->saddr) &&
ipv6_addr_equal(dst, &fq->daddr)) {
- atomic_inc(&fq->refcnt);
- read_unlock(&ip6_frag_lock);
+ atomic_inc(&fq->q.refcnt);
+ read_unlock(&ip6_frags.lock);
return fq;
}
}
- read_unlock(&ip6_frag_lock);
+ read_unlock(&ip6_frags.lock);
return ip6_frag_create(id, src, dst, idev);
}
-static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
+static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
struct frag_hdr *fhdr, int nhoff)
{
struct sk_buff *prev, *next;
+ struct net_device *dev;
int offset, end;
- if (fq->last_in & COMPLETE)
+ if (fq->q.last_in & COMPLETE)
goto err;
offset = ntohs(fhdr->frag_off) & ~0x7;
@@ -439,7 +342,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
((u8 *)&fhdr->frag_off -
skb_network_header(skb)));
- return;
+ return -1;
}
if (skb->ip_summed == CHECKSUM_COMPLETE) {
@@ -454,11 +357,11 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
/* If we already have some bits beyond end
* or have different end, the segment is corrupted.
*/
- if (end < fq->len ||
- ((fq->last_in & LAST_IN) && end != fq->len))
+ if (end < fq->q.len ||
+ ((fq->q.last_in & LAST_IN) && end != fq->q.len))
goto err;
- fq->last_in |= LAST_IN;
- fq->len = end;
+ fq->q.last_in |= LAST_IN;
+ fq->q.len = end;
} else {
/* Check if the fragment is rounded to 8 bytes.
* Required by the RFC.
@@ -471,13 +374,13 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
offsetof(struct ipv6hdr, payload_len));
- return;
+ return -1;
}
- if (end > fq->len) {
+ if (end > fq->q.len) {
/* Some bits beyond end -> corruption. */
- if (fq->last_in & LAST_IN)
+ if (fq->q.last_in & LAST_IN)
goto err;
- fq->len = end;
+ fq->q.len = end;
}
}
@@ -496,7 +399,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
* this fragment, right?
*/
prev = NULL;
- for(next = fq->fragments; next != NULL; next = next->next) {
+ for(next = fq->q.fragments; next != NULL; next = next->next) {
if (FRAG6_CB(next)->offset >= offset)
break; /* bingo! */
prev = next;
@@ -533,7 +436,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
if (!pskb_pull(next, i))
goto err;
FRAG6_CB(next)->offset += i; /* next fragment */
- fq->meat -= i;
+ fq->q.meat -= i;
if (next->ip_summed != CHECKSUM_UNNECESSARY)
next->ip_summed = CHECKSUM_NONE;
break;
@@ -548,9 +451,9 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
if (prev)
prev->next = next;
else
- fq->fragments = next;
+ fq->q.fragments = next;
- fq->meat -= free_it->len;
+ fq->q.meat -= free_it->len;
frag_kfree_skb(free_it, NULL);
}
}
@@ -562,30 +465,37 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
if (prev)
prev->next = skb;
else
- fq->fragments = skb;
+ fq->q.fragments = skb;
- if (skb->dev)
- fq->iif = skb->dev->ifindex;
- skb->dev = NULL;
- fq->stamp = skb->tstamp;
- fq->meat += skb->len;
- atomic_add(skb->truesize, &ip6_frag_mem);
+ dev = skb->dev;
+ if (dev) {
+ fq->iif = dev->ifindex;
+ skb->dev = NULL;
+ }
+ fq->q.stamp = skb->tstamp;
+ fq->q.meat += skb->len;
+ atomic_add(skb->truesize, &ip6_frags.mem);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
*/
if (offset == 0) {
fq->nhoffset = nhoff;
- fq->last_in |= FIRST_IN;
+ fq->q.last_in |= FIRST_IN;
}
- write_lock(&ip6_frag_lock);
- list_move_tail(&fq->lru_list, &ip6_frag_lru_list);
- write_unlock(&ip6_frag_lock);
- return;
+
+ if (fq->q.last_in == (FIRST_IN | LAST_IN) && fq->q.meat == fq->q.len)
+ return ip6_frag_reasm(fq, prev, dev);
+
+ write_lock(&ip6_frags.lock);
+ list_move_tail(&fq->q.lru_list, &ip6_frags.lru_list);
+ write_unlock(&ip6_frags.lock);
+ return -1;
err:
IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
+ return -1;
}
/*
@@ -597,21 +507,39 @@ err:
* queue is eligible for reassembly i.e. it is not COMPLETE,
* the last and the first frames arrived and all the bits are here.
*/
-static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
+static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
struct net_device *dev)
{
- struct sk_buff *fp, *head = fq->fragments;
+ struct sk_buff *fp, *head = fq->q.fragments;
int payload_len;
unsigned int nhoff;
fq_kill(fq);
+ /* Make the one we just received the head. */
+ if (prev) {
+ head = prev->next;
+ fp = skb_clone(head, GFP_ATOMIC);
+
+ if (!fp)
+ goto out_oom;
+
+ fp->next = head->next;
+ prev->next = fp;
+
+ skb_morph(head, fq->q.fragments);
+ head->next = fq->q.fragments->next;
+
+ kfree_skb(fq->q.fragments);
+ fq->q.fragments = head;
+ }
+
BUG_TRAP(head != NULL);
BUG_TRAP(FRAG6_CB(head)->offset == 0);
/* Unfragmented part is taken from the first segment. */
payload_len = ((head->data - skb_network_header(head)) -
- sizeof(struct ipv6hdr) + fq->len -
+ sizeof(struct ipv6hdr) + fq->q.len -
sizeof(struct frag_hdr));
if (payload_len > IPV6_MAXPLEN)
goto out_oversize;
@@ -640,7 +568,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
- atomic_add(clone->truesize, &ip6_frag_mem);
+ atomic_add(clone->truesize, &ip6_frags.mem);
}
/* We have to remove fragment header from datagram and to relocate
@@ -655,7 +583,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &ip6_frag_mem);
+ atomic_sub(head->truesize, &ip6_frags.mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -665,17 +593,15 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &ip6_frag_mem);
+ atomic_sub(fp->truesize, &ip6_frags.mem);
}
head->next = NULL;
head->dev = dev;
- head->tstamp = fq->stamp;
+ head->tstamp = fq->q.stamp;
ipv6_hdr(head)->payload_len = htons(payload_len);
IP6CB(head)->nhoff = nhoff;
- *skb_in = head;
-
/* Yes, and fold redundant checksum back. 8) */
if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_partial(skb_network_header(head),
@@ -685,7 +611,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
rcu_read_lock();
IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
rcu_read_unlock();
- fq->fragments = NULL;
+ fq->q.fragments = NULL;
return 1;
out_oversize:
@@ -702,10 +628,8 @@ out_fail:
return -1;
}
-static int ipv6_frag_rcv(struct sk_buff **skbp)
+static int ipv6_frag_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *skbp;
- struct net_device *dev = skb->dev;
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr = ipv6_hdr(skb);
@@ -739,23 +663,19 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
return 1;
}
- if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
+ if (atomic_read(&ip6_frags.mem) > ip6_frags_ctl.high_thresh)
ip6_evictor(ip6_dst_idev(skb->dst));
if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr,
ip6_dst_idev(skb->dst))) != NULL) {
- int ret = -1;
+ int ret;
- spin_lock(&fq->lock);
+ spin_lock(&fq->q.lock);
- ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
+ ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
- if (fq->last_in == (FIRST_IN|LAST_IN) &&
- fq->meat == fq->len)
- ret = ip6_frag_reasm(fq, skbp, dev);
-
- spin_unlock(&fq->lock);
- fq_put(fq, NULL);
+ spin_unlock(&fq->q.lock);
+ fq_put(fq);
return ret;
}
@@ -775,11 +695,10 @@ void __init ipv6_frag_init(void)
if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0)
printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n");
- ip6_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
- (jiffies ^ (jiffies >> 6)));
-
- init_timer(&ip6_frag_secret_timer);
- ip6_frag_secret_timer.function = ip6_frag_secret_rebuild;
- ip6_frag_secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval;
- add_timer(&ip6_frag_secret_timer);
+ ip6_frags.ctl = &ip6_frags_ctl;
+ ip6_frags.hashfn = ip6_hashfn;
+ ip6_frags.destructor = ip6_frag_free;
+ ip6_frags.skb_free = NULL;
+ ip6_frags.qsize = sizeof(struct frag_queue);
+ inet_frags_init(&ip6_frags);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6ff19f9eb9e..cce9941c11c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -663,7 +663,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
return rt;
}
-static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,
struct flowi *fl, int flags)
{
struct fib6_node *fn;
@@ -682,7 +682,7 @@ restart_2:
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart:
- rt = rt6_select(fn, fl->iif, strict | reachable);
+ rt = rt6_select(fn, oif, strict | reachable);
BACKTRACK(&fl->fl6_src);
if (rt == &ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE)
@@ -735,6 +735,12 @@ out2:
return rt;
}
+static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
+ struct flowi *fl, int flags)
+{
+ return ip6_pol_route(table, fl->iif, fl, flags);
+}
+
void ip6_route_input(struct sk_buff *skb)
{
struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -761,72 +767,7 @@ void ip6_route_input(struct sk_buff *skb)
static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
struct flowi *fl, int flags)
{
- struct fib6_node *fn;
- struct rt6_info *rt, *nrt;
- int strict = 0;
- int attempts = 3;
- int err;
- int reachable = ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
-
- strict |= flags & RT6_LOOKUP_F_IFACE;
-
-relookup:
- read_lock_bh(&table->tb6_lock);
-
-restart_2:
- fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
-
-restart:
- rt = rt6_select(fn, fl->oif, strict | reachable);
- BACKTRACK(&fl->fl6_src);
- if (rt == &ip6_null_entry ||
- rt->rt6i_flags & RTF_CACHE)
- goto out;
-
- dst_hold(&rt->u.dst);
- read_unlock_bh(&table->tb6_lock);
-
- if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
- nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
- else {
-#if CLONE_OFFLINK_ROUTE
- nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
-#else
- goto out2;
-#endif
- }
-
- dst_release(&rt->u.dst);
- rt = nrt ? : &ip6_null_entry;
-
- dst_hold(&rt->u.dst);
- if (nrt) {
- err = ip6_ins_rt(nrt);
- if (!err)
- goto out2;
- }
-
- if (--attempts <= 0)
- goto out2;
-
- /*
- * Race condition! In the gap, when table->tb6_lock was
- * released someone could insert this route. Relookup.
- */
- dst_release(&rt->u.dst);
- goto relookup;
-
-out:
- if (reachable) {
- reachable = 0;
- goto restart_2;
- }
- dst_hold(&rt->u.dst);
- read_unlock_bh(&table->tb6_lock);
-out2:
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.__use++;
- return rt;
+ return ip6_pol_route(table, fl->oif, fl, flags);
}
struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 3fb44277207..68bb2548e46 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -12,6 +12,7 @@
#include <net/ndisc.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
+#include <net/inet_frag.h>
#ifdef CONFIG_SYSCTL
@@ -41,7 +42,7 @@ static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH,
.procname = "ip6frag_high_thresh",
- .data = &sysctl_ip6frag_high_thresh,
+ .data = &ip6_frags_ctl.high_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
@@ -49,7 +50,7 @@ static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH,
.procname = "ip6frag_low_thresh",
- .data = &sysctl_ip6frag_low_thresh,
+ .data = &ip6_frags_ctl.low_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
@@ -57,7 +58,7 @@ static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_TIME,
.procname = "ip6frag_time",
- .data = &sysctl_ip6frag_time,
+ .data = &ip6_frags_ctl.timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
@@ -66,7 +67,7 @@ static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
.procname = "ip6frag_secret_interval",
- .data = &sysctl_ip6frag_secret_interval,
+ .data = &ip6_frags_ctl.secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index a07b59c528f..737b755342b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1668,9 +1668,8 @@ ipv6_pktoptions:
return 0;
}
-static int tcp_v6_rcv(struct sk_buff **pskb)
+static int tcp_v6_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *pskb;
struct tcphdr *th;
struct sock *sk;
int ret;
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
index 23e2809878a..6323921b40b 100644
--- a/net/ipv6/tunnel6.c
+++ b/net/ipv6/tunnel6.c
@@ -87,9 +87,8 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
EXPORT_SYMBOL(xfrm6_tunnel_deregister);
-static int tunnel6_rcv(struct sk_buff **pskb)
+static int tunnel6_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
@@ -106,9 +105,8 @@ drop:
return 0;
}
-static int tunnel46_rcv(struct sk_buff **pskb)
+static int tunnel46_rcv(struct sk_buff *skb)
{
- struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 82ff26dd447..caebad6ee51 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -405,10 +405,9 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
return 0;
}
-int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
+int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
int proto)
{
- struct sk_buff *skb = *pskb;
struct sock *sk;
struct udphdr *uh;
struct net_device *dev = skb->dev;
@@ -494,9 +493,9 @@ discard:
return 0;
}
-static __inline__ int udpv6_rcv(struct sk_buff **pskb)
+static __inline__ int udpv6_rcv(struct sk_buff *skb)
{
- return __udp6_lib_rcv(pskb, udp_hash, IPPROTO_UDP);
+ return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP);
}
/*
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 6e252f318f7..2d3fda60123 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -6,7 +6,7 @@
#include <net/addrconf.h>
#include <net/inet_common.h>
-extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
+extern int __udp6_lib_rcv(struct sk_buff *, struct hlist_head [], int );
extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
int , int , int , __be32 , struct hlist_head []);
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index f54016a5500..766566f7de4 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -17,9 +17,9 @@
DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly;
-static int udplitev6_rcv(struct sk_buff **pskb)
+static int udplitev6_rcv(struct sk_buff *skb)
{
- return __udp6_lib_rcv(pskb, udplite_hash, IPPROTO_UDPLITE);
+ return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
}
static void udplitev6_err(struct sk_buff *skb,
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index c858537cec4..02f69e544f6 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -133,9 +133,9 @@ drop:
EXPORT_SYMBOL(xfrm6_rcv_spi);
-int xfrm6_rcv(struct sk_buff **pskb)
+int xfrm6_rcv(struct sk_buff *skb)
{
- return xfrm6_rcv_spi(*pskb, 0);
+ return xfrm6_rcv_spi(skb, 0);
}
EXPORT_SYMBOL(xfrm6_rcv);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 4618c18e611..a5a32c17249 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -80,7 +80,7 @@ static int xfrm6_output_finish2(struct sk_buff *skb)
while (likely((err = xfrm6_output_one(skb)) == 0)) {
nf_reset(skb);
- err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, &skb, NULL,
+ err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
skb->dst->dev, dst_output);
if (unlikely(err != 1))
break;
@@ -88,7 +88,7 @@ static int xfrm6_output_finish2(struct sk_buff *skb)
if (!skb->dst->xfrm)
return dst_output(skb);
- err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
+ err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
skb->dst->dev, xfrm6_output_finish2);
if (unlikely(err != 1))
break;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a523fa4136e..bed9ba01e8e 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -117,7 +117,7 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
EXPORT_SYMBOL(nf_unregister_hooks);
unsigned int nf_iterate(struct list_head *head,
- struct sk_buff **skb,
+ struct sk_buff *skb,
int hook,
const struct net_device *indev,
const struct net_device *outdev,
@@ -160,7 +160,7 @@ unsigned int nf_iterate(struct list_head *head,
/* Returns 1 if okfn() needs to be executed by the caller,
* -EPERM for NF_DROP, 0 otherwise. */
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
@@ -175,17 +175,17 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
elem = &nf_hooks[pf][hook];
next_hook:
- verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
+ verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
outdev, &elem, okfn, hook_thresh);
if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret = 1;
goto unlock;
} else if (verdict == NF_DROP) {
- kfree_skb(*pskb);
+ kfree_skb(skb);
ret = -EPERM;
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
- if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn,
+ if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
verdict >> NF_VERDICT_BITS))
goto next_hook;
}
@@ -196,34 +196,24 @@ unlock:
EXPORT_SYMBOL(nf_hook_slow);
-int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+int skb_make_writable(struct sk_buff *skb, unsigned int writable_len)
{
- struct sk_buff *nskb;
-
- if (writable_len > (*pskb)->len)
+ if (writable_len > skb->len)
return 0;
/* Not exclusive use of packet? Must copy. */
- if (skb_cloned(*pskb) && !skb_clone_writable(*pskb, writable_len))
- goto copy_skb;
- if (skb_shared(*pskb))
- goto copy_skb;
-
- return pskb_may_pull(*pskb, writable_len);
-
-copy_skb:
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return 0;
- BUG_ON(skb_is_nonlinear(nskb));
-
- /* Rest of kernel will get very unhappy if we pass it a
- suddenly-orphaned skbuff */
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- return 1;
+ if (!skb_cloned(skb)) {
+ if (writable_len <= skb_headlen(skb))
+ return 1;
+ } else if (skb_clone_writable(skb, writable_len))
+ return 1;
+
+ if (writable_len <= skb_headlen(skb))
+ writable_len = 0;
+ else
+ writable_len -= skb_headlen(skb);
+
+ return !!__pskb_pull_tail(skb, writable_len);
}
EXPORT_SYMBOL(skb_make_writable);
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index e42ab230ad8..7b8239c0cd5 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
module_param(ts_algo, charp, 0400);
MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
-unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
@@ -79,7 +79,7 @@ static struct {
},
};
-static int amanda_help(struct sk_buff **pskb,
+static int amanda_help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -101,25 +101,25 @@ static int amanda_help(struct sk_buff **pskb,
/* increase the UDP timeout of the master connection as replies from
* Amanda clients to the server can be quite delayed */
- nf_ct_refresh(ct, *pskb, master_timeout * HZ);
+ nf_ct_refresh(ct, skb, master_timeout * HZ);
/* No data? */
dataoff = protoff + sizeof(struct udphdr);
- if (dataoff >= (*pskb)->len) {
+ if (dataoff >= skb->len) {
if (net_ratelimit())
- printk("amanda_help: skblen = %u\n", (*pskb)->len);
+ printk("amanda_help: skblen = %u\n", skb->len);
return NF_ACCEPT;
}
memset(&ts, 0, sizeof(ts));
- start = skb_find_text(*pskb, dataoff, (*pskb)->len,
+ start = skb_find_text(skb, dataoff, skb->len,
search[SEARCH_CONNECT].ts, &ts);
if (start == UINT_MAX)
goto out;
start += dataoff + search[SEARCH_CONNECT].len;
memset(&ts, 0, sizeof(ts));
- stop = skb_find_text(*pskb, start, (*pskb)->len,
+ stop = skb_find_text(skb, start, skb->len,
search[SEARCH_NEWLINE].ts, &ts);
if (stop == UINT_MAX)
goto out;
@@ -127,13 +127,13 @@ static int amanda_help(struct sk_buff **pskb,
for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
memset(&ts, 0, sizeof(ts));
- off = skb_find_text(*pskb, start, stop, search[i].ts, &ts);
+ off = skb_find_text(skb, start, stop, search[i].ts, &ts);
if (off == UINT_MAX)
continue;
off += start + search[i].len;
len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
- if (skb_copy_bits(*pskb, off, pbuf, len))
+ if (skb_copy_bits(skb, off, pbuf, len))
break;
pbuf[len] = '\0';
@@ -153,7 +153,7 @@ static int amanda_help(struct sk_buff **pskb,
nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
- ret = nf_nat_amanda(pskb, ctinfo, off - dataoff,
+ ret = nf_nat_amanda(skb, ctinfo, off - dataoff,
len, exp);
else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 83c30b45d17..4d6171bc082 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -307,7 +307,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert);
/* Confirm a connection given skb; places it in hash table */
int
-__nf_conntrack_confirm(struct sk_buff **pskb)
+__nf_conntrack_confirm(struct sk_buff *skb)
{
unsigned int hash, repl_hash;
struct nf_conntrack_tuple_hash *h;
@@ -316,7 +316,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
struct hlist_node *n;
enum ip_conntrack_info ctinfo;
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
/* ipt_REJECT uses nf_conntrack_attach to attach related
ICMP/TCP RST packets in other direction. Actual packet
@@ -367,14 +367,14 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
write_unlock_bh(&nf_conntrack_lock);
help = nfct_help(ct);
if (help && help->helper)
- nf_conntrack_event_cache(IPCT_HELPER, *pskb);
+ nf_conntrack_event_cache(IPCT_HELPER, skb);
#ifdef CONFIG_NF_NAT_NEEDED
if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
- nf_conntrack_event_cache(IPCT_NATINFO, *pskb);
+ nf_conntrack_event_cache(IPCT_NATINFO, skb);
#endif
nf_conntrack_event_cache(master_ct(ct) ?
- IPCT_RELATED : IPCT_NEW, *pskb);
+ IPCT_RELATED : IPCT_NEW, skb);
return NF_ACCEPT;
out:
@@ -632,7 +632,7 @@ resolve_normal_ct(struct sk_buff *skb,
}
unsigned int
-nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
+nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
@@ -644,14 +644,14 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
int ret;
/* Previously seen (loopback or untracked)? Ignore. */
- if ((*pskb)->nfct) {
+ if (skb->nfct) {
NF_CT_STAT_INC_ATOMIC(ignore);
return NF_ACCEPT;
}
/* rcu_read_lock()ed by nf_hook_slow */
l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
- ret = l3proto->get_l4proto(*pskb, skb_network_offset(*pskb),
+ ret = l3proto->get_l4proto(skb, skb_network_offset(skb),
&dataoff, &protonum);
if (ret <= 0) {
pr_debug("not prepared to track yet or error occured\n");
@@ -666,13 +666,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
* inverse of the return code tells to the netfilter
* core what to do with the packet. */
if (l4proto->error != NULL &&
- (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
+ (ret = l4proto->error(skb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
NF_CT_STAT_INC_ATOMIC(error);
NF_CT_STAT_INC_ATOMIC(invalid);
return -ret;
}
- ct = resolve_normal_ct(*pskb, dataoff, pf, protonum, l3proto, l4proto,
+ ct = resolve_normal_ct(skb, dataoff, pf, protonum, l3proto, l4proto,
&set_reply, &ctinfo);
if (!ct) {
/* Not valid part of a connection */
@@ -686,21 +686,21 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
return NF_DROP;
}
- NF_CT_ASSERT((*pskb)->nfct);
+ NF_CT_ASSERT(skb->nfct);
- ret = l4proto->packet(ct, *pskb, dataoff, ctinfo, pf, hooknum);
+ ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
if (ret < 0) {
/* Invalid: inverse of the return code tells
* the netfilter core what to do */
pr_debug("nf_conntrack_in: Can't track with proto module\n");
- nf_conntrack_put((*pskb)->nfct);
- (*pskb)->nfct = NULL;
+ nf_conntrack_put(skb->nfct);
+ skb->nfct = NULL;
NF_CT_STAT_INC_ATOMIC(invalid);
return -ret;
}
if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
- nf_conntrack_event_cache(IPCT_STATUS, *pskb);
+ nf_conntrack_event_cache(IPCT_STATUS, skb);
return ret;
}
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index c763ee74ea0..6df259067f7 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -43,7 +43,7 @@ module_param_array(ports, ushort, &ports_c, 0400);
static int loose;
module_param(loose, bool, 0600);
-unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
enum nf_ct_ftp_type type,
unsigned int matchoff,
@@ -344,7 +344,7 @@ static void update_nl_seq(u32 nl_seq, struct nf_ct_ftp_master *info, int dir,
}
}
-static int help(struct sk_buff **pskb,
+static int help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -371,21 +371,21 @@ static int help(struct sk_buff **pskb,
return NF_ACCEPT;
}
- th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
dataoff = protoff + th->doff * 4;
/* No data? */
- if (dataoff >= (*pskb)->len) {
+ if (dataoff >= skb->len) {
pr_debug("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
- (*pskb)->len);
+ skb->len);
return NF_ACCEPT;
}
- datalen = (*pskb)->len - dataoff;
+ datalen = skb->len - dataoff;
spin_lock_bh(&nf_ftp_lock);
- fb_ptr = skb_header_pointer(*pskb, dataoff, datalen, ftp_buffer);
+ fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
BUG_ON(fb_ptr == NULL);
ends_in_nl = (fb_ptr[datalen - 1] == '\n');
@@ -491,7 +491,7 @@ static int help(struct sk_buff **pskb,
* (possibly changed) expectation itself. */
nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook);
if (nf_nat_ftp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype,
+ ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp);
else {
/* Can't expect this? Best to drop packet now. */
@@ -508,7 +508,7 @@ out_update_nl:
/* Now if this ends in \n, update ftp info. Seq may have been
* adjusted by NAT code. */
if (ends_in_nl)
- update_nl_seq(seq, ct_ftp_info, dir, *pskb);
+ update_nl_seq(seq, ct_ftp_info, dir, skb);
out:
spin_unlock_bh(&nf_ftp_lock);
return ret;
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index a8a9dfbe7a6..f23fd9598e1 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -47,27 +47,27 @@ MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "
"(determined by routing information)");
/* Hooks for NAT */
-int (*set_h245_addr_hook) (struct sk_buff **pskb,
+int (*set_h245_addr_hook) (struct sk_buff *skb,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
__read_mostly;
-int (*set_h225_addr_hook) (struct sk_buff **pskb,
+int (*set_h225_addr_hook) (struct sk_buff *skb,
unsigned char **data, int dataoff,
TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
__read_mostly;
-int (*set_sig_addr_hook) (struct sk_buff **pskb,
+int (*set_sig_addr_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count) __read_mostly;
-int (*set_ras_addr_hook) (struct sk_buff **pskb,
+int (*set_ras_addr_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count) __read_mostly;
-int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb,
+int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -75,25 +75,25 @@ int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb,
__be16 port, __be16 rtp_port,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp) __read_mostly;
-int (*nat_t120_hook) (struct sk_buff **pskb,
+int (*nat_t120_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp) __read_mostly;
-int (*nat_h245_hook) (struct sk_buff **pskb,
+int (*nat_h245_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp) __read_mostly;
-int (*nat_callforwarding_hook) (struct sk_buff **pskb,
+int (*nat_callforwarding_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp) __read_mostly;
-int (*nat_q931_hook) (struct sk_buff **pskb,
+int (*nat_q931_hook) (struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, TransportAddress *taddr, int idx,
@@ -108,7 +108,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[];
static struct nf_conntrack_helper nf_conntrack_helper_ras[];
/****************************************************************************/
-static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
+static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
unsigned char **data, int *datalen, int *dataoff)
{
@@ -122,7 +122,7 @@ static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
int tpktoff;
/* Get TCP header */
- th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL)
return 0;
@@ -130,13 +130,13 @@ static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
tcpdataoff = protoff + th->doff * 4;
/* Get TCP data length */
- tcpdatalen = (*pskb)->len - tcpdataoff;
+ tcpdatalen = skb->len - tcpdataoff;
if (tcpdatalen <= 0) /* No TCP data */
goto clear_out;
if (*data == NULL) { /* first TPKT */
/* Get first TPKT pointer */
- tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen,
+ tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
h323_buffer);
BUG_ON(tpkt == NULL);
@@ -248,7 +248,7 @@ static int get_h245_addr(struct nf_conn *ct, unsigned char *data,
}
/****************************************************************************/
-static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
+static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr)
@@ -297,7 +297,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
(nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook)) &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
- ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ ret = nat_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
taddr, port, rtp_port, rtp_exp, rtcp_exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(rtp_exp) == 0) {
@@ -321,7 +321,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int expect_t120(struct sk_buff **pskb,
+static int expect_t120(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -355,7 +355,7 @@ static int expect_t120(struct sk_buff **pskb,
(nat_t120 = rcu_dereference(nat_t120_hook)) &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
- ret = nat_t120(pskb, ct, ctinfo, data, dataoff, taddr,
+ ret = nat_t120(skb, ct, ctinfo, data, dataoff, taddr,
port, exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(exp) == 0) {
@@ -371,7 +371,7 @@ static int expect_t120(struct sk_buff **pskb,
}
/****************************************************************************/
-static int process_h245_channel(struct sk_buff **pskb,
+static int process_h245_channel(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -381,7 +381,7 @@ static int process_h245_channel(struct sk_buff **pskb,
if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
/* RTP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
&channel->mediaChannel);
if (ret < 0)
return -1;
@@ -390,7 +390,7 @@ static int process_h245_channel(struct sk_buff **pskb,
if (channel->
options & eH2250LogicalChannelParameters_mediaControlChannel) {
/* RTCP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
&channel->mediaControlChannel);
if (ret < 0)
return -1;
@@ -400,7 +400,7 @@ static int process_h245_channel(struct sk_buff **pskb,
}
/****************************************************************************/
-static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
OpenLogicalChannel *olc)
@@ -412,7 +412,7 @@ static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==
eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
{
- ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ ret = process_h245_channel(skb, ct, ctinfo, data, dataoff,
&olc->
forwardLogicalChannelParameters.
multiplexParameters.
@@ -430,7 +430,7 @@ static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
{
ret =
- process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ process_h245_channel(skb, ct, ctinfo, data, dataoff,
&olc->
reverseLogicalChannelParameters.
multiplexParameters.
@@ -448,7 +448,7 @@ static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
t120.choice == eDataProtocolCapability_separateLANStack &&
olc->separateStack.networkAddress.choice ==
eNetworkAccessParameters_networkAddress_localAreaAddress) {
- ret = expect_t120(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_t120(skb, ct, ctinfo, data, dataoff,
&olc->separateStack.networkAddress.
localAreaAddress);
if (ret < 0)
@@ -459,7 +459,7 @@ static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
OpenLogicalChannelAck *olca)
@@ -477,7 +477,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
choice ==
eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
{
- ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ ret = process_h245_channel(skb, ct, ctinfo, data, dataoff,
&olca->
reverseLogicalChannelParameters.
multiplexParameters.
@@ -496,7 +496,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
if (ack->options &
eH2250LogicalChannelAckParameters_mediaChannel) {
/* RTP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
&ack->mediaChannel);
if (ret < 0)
return -1;
@@ -505,7 +505,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
if (ack->options &
eH2250LogicalChannelAckParameters_mediaControlChannel) {
/* RTCP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
&ack->mediaControlChannel);
if (ret < 0)
return -1;
@@ -515,7 +515,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
if ((olca->options & eOpenLogicalChannelAck_separateStack) &&
olca->separateStack.networkAddress.choice ==
eNetworkAccessParameters_networkAddress_localAreaAddress) {
- ret = expect_t120(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_t120(skb, ct, ctinfo, data, dataoff,
&olca->separateStack.networkAddress.
localAreaAddress);
if (ret < 0)
@@ -526,7 +526,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
MultimediaSystemControlMessage *mscm)
@@ -535,7 +535,7 @@ static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
case eMultimediaSystemControlMessage_request:
if (mscm->request.choice ==
eRequestMessage_openLogicalChannel) {
- return process_olc(pskb, ct, ctinfo, data, dataoff,
+ return process_olc(skb, ct, ctinfo, data, dataoff,
&mscm->request.openLogicalChannel);
}
pr_debug("nf_ct_h323: H.245 Request %d\n",
@@ -544,7 +544,7 @@ static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
case eMultimediaSystemControlMessage_response:
if (mscm->response.choice ==
eResponseMessage_openLogicalChannelAck) {
- return process_olca(pskb, ct, ctinfo, data, dataoff,
+ return process_olca(skb, ct, ctinfo, data, dataoff,
&mscm->response.
openLogicalChannelAck);
}
@@ -560,7 +560,7 @@ static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int h245_help(struct sk_buff **pskb, unsigned int protoff,
+static int h245_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
static MultimediaSystemControlMessage mscm;
@@ -574,12 +574,12 @@ static int h245_help(struct sk_buff **pskb, unsigned int protoff,
ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
return NF_ACCEPT;
}
- pr_debug("nf_ct_h245: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_h245: skblen = %u\n", skb->len);
spin_lock_bh(&nf_h323_lock);
/* Process each TPKT */
- while (get_tpkt_data(pskb, protoff, ct, ctinfo,
+ while (get_tpkt_data(skb, protoff, ct, ctinfo,
&data, &datalen, &dataoff)) {
pr_debug("nf_ct_h245: TPKT len=%d ", datalen);
NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
@@ -596,7 +596,7 @@ static int h245_help(struct sk_buff **pskb, unsigned int protoff,
}
/* Process H.245 signal */
- if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0)
+ if (process_h245(skb, ct, ctinfo, &data, dataoff, &mscm) < 0)
goto drop;
}
@@ -654,7 +654,7 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
}
/****************************************************************************/
-static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct,
+static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr)
@@ -687,7 +687,7 @@ static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct,
(nat_h245 = rcu_dereference(nat_h245_hook)) &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
- ret = nat_h245(pskb, ct, ctinfo, data, dataoff, taddr,
+ ret = nat_h245(skb, ct, ctinfo, data, dataoff, taddr,
port, exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(exp) == 0) {
@@ -758,7 +758,7 @@ static int callforward_do_filter(union nf_conntrack_address *src,
}
/****************************************************************************/
-static int expect_callforwarding(struct sk_buff **pskb,
+static int expect_callforwarding(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -798,7 +798,7 @@ static int expect_callforwarding(struct sk_buff **pskb,
(nat_callforwarding = rcu_dereference(nat_callforwarding_hook)) &&
ct->status & IPS_NAT_MASK) {
/* Need NAT */
- ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff,
+ ret = nat_callforwarding(skb, ct, ctinfo, data, dataoff,
taddr, port, exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(exp) == 0) {
@@ -814,7 +814,7 @@ static int expect_callforwarding(struct sk_buff **pskb,
}
/****************************************************************************/
-static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
Setup_UUIE *setup)
@@ -829,7 +829,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
pr_debug("nf_ct_q931: Setup\n");
if (setup->options & eSetup_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&setup->h245Address);
if (ret < 0)
return -1;
@@ -846,7 +846,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
NIP6(*(struct in6_addr *)&addr), ntohs(port),
NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3),
ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
- ret = set_h225_addr(pskb, data, dataoff,
+ ret = set_h225_addr(skb, data, dataoff,
&setup->destCallSignalAddress,
&ct->tuplehash[!dir].tuple.src.u3,
ct->tuplehash[!dir].tuple.src.u.tcp.port);
@@ -864,7 +864,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
NIP6(*(struct in6_addr *)&addr), ntohs(port),
NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3),
ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
- ret = set_h225_addr(pskb, data, dataoff,
+ ret = set_h225_addr(skb, data, dataoff,
&setup->sourceCallSignalAddress,
&ct->tuplehash[!dir].tuple.dst.u3,
ct->tuplehash[!dir].tuple.dst.u.tcp.port);
@@ -874,7 +874,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
if (setup->options & eSetup_UUIE_fastStart) {
for (i = 0; i < setup->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&setup->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -885,7 +885,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_callproceeding(struct sk_buff **pskb,
+static int process_callproceeding(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
@@ -897,7 +897,7 @@ static int process_callproceeding(struct sk_buff **pskb,
pr_debug("nf_ct_q931: CallProceeding\n");
if (callproc->options & eCallProceeding_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&callproc->h245Address);
if (ret < 0)
return -1;
@@ -905,7 +905,7 @@ static int process_callproceeding(struct sk_buff **pskb,
if (callproc->options & eCallProceeding_UUIE_fastStart) {
for (i = 0; i < callproc->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&callproc->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -916,7 +916,7 @@ static int process_callproceeding(struct sk_buff **pskb,
}
/****************************************************************************/
-static int process_connect(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
Connect_UUIE *connect)
@@ -927,7 +927,7 @@ static int process_connect(struct sk_buff **pskb, struct nf_conn *ct,
pr_debug("nf_ct_q931: Connect\n");
if (connect->options & eConnect_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&connect->h245Address);
if (ret < 0)
return -1;
@@ -935,7 +935,7 @@ static int process_connect(struct sk_buff **pskb, struct nf_conn *ct,
if (connect->options & eConnect_UUIE_fastStart) {
for (i = 0; i < connect->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&connect->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -946,7 +946,7 @@ static int process_connect(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
Alerting_UUIE *alert)
@@ -957,7 +957,7 @@ static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct,
pr_debug("nf_ct_q931: Alerting\n");
if (alert->options & eAlerting_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&alert->h245Address);
if (ret < 0)
return -1;
@@ -965,7 +965,7 @@ static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct,
if (alert->options & eAlerting_UUIE_fastStart) {
for (i = 0; i < alert->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&alert->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -976,7 +976,7 @@ static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
Facility_UUIE *facility)
@@ -988,7 +988,7 @@ static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
if (facility->reason.choice == eFacilityReason_callForwarded) {
if (facility->options & eFacility_UUIE_alternativeAddress)
- return expect_callforwarding(pskb, ct, ctinfo, data,
+ return expect_callforwarding(skb, ct, ctinfo, data,
dataoff,
&facility->
alternativeAddress);
@@ -996,7 +996,7 @@ static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
}
if (facility->options & eFacility_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&facility->h245Address);
if (ret < 0)
return -1;
@@ -1004,7 +1004,7 @@ static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
if (facility->options & eFacility_UUIE_fastStart) {
for (i = 0; i < facility->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&facility->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -1015,7 +1015,7 @@ static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_progress(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
Progress_UUIE *progress)
@@ -1026,7 +1026,7 @@ static int process_progress(struct sk_buff **pskb, struct nf_conn *ct,
pr_debug("nf_ct_q931: Progress\n");
if (progress->options & eProgress_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = expect_h245(skb, ct, ctinfo, data, dataoff,
&progress->h245Address);
if (ret < 0)
return -1;
@@ -1034,7 +1034,7 @@ static int process_progress(struct sk_buff **pskb, struct nf_conn *ct,
if (progress->options & eProgress_UUIE_fastStart) {
for (i = 0; i < progress->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ ret = process_olc(skb, ct, ctinfo, data, dataoff,
&progress->fastStart.item[i]);
if (ret < 0)
return -1;
@@ -1045,7 +1045,7 @@ static int process_progress(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_q931(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff, Q931 *q931)
{
@@ -1055,28 +1055,28 @@ static int process_q931(struct sk_buff **pskb, struct nf_conn *ct,
switch (pdu->h323_message_body.choice) {
case eH323_UU_PDU_h323_message_body_setup:
- ret = process_setup(pskb, ct, ctinfo, data, dataoff,
+ ret = process_setup(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.setup);
break;
case eH323_UU_PDU_h323_message_body_callProceeding:
- ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff,
+ ret = process_callproceeding(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.
callProceeding);
break;
case eH323_UU_PDU_h323_message_body_connect:
- ret = process_connect(pskb, ct, ctinfo, data, dataoff,
+ ret = process_connect(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.connect);
break;
case eH323_UU_PDU_h323_message_body_alerting:
- ret = process_alerting(pskb, ct, ctinfo, data, dataoff,
+ ret = process_alerting(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.alerting);
break;
case eH323_UU_PDU_h323_message_body_facility:
- ret = process_facility(pskb, ct, ctinfo, data, dataoff,
+ ret = process_facility(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.facility);
break;
case eH323_UU_PDU_h323_message_body_progress:
- ret = process_progress(pskb, ct, ctinfo, data, dataoff,
+ ret = process_progress(skb, ct, ctinfo, data, dataoff,
&pdu->h323_message_body.progress);
break;
default:
@@ -1090,7 +1090,7 @@ static int process_q931(struct sk_buff **pskb, struct nf_conn *ct,
if (pdu->options & eH323_UU_PDU_h245Control) {
for (i = 0; i < pdu->h245Control.count; i++) {
- ret = process_h245(pskb, ct, ctinfo, data, dataoff,
+ ret = process_h245(skb, ct, ctinfo, data, dataoff,
&pdu->h245Control.item[i]);
if (ret < 0)
return -1;
@@ -1101,7 +1101,7 @@ static int process_q931(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int q931_help(struct sk_buff **pskb, unsigned int protoff,
+static int q931_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
static Q931 q931;
@@ -1115,12 +1115,12 @@ static int q931_help(struct sk_buff **pskb, unsigned int protoff,
ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
return NF_ACCEPT;
}
- pr_debug("nf_ct_q931: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_q931: skblen = %u\n", skb->len);
spin_lock_bh(&nf_h323_lock);
/* Process each TPKT */
- while (get_tpkt_data(pskb, protoff, ct, ctinfo,
+ while (get_tpkt_data(skb, protoff, ct, ctinfo,
&data, &datalen, &dataoff)) {
pr_debug("nf_ct_q931: TPKT len=%d ", datalen);
NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
@@ -1136,7 +1136,7 @@ static int q931_help(struct sk_buff **pskb, unsigned int protoff,
}
/* Process Q.931 signal */
- if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0)
+ if (process_q931(skb, ct, ctinfo, &data, dataoff, &q931) < 0)
goto drop;
}
@@ -1177,20 +1177,20 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
};
/****************************************************************************/
-static unsigned char *get_udp_data(struct sk_buff **pskb, unsigned int protoff,
+static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
int *datalen)
{
struct udphdr _uh, *uh;
int dataoff;
- uh = skb_header_pointer(*pskb, protoff, sizeof(_uh), &_uh);
+ uh = skb_header_pointer(skb, protoff, sizeof(_uh), &_uh);
if (uh == NULL)
return NULL;
dataoff = protoff + sizeof(_uh);
- if (dataoff >= (*pskb)->len)
+ if (dataoff >= skb->len)
return NULL;
- *datalen = (*pskb)->len - dataoff;
- return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer);
+ *datalen = skb->len - dataoff;
+ return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
}
/****************************************************************************/
@@ -1227,7 +1227,7 @@ static int set_expect_timeout(struct nf_conntrack_expect *exp,
}
/****************************************************************************/
-static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
+static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count)
@@ -1265,7 +1265,7 @@ static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
nat_q931 = rcu_dereference(nat_q931_hook);
if (nat_q931 && ct->status & IPS_NAT_MASK) { /* Need NAT */
- ret = nat_q931(pskb, ct, ctinfo, data, taddr, i, port, exp);
+ ret = nat_q931(skb, ct, ctinfo, data, taddr, i, port, exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(exp) == 0) {
pr_debug("nf_ct_ras: expect Q.931 ");
@@ -1283,7 +1283,7 @@ static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_grq(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, GatekeeperRequest *grq)
{
@@ -1293,13 +1293,13 @@ static int process_grq(struct sk_buff **pskb, struct nf_conn *ct,
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK) /* NATed */
- return set_ras_addr(pskb, ct, ctinfo, data,
+ return set_ras_addr(skb, ct, ctinfo, data,
&grq->rasAddress, 1);
return 0;
}
/****************************************************************************/
-static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, GatekeeperConfirm *gcf)
{
@@ -1343,7 +1343,7 @@ static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, RegistrationRequest *rrq)
{
@@ -1353,7 +1353,7 @@ static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
pr_debug("nf_ct_ras: RRQ\n");
- ret = expect_q931(pskb, ct, ctinfo, data,
+ ret = expect_q931(skb, ct, ctinfo, data,
rrq->callSignalAddress.item,
rrq->callSignalAddress.count);
if (ret < 0)
@@ -1361,7 +1361,7 @@ static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK) {
- ret = set_ras_addr(pskb, ct, ctinfo, data,
+ ret = set_ras_addr(skb, ct, ctinfo, data,
rrq->rasAddress.item,
rrq->rasAddress.count);
if (ret < 0)
@@ -1378,7 +1378,7 @@ static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, RegistrationConfirm *rcf)
{
@@ -1392,7 +1392,7 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
+ ret = set_sig_addr(skb, ct, ctinfo, data,
rcf->callSignalAddress.item,
rcf->callSignalAddress.count);
if (ret < 0)
@@ -1407,7 +1407,7 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
if (info->timeout > 0) {
pr_debug("nf_ct_ras: set RAS connection timeout to "
"%u seconds\n", info->timeout);
- nf_ct_refresh(ct, *pskb, info->timeout * HZ);
+ nf_ct_refresh(ct, skb, info->timeout * HZ);
/* Set expect timeout */
read_lock_bh(&nf_conntrack_lock);
@@ -1427,7 +1427,7 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_urq(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, UnregistrationRequest *urq)
{
@@ -1440,7 +1440,7 @@ static int process_urq(struct sk_buff **pskb, struct nf_conn *ct,
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
+ ret = set_sig_addr(skb, ct, ctinfo, data,
urq->callSignalAddress.item,
urq->callSignalAddress.count);
if (ret < 0)
@@ -1453,13 +1453,13 @@ static int process_urq(struct sk_buff **pskb, struct nf_conn *ct,
info->sig_port[!dir] = 0;
/* Give it 30 seconds for UCF or URJ */
- nf_ct_refresh(ct, *pskb, 30 * HZ);
+ nf_ct_refresh(ct, skb, 30 * HZ);
return 0;
}
/****************************************************************************/
-static int process_arq(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, AdmissionRequest *arq)
{
@@ -1479,7 +1479,7 @@ static int process_arq(struct sk_buff **pskb, struct nf_conn *ct,
port == info->sig_port[dir] &&
set_h225_addr && ct->status & IPS_NAT_MASK) {
/* Answering ARQ */
- return set_h225_addr(pskb, data, 0,
+ return set_h225_addr(skb, data, 0,
&arq->destCallSignalAddress,
&ct->tuplehash[!dir].tuple.dst.u3,
info->sig_port[!dir]);
@@ -1491,7 +1491,7 @@ static int process_arq(struct sk_buff **pskb, struct nf_conn *ct,
!memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
set_h225_addr && ct->status & IPS_NAT_MASK) {
/* Calling ARQ */
- return set_h225_addr(pskb, data, 0,
+ return set_h225_addr(skb, data, 0,
&arq->srcCallSignalAddress,
&ct->tuplehash[!dir].tuple.dst.u3,
port);
@@ -1501,7 +1501,7 @@ static int process_arq(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_acf(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, AdmissionConfirm *acf)
{
@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff **pskb, struct nf_conn *ct,
/* Answering ACF */
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK)
- return set_sig_addr(pskb, ct, ctinfo, data,
+ return set_sig_addr(skb, ct, ctinfo, data,
&acf->destCallSignalAddress, 1);
return 0;
}
@@ -1548,7 +1548,7 @@ static int process_acf(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_lrq(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, LocationRequest *lrq)
{
@@ -1558,13 +1558,13 @@ static int process_lrq(struct sk_buff **pskb, struct nf_conn *ct,
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK)
- return set_ras_addr(pskb, ct, ctinfo, data,
+ return set_ras_addr(skb, ct, ctinfo, data,
&lrq->replyAddress, 1);
return 0;
}
/****************************************************************************/
-static int process_lcf(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, LocationConfirm *lcf)
{
@@ -1603,7 +1603,7 @@ static int process_lcf(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_irr(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, InfoRequestResponse *irr)
{
@@ -1615,7 +1615,7 @@ static int process_irr(struct sk_buff **pskb, struct nf_conn *ct,
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK) {
- ret = set_ras_addr(pskb, ct, ctinfo, data,
+ ret = set_ras_addr(skb, ct, ctinfo, data,
&irr->rasAddress, 1);
if (ret < 0)
return -1;
@@ -1623,7 +1623,7 @@ static int process_irr(struct sk_buff **pskb, struct nf_conn *ct,
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
+ ret = set_sig_addr(skb, ct, ctinfo, data,
irr->callSignalAddress.item,
irr->callSignalAddress.count);
if (ret < 0)
@@ -1634,40 +1634,40 @@ static int process_irr(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int process_ras(struct sk_buff **pskb, struct nf_conn *ct,
+static int process_ras(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, RasMessage *ras)
{
switch (ras->choice) {
case eRasMessage_gatekeeperRequest:
- return process_grq(pskb, ct, ctinfo, data,
+ return process_grq(skb, ct, ctinfo, data,
&ras->gatekeeperRequest);
case eRasMessage_gatekeeperConfirm:
- return process_gcf(pskb, ct, ctinfo, data,
+ return process_gcf(skb, ct, ctinfo, data,
&ras->gatekeeperConfirm);
case eRasMessage_registrationRequest:
- return process_rrq(pskb, ct, ctinfo, data,
+ return process_rrq(skb, ct, ctinfo, data,
&ras->registrationRequest);
case eRasMessage_registrationConfirm:
- return process_rcf(pskb, ct, ctinfo, data,
+ return process_rcf(skb, ct, ctinfo, data,
&ras->registrationConfirm);
case eRasMessage_unregistrationRequest:
- return process_urq(pskb, ct, ctinfo, data,
+ return process_urq(skb, ct, ctinfo, data,
&ras->unregistrationRequest);
case eRasMessage_admissionRequest:
- return process_arq(pskb, ct, ctinfo, data,
+ return process_arq(skb, ct, ctinfo, data,
&ras->admissionRequest);
case eRasMessage_admissionConfirm:
- return process_acf(pskb, ct, ctinfo, data,
+ return process_acf(skb, ct, ctinfo, data,
&ras->admissionConfirm);
case eRasMessage_locationRequest:
- return process_lrq(pskb, ct, ctinfo, data,
+ return process_lrq(skb, ct, ctinfo, data,
&ras->locationRequest);
case eRasMessage_locationConfirm:
- return process_lcf(pskb, ct, ctinfo, data,
+ return process_lcf(skb, ct, ctinfo, data,
&ras->locationConfirm);
case eRasMessage_infoRequestResponse:
- return process_irr(pskb, ct, ctinfo, data,
+ return process_irr(skb, ct, ctinfo, data,
&ras->infoRequestResponse);
default:
pr_debug("nf_ct_ras: RAS message %d\n", ras->choice);
@@ -1678,7 +1678,7 @@ static int process_ras(struct sk_buff **pskb, struct nf_conn *ct,
}
/****************************************************************************/
-static int ras_help(struct sk_buff **pskb, unsigned int protoff,
+static int ras_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
static RasMessage ras;
@@ -1686,12 +1686,12 @@ static int ras_help(struct sk_buff **pskb, unsigned int protoff,
int datalen = 0;
int ret;
- pr_debug("nf_ct_ras: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_ras: skblen = %u\n", skb->len);
spin_lock_bh(&nf_h323_lock);
/* Get UDP data */
- data = get_udp_data(pskb, protoff, &datalen);
+ data = get_udp_data(skb, protoff, &datalen);
if (data == NULL)
goto accept;
pr_debug("nf_ct_ras: RAS message len=%d ", datalen);
@@ -1707,7 +1707,7 @@ static int ras_help(struct sk_buff **pskb, unsigned int protoff,
}
/* Process RAS message */
- if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0)
+ if (process_ras(skb, ct, ctinfo, &data, &ras) < 0)
goto drop;
accept:
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 1562ca97a34..dfaed4ba83c 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -30,7 +30,7 @@ static unsigned int dcc_timeout __read_mostly = 300;
static char *irc_buffer;
static DEFINE_SPINLOCK(irc_buffer_lock);
-unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
@@ -89,7 +89,7 @@ static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
return 0;
}
-static int help(struct sk_buff **pskb, unsigned int protoff,
+static int help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
unsigned int dataoff;
@@ -116,22 +116,22 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
return NF_ACCEPT;
/* Not a full tcp header? */
- th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
/* No data? */
dataoff = protoff + th->doff*4;
- if (dataoff >= (*pskb)->len)
+ if (dataoff >= skb->len)
return NF_ACCEPT;
spin_lock_bh(&irc_buffer_lock);
- ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff,
+ ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
irc_buffer);
BUG_ON(ib_ptr == NULL);
data = ib_ptr;
- data_limit = ib_ptr + (*pskb)->len - dataoff;
+ data_limit = ib_ptr + skb->len - dataoff;
/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
* 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
@@ -143,7 +143,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
data += 5;
/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
pr_debug("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
NIPQUAD(iph->saddr), ntohs(th->source),
NIPQUAD(iph->daddr), ntohs(th->dest));
@@ -193,7 +193,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
if (nf_nat_irc && ct->status & IPS_NAT_MASK)
- ret = nf_nat_irc(pskb, ctinfo,
+ ret = nf_nat_irc(skb, ctinfo,
addr_beg_p - ib_ptr,
addr_end_p - addr_beg_p,
exp);
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 1d59fabeb5f..9810d81e2a0 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -42,17 +42,17 @@ static unsigned int timeout __read_mostly = 3;
module_param(timeout, uint, 0400);
MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
-static int help(struct sk_buff **pskb, unsigned int protoff,
+static int help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
struct nf_conntrack_expect *exp;
- struct iphdr *iph = ip_hdr(*pskb);
- struct rtable *rt = (struct rtable *)(*pskb)->dst;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = (struct rtable *)skb->dst;
struct in_device *in_dev;
__be32 mask = 0;
/* we're only interested in locally generated packets */
- if ((*pskb)->sk == NULL)
+ if (skb->sk == NULL)
goto out;
if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
goto out;
@@ -91,7 +91,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
nf_ct_expect_related(exp);
nf_ct_expect_put(exp);
- nf_ct_refresh(ct, *pskb, timeout * HZ);
+ nf_ct_refresh(ct, skb, timeout * HZ);
out:
return NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index b0804199ab5..099b6df3e2b 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -41,14 +41,14 @@ MODULE_ALIAS("ip_conntrack_pptp");
static DEFINE_SPINLOCK(nf_pptp_lock);
int
-(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb,
+(*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_outbound);
int
-(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb,
+(*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq) __read_mostly;
@@ -254,7 +254,7 @@ out_unexpect_orig:
}
static inline int
-pptp_inbound_pkt(struct sk_buff **pskb,
+pptp_inbound_pkt(struct sk_buff *skb,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq,
unsigned int reqlen,
@@ -367,7 +367,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound);
if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK)
- return nf_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq);
+ return nf_nat_pptp_inbound(skb, ct, ctinfo, ctlh, pptpReq);
return NF_ACCEPT;
invalid:
@@ -380,7 +380,7 @@ invalid:
}
static inline int
-pptp_outbound_pkt(struct sk_buff **pskb,
+pptp_outbound_pkt(struct sk_buff *skb,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq,
unsigned int reqlen,
@@ -462,7 +462,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
nf_nat_pptp_outbound = rcu_dereference(nf_nat_pptp_hook_outbound);
if (nf_nat_pptp_outbound && ct->status & IPS_NAT_MASK)
- return nf_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq);
+ return nf_nat_pptp_outbound(skb, ct, ctinfo, ctlh, pptpReq);
return NF_ACCEPT;
invalid:
@@ -492,7 +492,7 @@ static const unsigned int pptp_msg_size[] = {
/* track caller id inside control connection, call expect_related */
static int
-conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
+conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
@@ -502,7 +502,7 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
struct pptp_pkt_hdr _pptph, *pptph;
struct PptpControlHeader _ctlh, *ctlh;
union pptp_ctrl_union _pptpReq, *pptpReq;
- unsigned int tcplen = (*pskb)->len - protoff;
+ unsigned int tcplen = skb->len - protoff;
unsigned int datalen, reqlen, nexthdr_off;
int oldsstate, oldcstate;
int ret;
@@ -514,12 +514,12 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
return NF_ACCEPT;
nexthdr_off = protoff;
- tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph);
+ tcph = skb_header_pointer(skb, nexthdr_off, sizeof(_tcph), &_tcph);
BUG_ON(!tcph);
nexthdr_off += tcph->doff * 4;
datalen = tcplen - tcph->doff * 4;
- pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
+ pptph = skb_header_pointer(skb, nexthdr_off, sizeof(_pptph), &_pptph);
if (!pptph) {
pr_debug("no full PPTP header, can't track\n");
return NF_ACCEPT;
@@ -534,7 +534,7 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
return NF_ACCEPT;
}
- ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
+ ctlh = skb_header_pointer(skb, nexthdr_off, sizeof(_ctlh), &_ctlh);
if (!ctlh)
return NF_ACCEPT;
nexthdr_off += sizeof(_ctlh);
@@ -547,7 +547,7 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
if (reqlen > sizeof(*pptpReq))
reqlen = sizeof(*pptpReq);
- pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
+ pptpReq = skb_header_pointer(skb, nexthdr_off, reqlen, &_pptpReq);
if (!pptpReq)
return NF_ACCEPT;
@@ -560,11 +560,11 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
* established from PNS->PAC. However, RFC makes no guarantee */
if (dir == IP_CT_DIR_ORIGINAL)
/* client -> server (PNS -> PAC) */
- ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
+ ret = pptp_outbound_pkt(skb, ctlh, pptpReq, reqlen, ct,
ctinfo);
else
/* server -> client (PAC -> PNS) */
- ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
+ ret = pptp_inbound_pkt(skb, ctlh, pptpReq, reqlen, ct,
ctinfo);
pr_debug("sstate: %d->%d, cstate: %d->%d\n",
oldsstate, info->sstate, oldcstate, info->cstate);
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index 355d371bac9..b5a16c6e21c 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -56,7 +56,7 @@ struct sane_reply_net_start {
/* other fields aren't interesting for conntrack */
};
-static int help(struct sk_buff **pskb,
+static int help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -80,19 +80,19 @@ static int help(struct sk_buff **pskb,
return NF_ACCEPT;
/* Not a full tcp header? */
- th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
/* No data? */
dataoff = protoff + th->doff * 4;
- if (dataoff >= (*pskb)->len)
+ if (dataoff >= skb->len)
return NF_ACCEPT;
- datalen = (*pskb)->len - dataoff;
+ datalen = skb->len - dataoff;
spin_lock_bh(&nf_sane_lock);
- sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer);
+ sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
BUG_ON(sb_ptr == NULL);
if (dir == IP_CT_DIR_ORIGINAL) {
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index d449fa47491..8f8b5a48df3 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -36,13 +36,13 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT;
module_param(sip_timeout, uint, 0600);
MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
-unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char **dptr) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
-unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
const char *dptr) __read_mostly;
@@ -363,7 +363,7 @@ int ct_sip_get_info(struct nf_conn *ct,
}
EXPORT_SYMBOL_GPL(ct_sip_get_info);
-static int set_expected_rtp(struct sk_buff **pskb,
+static int set_expected_rtp(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
union nf_conntrack_address *addr,
@@ -385,7 +385,7 @@ static int set_expected_rtp(struct sk_buff **pskb,
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_sdp(pskb, ctinfo, exp, dptr);
+ ret = nf_nat_sdp(skb, ctinfo, exp, dptr);
else {
if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
@@ -397,7 +397,7 @@ static int set_expected_rtp(struct sk_buff **pskb,
return ret;
}
-static int sip_help(struct sk_buff **pskb,
+static int sip_help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -414,13 +414,13 @@ static int sip_help(struct sk_buff **pskb,
/* No Data ? */
dataoff = protoff + sizeof(struct udphdr);
- if (dataoff >= (*pskb)->len)
+ if (dataoff >= skb->len)
return NF_ACCEPT;
- nf_ct_refresh(ct, *pskb, sip_timeout * HZ);
+ nf_ct_refresh(ct, skb, sip_timeout * HZ);
- if (!skb_is_nonlinear(*pskb))
- dptr = (*pskb)->data + dataoff;
+ if (!skb_is_nonlinear(skb))
+ dptr = skb->data + dataoff;
else {
pr_debug("Copy of skbuff not supported yet.\n");
goto out;
@@ -428,13 +428,13 @@ static int sip_help(struct sk_buff **pskb,
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
- if (!nf_nat_sip(pskb, ctinfo, ct, &dptr)) {
+ if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) {
ret = NF_DROP;
goto out;
}
}
- datalen = (*pskb)->len - dataoff;
+ datalen = skb->len - dataoff;
if (datalen < sizeof("SIP/2.0 200") - 1)
goto out;
@@ -464,7 +464,7 @@ static int sip_help(struct sk_buff **pskb,
ret = NF_DROP;
goto out;
}
- ret = set_expected_rtp(pskb, ct, ctinfo, &addr,
+ ret = set_expected_rtp(skb, ct, ctinfo, &addr,
htons(port), dptr);
}
}
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index cc19506cf2f..e894aa1ff3a 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -29,12 +29,12 @@ static int ports_c;
module_param_array(ports, ushort, &ports_c, 0400);
MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
-unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb,
+unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_tftp_hook);
-static int tftp_help(struct sk_buff **pskb,
+static int tftp_help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
@@ -46,7 +46,7 @@ static int tftp_help(struct sk_buff **pskb,
int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
typeof(nf_nat_tftp_hook) nf_nat_tftp;
- tfh = skb_header_pointer(*pskb, protoff + sizeof(struct udphdr),
+ tfh = skb_header_pointer(skb, protoff + sizeof(struct udphdr),
sizeof(_tftph), &_tftph);
if (tfh == NULL)
return NF_ACCEPT;
@@ -70,7 +70,7 @@ static int tftp_help(struct sk_buff **pskb,
nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_tftp(pskb, ctinfo, exp);
+ ret = nf_nat_tftp(skb, ctinfo, exp);
else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
nf_ct_expect_put(exp);
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
index 0df7fff196a..196269c1e58 100644
--- a/net/netfilter/nf_internals.h
+++ b/net/netfilter/nf_internals.h
@@ -14,7 +14,7 @@
/* core.c */
extern unsigned int nf_iterate(struct list_head *head,
- struct sk_buff **skb,
+ struct sk_buff *skb,
int hook,
const struct net_device *indev,
const struct net_device *outdev,
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index a481a349f7b..0cef1433d66 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -256,14 +256,14 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
if (verdict == NF_ACCEPT) {
afinfo = nf_get_afinfo(info->pf);
- if (!afinfo || afinfo->reroute(&skb, info) < 0)
+ if (!afinfo || afinfo->reroute(skb, info) < 0)
verdict = NF_DROP;
}
if (verdict == NF_ACCEPT) {
next_hook:
verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
- &skb, info->hook,
+ skb, info->hook,
info->indev, info->outdev, &elem,
info->okfn, INT_MIN);
}
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 49f0480afe0..3ceeffcf6f9 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -617,6 +617,7 @@ static int
nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
{
int diff;
+ int err;
diff = data_len - e->skb->len;
if (diff < 0) {
@@ -626,25 +627,18 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
if (data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- struct sk_buff *newskb;
-
- newskb = skb_copy_expand(e->skb,
- skb_headroom(e->skb),
- diff,
- GFP_ATOMIC);
- if (newskb == NULL) {
+ err = pskb_expand_head(e->skb, 0,
+ diff - skb_tailroom(e->skb),
+ GFP_ATOMIC);
+ if (err) {
printk(KERN_WARNING "nf_queue: OOM "
"in mangle, dropping packet\n");
- return -ENOMEM;
+ return err;
}
- if (e->skb->sk)
- skb_set_owner_w(newskb, e->skb->sk);
- kfree_skb(e->skb);
- e->skb = newskb;
}
skb_put(e->skb, diff);
}
- if (!skb_make_writable(&e->skb, data_len))
+ if (!skb_make_writable(e->skb, data_len))
return -ENOMEM;
skb_copy_to_linear_data(e->skb, data, data_len);
e->skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 07a1b966500..77eeae658d4 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -27,7 +27,7 @@ MODULE_ALIAS("ipt_CLASSIFY");
MODULE_ALIAS("ip6t_CLASSIFY");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -36,7 +36,7 @@ target(struct sk_buff **pskb,
{
const struct xt_classify_target_info *clinfo = targinfo;
- (*pskb)->priority = clinfo->priority;
+ skb->priority = clinfo->priority;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index 7043c2757e0..8cc324b159e 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -34,7 +34,7 @@ MODULE_ALIAS("ip6t_CONNMARK");
#include <net/netfilter/nf_conntrack_ecache.h>
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -48,28 +48,28 @@ target(struct sk_buff **pskb,
u_int32_t mark;
u_int32_t newmark;
- ct = nf_ct_get(*pskb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
if (ct) {
switch(markinfo->mode) {
case XT_CONNMARK_SET:
newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
if (newmark != ct->mark) {
ct->mark = newmark;
- nf_conntrack_event_cache(IPCT_MARK, *pskb);
+ nf_conntrack_event_cache(IPCT_MARK, skb);
}
break;
case XT_CONNMARK_SAVE:
newmark = (ct->mark & ~markinfo->mask) |
- ((*pskb)->mark & markinfo->mask);
+ (skb->mark & markinfo->mask);
if (ct->mark != newmark) {
ct->mark = newmark;
- nf_conntrack_event_cache(IPCT_MARK, *pskb);
+ nf_conntrack_event_cache(IPCT_MARK, skb);
}
break;
case XT_CONNMARK_RESTORE:
- mark = (*pskb)->mark;
+ mark = skb->mark;
diff = (ct->mark ^ mark) & markinfo->mask;
- (*pskb)->mark = mark ^ diff;
+ skb->mark = mark ^ diff;
break;
}
}
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 63d73138c1b..021b5c8d20e 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -61,12 +61,11 @@ static void secmark_restore(struct sk_buff *skb)
}
}
-static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+static unsigned int target(struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
- struct sk_buff *skb = *pskb;
const struct xt_connsecmark_target_info *info = targinfo;
switch (info->mode) {
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
index 798ab731009..6322a933ab7 100644
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -25,7 +25,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_DSCP");
MODULE_ALIAS("ip6t_DSCP");
-static unsigned int target(struct sk_buff **pskb,
+static unsigned int target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -33,20 +33,20 @@ static unsigned int target(struct sk_buff **pskb,
const void *targinfo)
{
const struct xt_DSCP_info *dinfo = targinfo;
- u_int8_t dscp = ipv4_get_dsfield(ip_hdr(*pskb)) >> XT_DSCP_SHIFT;
+ u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
if (dscp != dinfo->dscp) {
- if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
- ipv4_change_dsfield(ip_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
+ ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
}
-static unsigned int target6(struct sk_buff **pskb,
+static unsigned int target6(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -54,13 +54,13 @@ static unsigned int target6(struct sk_buff **pskb,
const void *targinfo)
{
const struct xt_DSCP_info *dinfo = targinfo;
- u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(*pskb)) >> XT_DSCP_SHIFT;
+ u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
if (dscp != dinfo->dscp) {
- if (!skb_make_writable(pskb, sizeof(struct ipv6hdr)))
+ if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
return NF_DROP;
- ipv6_change_dsfield(ipv6_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
+ ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index f30fe0baf7d..bc6503d77d7 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -22,7 +22,7 @@ MODULE_ALIAS("ipt_MARK");
MODULE_ALIAS("ip6t_MARK");
static unsigned int
-target_v0(struct sk_buff **pskb,
+target_v0(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -31,12 +31,12 @@ target_v0(struct sk_buff **pskb,
{
const struct xt_mark_target_info *markinfo = targinfo;
- (*pskb)->mark = markinfo->mark;
+ skb->mark = markinfo->mark;
return XT_CONTINUE;
}
static unsigned int
-target_v1(struct sk_buff **pskb,
+target_v1(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -52,15 +52,15 @@ target_v1(struct sk_buff **pskb,
break;
case XT_MARK_AND:
- mark = (*pskb)->mark & markinfo->mark;
+ mark = skb->mark & markinfo->mark;
break;
case XT_MARK_OR:
- mark = (*pskb)->mark | markinfo->mark;
+ mark = skb->mark | markinfo->mark;
break;
}
- (*pskb)->mark = mark;
+ skb->mark = mark;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c
index d3594c7ccb2..9fb449ffbf8 100644
--- a/net/netfilter/xt_NFLOG.c
+++ b/net/netfilter/xt_NFLOG.c
@@ -20,7 +20,7 @@ MODULE_ALIAS("ipt_NFLOG");
MODULE_ALIAS("ip6t_NFLOG");
static unsigned int
-nflog_target(struct sk_buff **pskb,
+nflog_target(struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
unsigned int hooknum, const struct xt_target *target,
const void *targinfo)
@@ -33,7 +33,7 @@ nflog_target(struct sk_buff **pskb,
li.u.ulog.group = info->group;
li.u.ulog.qthreshold = info->threshold;
- nf_log_packet(target->family, hooknum, *pskb, in, out, &li,
+ nf_log_packet(target->family, hooknum, skb, in, out, &li,
"%s", info->prefix);
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 13f59f3e8c3..c3984e9f766 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -24,7 +24,7 @@ MODULE_ALIAS("ip6t_NFQUEUE");
MODULE_ALIAS("arpt_NFQUEUE");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index fec1aefb1c3..4976ce18661 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -12,7 +12,7 @@ MODULE_ALIAS("ipt_NOTRACK");
MODULE_ALIAS("ip6t_NOTRACK");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -20,16 +20,16 @@ target(struct sk_buff **pskb,
const void *targinfo)
{
/* Previously seen (loopback)? Ignore. */
- if ((*pskb)->nfct != NULL)
+ if (skb->nfct != NULL)
return XT_CONTINUE;
/* Attach fake conntrack entry.
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
- (*pskb)->nfct = &nf_conntrack_untracked.ct_general;
- (*pskb)->nfctinfo = IP_CT_NEW;
- nf_conntrack_get((*pskb)->nfct);
+ skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfctinfo = IP_CT_NEW;
+ nf_conntrack_get(skb->nfct);
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index c83779a941a..235806eb6ec 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -28,7 +28,7 @@ MODULE_ALIAS("ip6t_SECMARK");
static u8 mode;
-static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+static unsigned int target(struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
@@ -47,7 +47,7 @@ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
BUG();
}
- (*pskb)->secmark = secmark;
+ skb->secmark = secmark;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index d40f7e4b128..07435a602b1 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -39,7 +39,7 @@ optlen(const u_int8_t *opt, unsigned int offset)
}
static int
-tcpmss_mangle_packet(struct sk_buff **pskb,
+tcpmss_mangle_packet(struct sk_buff *skb,
const struct xt_tcpmss_info *info,
unsigned int tcphoff,
unsigned int minlen)
@@ -50,11 +50,11 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
u16 newmss;
u8 *opt;
- if (!skb_make_writable(pskb, (*pskb)->len))
+ if (!skb_make_writable(skb, skb->len))
return -1;
- tcplen = (*pskb)->len - tcphoff;
- tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
+ tcplen = skb->len - tcphoff;
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
/* Since it passed flags test in tcp match, we know it is is
not a fragment, and has data >= tcp header length. SYN
@@ -64,19 +64,19 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
if (tcplen != tcph->doff*4) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n",
- (*pskb)->len);
+ skb->len);
return -1;
}
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
- if (dst_mtu((*pskb)->dst) <= minlen) {
+ if (dst_mtu(skb->dst) <= minlen) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: "
"unknown or invalid path-MTU (%u)\n",
- dst_mtu((*pskb)->dst));
+ dst_mtu(skb->dst));
return -1;
}
- newmss = dst_mtu((*pskb)->dst) - minlen;
+ newmss = dst_mtu(skb->dst) - minlen;
} else
newmss = info->mss;
@@ -95,7 +95,7 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
opt[i+2] = (newmss & 0xff00) >> 8;
opt[i+3] = newmss & 0x00ff;
- nf_proto_csum_replace2(&tcph->check, *pskb,
+ nf_proto_csum_replace2(&tcph->check, skb,
htons(oldmss), htons(newmss), 0);
return 0;
}
@@ -104,57 +104,53 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
/*
* MSS Option not found ?! add it..
*/
- if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
- struct sk_buff *newskb;
-
- newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
- TCPOLEN_MSS, GFP_ATOMIC);
- if (!newskb)
+ if (skb_tailroom(skb) < TCPOLEN_MSS) {
+ if (pskb_expand_head(skb, 0,
+ TCPOLEN_MSS - skb_tailroom(skb),
+ GFP_ATOMIC))
return -1;
- kfree_skb(*pskb);
- *pskb = newskb;
- tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
}
- skb_put((*pskb), TCPOLEN_MSS);
+ skb_put(skb, TCPOLEN_MSS);
opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
- nf_proto_csum_replace2(&tcph->check, *pskb,
+ nf_proto_csum_replace2(&tcph->check, skb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8;
opt[3] = newmss & 0x00ff;
- nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
+ nf_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0);
oldval = ((__be16 *)tcph)[6];
tcph->doff += TCPOLEN_MSS/4;
- nf_proto_csum_replace2(&tcph->check, *pskb,
+ nf_proto_csum_replace2(&tcph->check, skb,
oldval, ((__be16 *)tcph)[6], 0);
return TCPOLEN_MSS;
}
static unsigned int
-xt_tcpmss_target4(struct sk_buff **pskb,
+xt_tcpmss_target4(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
- struct iphdr *iph = ip_hdr(*pskb);
+ struct iphdr *iph = ip_hdr(skb);
__be16 newlen;
int ret;
- ret = tcpmss_mangle_packet(pskb, targinfo, iph->ihl * 4,
+ ret = tcpmss_mangle_packet(skb, targinfo, iph->ihl * 4,
sizeof(*iph) + sizeof(struct tcphdr));
if (ret < 0)
return NF_DROP;
if (ret > 0) {
- iph = ip_hdr(*pskb);
+ iph = ip_hdr(skb);
newlen = htons(ntohs(iph->tot_len) + ret);
nf_csum_replace2(&iph->check, iph->tot_len, newlen);
iph->tot_len = newlen;
@@ -164,30 +160,30 @@ xt_tcpmss_target4(struct sk_buff **pskb,
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
static unsigned int
-xt_tcpmss_target6(struct sk_buff **pskb,
+xt_tcpmss_target6(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
- struct ipv6hdr *ipv6h = ipv6_hdr(*pskb);
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
u8 nexthdr;
int tcphoff;
int ret;
nexthdr = ipv6h->nexthdr;
- tcphoff = ipv6_skip_exthdr(*pskb, sizeof(*ipv6h), &nexthdr);
+ tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
if (tcphoff < 0) {
WARN_ON(1);
return NF_DROP;
}
- ret = tcpmss_mangle_packet(pskb, targinfo, tcphoff,
+ ret = tcpmss_mangle_packet(skb, targinfo, tcphoff,
sizeof(*ipv6h) + sizeof(struct tcphdr));
if (ret < 0)
return NF_DROP;
if (ret > 0) {
- ipv6h = ipv6_hdr(*pskb);
+ ipv6h = ipv6_hdr(skb);
ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
}
return XT_CONTINUE;
diff --git a/net/netfilter/xt_TRACE.c b/net/netfilter/xt_TRACE.c
index 4df2dedcc0b..26c5d08ab2c 100644
--- a/net/netfilter/xt_TRACE.c
+++ b/net/netfilter/xt_TRACE.c
@@ -10,14 +10,14 @@ MODULE_ALIAS("ipt_TRACE");
MODULE_ALIAS("ip6t_TRACE");
static unsigned int
-target(struct sk_buff **pskb,
+target(struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
- (*pskb)->nf_trace = 1;
+ skb->nf_trace = 1;
return XT_CONTINUE;
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index c776bcd9f82..98e313e5e59 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1378,6 +1378,8 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
nl_table[unit].cb_mutex = cb_mutex;
nl_table[unit].module = module;
nl_table[unit].registered = 1;
+ } else {
+ kfree(listeners);
}
netlink_table_ungrab();
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 6b407ece953..fa006e06ce3 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -202,11 +202,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
/* yes, we have to worry about both in and out dev
worry later - danger - this API seems to have changed
from earlier kernels */
-
- /* iptables targets take a double skb pointer in case the skb
- * needs to be replaced. We don't own the skb, so this must not
- * happen. The pskb_expand_head above should make sure of this */
- ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL,
+ ret = ipt->tcfi_t->u.kernel.target->target(skb, skb->dev, NULL,
ipt->tcfi_hook,
ipt->tcfi_t->u.kernel.target,
ipt->tcfi_t->data);
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 2d32fd27496..3f8335e6ea2 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -205,20 +205,19 @@ static unsigned int ingress_drop(struct Qdisc *sch)
#ifndef CONFIG_NET_CLS_ACT
#ifdef CONFIG_NETFILTER
static unsigned int
-ing_hook(unsigned int hook, struct sk_buff **pskb,
+ing_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *indev,
const struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
struct Qdisc *q;
- struct sk_buff *skb = *pskb;
struct net_device *dev = skb->dev;
int fwres=NF_ACCEPT;
DPRINTK("ing_hook: skb %s dev=%s len=%u\n",
skb->sk ? "(owned)" : "(unowned)",
- skb->dev ? (*pskb)->dev->name : "(no dev)",
+ skb->dev ? skb->dev->name : "(no dev)",
skb->len);
if (dev->qdisc_ingress) {
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 9de3ddaa276..eb4deaf5891 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -954,9 +954,9 @@ static struct inet_protosw sctpv6_stream_protosw = {
.flags = SCTP_PROTOSW_FLAG,
};
-static int sctp6_rcv(struct sk_buff **pskb)
+static int sctp6_rcv(struct sk_buff *skb)
{
- return sctp_rcv(*pskb) ? -1 : 0;
+ return sctp_rcv(skb) ? -1 : 0;
}
static struct inet6_protocol sctpv6_protocol = {
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 9c6a4b5f626..bd6f42a15a4 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -5058,6 +5058,7 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
+ struct sctp_authchunks __user *p = (void __user *)optval;
struct sctp_authchunks val;
struct sctp_association *asoc;
struct sctp_chunks_param *ch;
@@ -5066,10 +5067,10 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
if (len <= sizeof(struct sctp_authchunks))
return -EINVAL;
- if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
return -EFAULT;
- to = val.gauth_chunks;
+ to = p->gauth_chunks;
asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
if (!asoc)
return -EINVAL;
@@ -5092,6 +5093,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
+ struct sctp_authchunks __user *p = (void __user *)optval;
struct sctp_authchunks val;
struct sctp_association *asoc;
struct sctp_chunks_param *ch;
@@ -5100,10 +5102,10 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
if (len <= sizeof(struct sctp_authchunks))
return -EINVAL;
- if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
return -EFAULT;
- to = val.gauth_chunks;
+ to = p->gauth_chunks;
asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index 8ebfc4db7f5..5c69a725e53 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_SUNRPC) += sunrpc.o
obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
auth.o auth_null.o auth_unix.o \
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 42b3220bed3..8bd074df27d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -42,7 +42,7 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
{
u8 *ptr;
u8 pad;
- int len = buf->len;
+ size_t len = buf->len;
if (len <= buf->head[0].iov_len) {
pad = *(u8 *)(buf->head[0].iov_base + len - 1);
@@ -53,9 +53,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
} else
len -= buf->head[0].iov_len;
if (len <= buf->page_len) {
- int last = (buf->page_base + len - 1)
+ unsigned int last = (buf->page_base + len - 1)
>>PAGE_CACHE_SHIFT;
- int offset = (buf->page_base + len - 1)
+ unsigned int offset = (buf->page_base + len - 1)
& (PAGE_CACHE_SIZE - 1);
ptr = kmap_atomic(buf->pages[last], KM_USER0);
pad = *(ptr + offset);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 7da7050f06c..73940df6c46 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -631,7 +631,8 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
return 0;
}
-/* Verify the checksum on the header and return SVC_OK on success.
+/*
+ * Verify the checksum on the header and return SVC_OK on success.
* Otherwise, return SVC_DROP (in the case of a bad sequence number)
* or return SVC_DENIED and indicate error in authp.
*/
@@ -961,6 +962,78 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
}
/*
+ * Having read the cred already and found we're in the context
+ * initiation case, read the verifier and initiate (or check the results
+ * of) upcalls to userspace for help with context initiation. If
+ * the upcall results are available, write the verifier and result.
+ * Otherwise, drop the request pending an answer to the upcall.
+ */
+static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
+ struct rpc_gss_wire_cred *gc, __be32 *authp)
+{
+ struct kvec *argv = &rqstp->rq_arg.head[0];
+ struct kvec *resv = &rqstp->rq_res.head[0];
+ struct xdr_netobj tmpobj;
+ struct rsi *rsip, rsikey;
+
+ /* Read the verifier; should be NULL: */
+ *authp = rpc_autherr_badverf;
+ if (argv->iov_len < 2 * 4)
+ return SVC_DENIED;
+ if (svc_getnl(argv) != RPC_AUTH_NULL)
+ return SVC_DENIED;
+ if (svc_getnl(argv) != 0)
+ return SVC_DENIED;
+
+ /* Martial context handle and token for upcall: */
+ *authp = rpc_autherr_badcred;
+ if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
+ return SVC_DENIED;
+ memset(&rsikey, 0, sizeof(rsikey));
+ if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
+ return SVC_DROP;
+ *authp = rpc_autherr_badverf;
+ if (svc_safe_getnetobj(argv, &tmpobj)) {
+ kfree(rsikey.in_handle.data);
+ return SVC_DENIED;
+ }
+ if (dup_netobj(&rsikey.in_token, &tmpobj)) {
+ kfree(rsikey.in_handle.data);
+ return SVC_DROP;
+ }
+
+ /* Perform upcall, or find upcall result: */
+ rsip = rsi_lookup(&rsikey);
+ rsi_free(&rsikey);
+ if (!rsip)
+ return SVC_DROP;
+ switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
+ case -EAGAIN:
+ case -ETIMEDOUT:
+ case -ENOENT:
+ /* No upcall result: */
+ return SVC_DROP;
+ case 0:
+ /* Got an answer to the upcall; use it: */
+ if (gss_write_init_verf(rqstp, rsip))
+ return SVC_DROP;
+ if (resv->iov_len + 4 > PAGE_SIZE)
+ return SVC_DROP;
+ svc_putnl(resv, RPC_SUCCESS);
+ if (svc_safe_putnetobj(resv, &rsip->out_handle))
+ return SVC_DROP;
+ if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+ return SVC_DROP;
+ svc_putnl(resv, rsip->major_status);
+ svc_putnl(resv, rsip->minor_status);
+ svc_putnl(resv, GSS_SEQ_WIN);
+ if (svc_safe_putnetobj(resv, &rsip->out_token))
+ return SVC_DROP;
+ }
+ return SVC_COMPLETE;
+}
+
+/*
* Accept an rpcsec packet.
* If context establishment, punt to user space
* If data exchange, verify/decrypt
@@ -974,11 +1047,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
u32 crlen;
- struct xdr_netobj tmpobj;
struct gss_svc_data *svcdata = rqstp->rq_auth_data;
struct rpc_gss_wire_cred *gc;
struct rsc *rsci = NULL;
- struct rsi *rsip, rsikey;
__be32 *rpcstart;
__be32 *reject_stat = resv->iov_base + resv->iov_len;
int ret;
@@ -1023,30 +1094,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
goto auth_err;
- /*
- * We've successfully parsed the credential. Let's check out the
- * verifier. An AUTH_NULL verifier is allowed (and required) for
- * INIT and CONTINUE_INIT requests. AUTH_RPCSEC_GSS is required for
- * PROC_DATA and PROC_DESTROY.
- *
- * AUTH_NULL verifier is 0 (AUTH_NULL), 0 (length).
- * AUTH_RPCSEC_GSS verifier is:
- * 6 (AUTH_RPCSEC_GSS), length, checksum.
- * checksum is calculated over rpcheader from xid up to here.
- */
*authp = rpc_autherr_badverf;
switch (gc->gc_proc) {
case RPC_GSS_PROC_INIT:
case RPC_GSS_PROC_CONTINUE_INIT:
- if (argv->iov_len < 2 * 4)
- goto auth_err;
- if (svc_getnl(argv) != RPC_AUTH_NULL)
- goto auth_err;
- if (svc_getnl(argv) != 0)
- goto auth_err;
- break;
+ return svcauth_gss_handle_init(rqstp, gc, authp);
case RPC_GSS_PROC_DATA:
case RPC_GSS_PROC_DESTROY:
+ /* Look up the context, and check the verifier: */
*authp = rpcsec_gsserr_credproblem;
rsci = gss_svc_searchbyctx(&gc->gc_ctx);
if (!rsci)
@@ -1067,51 +1122,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
/* now act upon the command: */
switch (gc->gc_proc) {
- case RPC_GSS_PROC_INIT:
- case RPC_GSS_PROC_CONTINUE_INIT:
- *authp = rpc_autherr_badcred;
- if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
- goto auth_err;
- memset(&rsikey, 0, sizeof(rsikey));
- if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
- goto drop;
- *authp = rpc_autherr_badverf;
- if (svc_safe_getnetobj(argv, &tmpobj)) {
- kfree(rsikey.in_handle.data);
- goto auth_err;
- }
- if (dup_netobj(&rsikey.in_token, &tmpobj)) {
- kfree(rsikey.in_handle.data);
- goto drop;
- }
-
- rsip = rsi_lookup(&rsikey);
- rsi_free(&rsikey);
- if (!rsip) {
- goto drop;
- }
- switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
- case -EAGAIN:
- case -ETIMEDOUT:
- case -ENOENT:
- goto drop;
- case 0:
- if (gss_write_init_verf(rqstp, rsip))
- goto drop;
- if (resv->iov_len + 4 > PAGE_SIZE)
- goto drop;
- svc_putnl(resv, RPC_SUCCESS);
- if (svc_safe_putnetobj(resv, &rsip->out_handle))
- goto drop;
- if (resv->iov_len + 3 * 4 > PAGE_SIZE)
- goto drop;
- svc_putnl(resv, rsip->major_status);
- svc_putnl(resv, rsip->minor_status);
- svc_putnl(resv, GSS_SEQ_WIN);
- if (svc_safe_putnetobj(resv, &rsip->out_token))
- goto drop;
- }
- goto complete;
case RPC_GSS_PROC_DESTROY:
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
@@ -1158,7 +1168,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
goto out;
}
auth_err:
- /* Restore write pointer to original value: */
+ /* Restore write pointer to its original value: */
xdr_ressize_check(rqstp, reject_stat);
ret = SVC_DENIED;
goto out;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 52429b1ffcc..76be83ee4b0 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -127,7 +127,14 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
struct rpc_clnt *clnt = NULL;
struct rpc_auth *auth;
int err;
- int len;
+ size_t len;
+
+ /* sanity check the name before trying to print it */
+ err = -EINVAL;
+ len = strlen(servname);
+ if (len > RPC_MAXNETNAMELEN)
+ goto out_no_rpciod;
+ len++;
dprintk("RPC: creating %s client for %s (xprt %p)\n",
program->name, servname, xprt);
@@ -148,7 +155,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
clnt->cl_parent = clnt;
clnt->cl_server = clnt->cl_inline_name;
- len = strlen(servname) + 1;
if (len > sizeof(clnt->cl_inline_name)) {
char *buf = kmalloc(len, GFP_KERNEL);
if (buf != 0)
@@ -234,8 +240,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{
struct rpc_xprt *xprt;
struct rpc_clnt *clnt;
- struct rpc_xprtsock_create xprtargs = {
- .proto = args->protocol,
+ struct xprt_create xprtargs = {
+ .ident = args->protocol,
.srcaddr = args->saddress,
.dstaddr = args->address,
.addrlen = args->addrsize,
@@ -253,7 +259,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
*/
if (args->servername == NULL) {
struct sockaddr_in *addr =
- (struct sockaddr_in *) &args->address;
+ (struct sockaddr_in *) args->address;
snprintf(servername, sizeof(servername), NIPQUAD_FMT,
NIPQUAD(addr->sin_addr.s_addr));
args->servername = servername;
@@ -269,9 +275,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
xprt->resvport = 0;
- dprintk("RPC: creating %s client for %s (xprt %p)\n",
- args->program->name, args->servername, xprt);
-
clnt = rpc_new_client(xprt, args->servername, args->program,
args->version, args->authflavor);
if (IS_ERR(clnt))
@@ -439,7 +442,7 @@ rpc_release_client(struct rpc_clnt *clnt)
*/
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
struct rpc_program *program,
- int vers)
+ u32 vers)
{
struct rpc_clnt *clnt;
struct rpc_version *version;
@@ -843,8 +846,7 @@ call_allocate(struct rpc_task *task)
dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
if (RPC_IS_ASYNC(task) || !signalled()) {
- xprt_release(task);
- task->tk_action = call_reserve;
+ task->tk_action = call_allocate;
rpc_delay(task, HZ>>4);
return;
}
@@ -871,6 +873,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
buf->head[0].iov_len = len;
buf->tail[0].iov_len = 0;
buf->page_len = 0;
+ buf->flags = 0;
buf->len = 0;
buf->buflen = len;
}
@@ -937,7 +940,7 @@ call_bind(struct rpc_task *task)
static void
call_bind_status(struct rpc_task *task)
{
- int status = -EACCES;
+ int status = -EIO;
if (task->tk_status >= 0) {
dprint_status(task);
@@ -947,9 +950,20 @@ call_bind_status(struct rpc_task *task)
}
switch (task->tk_status) {
+ case -EAGAIN:
+ dprintk("RPC: %5u rpcbind waiting for another request "
+ "to finish\n", task->tk_pid);
+ /* avoid busy-waiting here -- could be a network outage. */
+ rpc_delay(task, 5*HZ);
+ goto retry_timeout;
case -EACCES:
dprintk("RPC: %5u remote rpcbind: RPC program/version "
"unavailable\n", task->tk_pid);
+ /* fail immediately if this is an RPC ping */
+ if (task->tk_msg.rpc_proc->p_proc == 0) {
+ status = -EOPNOTSUPP;
+ break;
+ }
rpc_delay(task, 3*HZ);
goto retry_timeout;
case -ETIMEDOUT:
@@ -957,6 +971,7 @@ call_bind_status(struct rpc_task *task)
task->tk_pid);
goto retry_timeout;
case -EPFNOSUPPORT:
+ /* server doesn't support any rpcbind version we know of */
dprintk("RPC: %5u remote rpcbind service unavailable\n",
task->tk_pid);
break;
@@ -969,7 +984,6 @@ call_bind_status(struct rpc_task *task)
default:
dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
task->tk_pid, -task->tk_status);
- status = -EIO;
}
rpc_exit(task, status);
@@ -1257,7 +1271,6 @@ call_refresh(struct rpc_task *task)
{
dprint_status(task);
- xprt_release(task); /* Must do to obtain new XID */
task->tk_action = call_refreshresult;
task->tk_status = 0;
task->tk_client->cl_stats->rpcauthrefresh++;
@@ -1375,6 +1388,8 @@ call_verify(struct rpc_task *task)
dprintk("RPC: %5u %s: retry stale creds\n",
task->tk_pid, __FUNCTION__);
rpcauth_invalcred(task);
+ /* Ensure we obtain a new XID! */
+ xprt_release(task);
task->tk_action = call_refresh;
goto out_retry;
case RPC_AUTH_BADCRED:
@@ -1523,13 +1538,18 @@ void rpc_show_tasks(void)
spin_lock(&clnt->cl_lock);
list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
const char *rpc_waitq = "none";
+ int proc;
+
+ if (t->tk_msg.rpc_proc)
+ proc = t->tk_msg.rpc_proc->p_proc;
+ else
+ proc = -1;
if (RPC_IS_QUEUED(t))
rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
- t->tk_pid,
- (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
+ t->tk_pid, proc,
t->tk_flags, t->tk_status,
t->tk_client,
(t->tk_client ? t->tk_client->cl_prog : 0),
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 669e12a4ed1..c8433e8865a 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -14,7 +14,7 @@
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/kernel.h>
#include <asm/ioctls.h>
@@ -329,6 +329,7 @@ rpc_show_info(struct seq_file *m, void *v)
clnt->cl_prog, clnt->cl_vers);
seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
+ seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
return 0;
}
@@ -585,6 +586,7 @@ rpc_populate(struct dentry *parent,
if (S_ISDIR(mode))
inc_nlink(dir);
d_add(dentry, inode);
+ fsnotify_create(dir, dentry);
}
mutex_unlock(&dir->i_mutex);
return 0;
@@ -606,7 +608,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
inode->i_ino = iunique(dir->i_sb, 100);
d_instantiate(dentry, inode);
inc_nlink(dir);
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_mkdir(dir, dentry);
return 0;
out_err:
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
@@ -748,7 +750,7 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi
rpci->flags = flags;
rpci->ops = ops;
rpci->nkern_readwriters = 1;
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_create(dir, dentry);
dget(dentry);
out:
mutex_unlock(&dir->i_mutex);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index d1740dbab99..a05493aedb6 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -16,11 +16,14 @@
#include <linux/types.h>
#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/xprtsock.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_BIND
@@ -91,26 +94,6 @@ enum {
#define RPCB_MAXADDRLEN (128u)
/*
- * r_netid
- *
- * Quoting RFC 3530, section 2.2:
- *
- * For TCP over IPv4 the value of r_netid is the string "tcp". For UDP
- * over IPv4 the value of r_netid is the string "udp".
- *
- * ...
- *
- * For TCP over IPv6 the value of r_netid is the string "tcp6". For UDP
- * over IPv6 the value of r_netid is the string "udp6".
- */
-#define RPCB_NETID_UDP "\165\144\160" /* "udp" */
-#define RPCB_NETID_TCP "\164\143\160" /* "tcp" */
-#define RPCB_NETID_UDP6 "\165\144\160\066" /* "udp6" */
-#define RPCB_NETID_TCP6 "\164\143\160\066" /* "tcp6" */
-
-#define RPCB_MAXNETIDLEN (4u)
-
-/*
* r_owner
*
* The "owner" is allowed to unset a service in the rpcbind database.
@@ -120,7 +103,7 @@ enum {
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
static void rpcb_getport_done(struct rpc_task *, void *);
-extern struct rpc_program rpcb_program;
+static struct rpc_program rpcb_program;
struct rpcbind_args {
struct rpc_xprt * r_xprt;
@@ -137,10 +120,13 @@ struct rpcbind_args {
static struct rpc_procinfo rpcb_procedures2[];
static struct rpc_procinfo rpcb_procedures3[];
-static struct rpcb_info {
+struct rpcb_info {
int rpc_vers;
struct rpc_procinfo * rpc_proc;
-} rpcb_next_version[];
+};
+
+static struct rpcb_info rpcb_next_version[];
+static struct rpcb_info rpcb_next_version6[];
static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
{
@@ -190,7 +176,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
RPC_CLNT_CREATE_INTR),
};
- ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+ switch (srvaddr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
+ break;
+ default:
+ return NULL;
+ }
+
if (!privileged)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
return rpc_create(&args);
@@ -234,7 +230,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
prog, vers, prot, port);
rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
- IPPROTO_UDP, 2, 1);
+ XPRT_TRANSPORT_UDP, 2, 1);
if (IS_ERR(rpcb_clnt))
return PTR_ERR(rpcb_clnt);
@@ -316,6 +312,7 @@ void rpcb_getport_async(struct rpc_task *task)
struct rpc_task *child;
struct sockaddr addr;
int status;
+ struct rpcb_info *info;
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
task->tk_pid, __FUNCTION__,
@@ -325,7 +322,7 @@ void rpcb_getport_async(struct rpc_task *task)
BUG_ON(clnt->cl_parent != clnt);
if (xprt_test_and_set_binding(xprt)) {
- status = -EACCES; /* tell caller to check again */
+ status = -EAGAIN; /* tell caller to check again */
dprintk("RPC: %5u %s: waiting for another binder\n",
task->tk_pid, __FUNCTION__);
goto bailout_nowake;
@@ -343,18 +340,43 @@ void rpcb_getport_async(struct rpc_task *task)
goto bailout_nofree;
}
- if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
+ rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+
+ /* Don't ever use rpcbind v2 for AF_INET6 requests */
+ switch (addr.sa_family) {
+ case AF_INET:
+ info = rpcb_next_version;
+ break;
+ case AF_INET6:
+ info = rpcb_next_version6;
+ break;
+ default:
+ status = -EAFNOSUPPORT;
+ dprintk("RPC: %5u %s: bad address family\n",
+ task->tk_pid, __FUNCTION__);
+ goto bailout_nofree;
+ }
+ if (info[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0;
- status = -EACCES; /* tell caller to try again later */
+ status = -EPFNOSUPPORT;
dprintk("RPC: %5u %s: no more getport versions available\n",
task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
- bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
+ bind_version = info[xprt->bind_index].rpc_vers;
dprintk("RPC: %5u %s: trying rpcbind version %u\n",
task->tk_pid, __FUNCTION__, bind_version);
+ rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
+ bind_version, 0);
+ if (IS_ERR(rpcb_clnt)) {
+ status = PTR_ERR(rpcb_clnt);
+ dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
+ task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+ goto bailout_nofree;
+ }
+
map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
if (!map) {
status = -ENOMEM;
@@ -367,28 +389,19 @@ void rpcb_getport_async(struct rpc_task *task)
map->r_prot = xprt->prot;
map->r_port = 0;
map->r_xprt = xprt_get(xprt);
- map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
- RPCB_NETID_UDP;
- memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
- sizeof(map->r_addr));
+ map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
+ memcpy(map->r_addr,
+ rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
+ sizeof(map->r_addr));
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
- rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
- rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
- if (IS_ERR(rpcb_clnt)) {
- status = PTR_ERR(rpcb_clnt);
- dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
- task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
- goto bailout;
- }
-
child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
rpc_release_client(rpcb_clnt);
if (IS_ERR(child)) {
status = -EIO;
dprintk("RPC: %5u %s: rpc_run_task failed\n",
task->tk_pid, __FUNCTION__);
- goto bailout_nofree;
+ goto bailout;
}
rpc_put_task(child);
@@ -403,6 +416,7 @@ bailout_nofree:
bailout_nowake:
task->tk_status = status;
}
+EXPORT_SYMBOL_GPL(rpcb_getport_async);
/*
* Rpcbind child task calls this callback via tk_exit.
@@ -413,6 +427,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
struct rpc_xprt *xprt = map->r_xprt;
int status = child->tk_status;
+ /* Garbage reply: retry with a lesser rpcbind version */
+ if (status == -EIO)
+ status = -EPROTONOSUPPORT;
+
/* rpcbind server doesn't support this rpcbind protocol version */
if (status == -EPROTONOSUPPORT)
xprt->bind_index++;
@@ -490,16 +508,24 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
unsigned short *portp)
{
char *addr;
- int addr_len, c, i, f, first, val;
+ u32 addr_len;
+ int c, i, f, first, val;
*portp = 0;
- addr_len = (unsigned int) ntohl(*p++);
- if (addr_len > RPCB_MAXADDRLEN) /* sanity */
- return -EINVAL;
-
- dprintk("RPC: rpcb_decode_getaddr returned string: '%s'\n",
- (char *) p);
-
+ addr_len = ntohl(*p++);
+
+ /*
+ * Simple sanity check. The smallest possible universal
+ * address is an IPv4 address string containing 11 bytes.
+ */
+ if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN)
+ goto out_err;
+
+ /*
+ * Start at the end and walk backwards until the first dot
+ * is encountered. When the second dot is found, we have
+ * both parts of the port number.
+ */
addr = (char *)p;
val = 0;
first = 1;
@@ -521,8 +547,19 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
}
}
+ /*
+ * Simple sanity check. If we never saw a dot in the reply,
+ * then this was probably just garbage.
+ */
+ if (first)
+ goto out_err;
+
dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp);
return 0;
+
+out_err:
+ dprintk("RPC: rpcbind server returned malformed reply\n");
+ return -EIO;
}
#define RPCB_program_sz (1u)
@@ -531,7 +568,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
#define RPCB_port_sz (1u)
#define RPCB_boolean_sz (1u)
-#define RPCB_netid_sz (1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
#define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
#define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
@@ -593,6 +630,14 @@ static struct rpcb_info rpcb_next_version[] = {
{ 0, NULL },
};
+static struct rpcb_info rpcb_next_version6[] = {
+#ifdef CONFIG_SUNRPC_BIND34
+ { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
+ { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+#endif
+ { 0, NULL },
+};
+
static struct rpc_version rpcb_version2 = {
.number = 2,
.nrprocs = RPCB_HIGHPROC_2,
@@ -621,7 +666,7 @@ static struct rpc_version *rpcb_version[] = {
static struct rpc_stat rpcb_stats;
-struct rpc_program rpcb_program = {
+static struct rpc_program rpcb_program = {
.name = "rpcbind",
.number = RPCBIND_PROGRAM,
.nrvers = ARRAY_SIZE(rpcb_version),
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 954d7ec86c7..3c773c53e12 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -777,6 +777,7 @@ void *rpc_malloc(struct rpc_task *task, size_t size)
task->tk_pid, size, buf);
return &buf->data;
}
+EXPORT_SYMBOL_GPL(rpc_malloc);
/**
* rpc_free - free buffer allocated via rpc_malloc
@@ -802,6 +803,7 @@ void rpc_free(void *buffer)
else
kfree(buf);
}
+EXPORT_SYMBOL_GPL(rpc_free);
/*
* Creation and deletion of RPC task structures
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index 1d377d1ab7f..97ac45f034d 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -34,6 +34,7 @@ size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
desc->offset += len;
return len;
}
+EXPORT_SYMBOL_GPL(xdr_skb_read_bits);
/**
* xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer
@@ -137,6 +138,7 @@ copy_tail:
out:
return copied;
}
+EXPORT_SYMBOL_GPL(xdr_partial_copy_from_skb);
/**
* csum_partial_copy_to_xdr - checksum and copy data
@@ -179,3 +181,4 @@ no_checksum:
return -1;
return 0;
}
+EXPORT_SYMBOL_GPL(csum_partial_copy_to_xdr);
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 384c4ad5ab8..33d89e842c8 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -20,7 +20,7 @@
#include <linux/sunrpc/auth.h>
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
-
+#include <linux/sunrpc/xprtsock.h>
/* RPC scheduler */
EXPORT_SYMBOL(rpc_execute);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 55ea6df069d..a4a6bf7deaa 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -777,6 +777,30 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
}
/*
+ * Printk the given error with the address of the client that caused it.
+ */
+static int
+__attribute__ ((format (printf, 2, 3)))
+svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+ char buf[RPC_MAX_ADDRBUFLEN];
+
+ if (!net_ratelimit())
+ return 0;
+
+ printk(KERN_WARNING "svc: %s: ",
+ svc_print_addr(rqstp, buf, sizeof(buf)));
+
+ va_start(args, fmt);
+ r = vprintk(fmt, args);
+ va_end(args);
+
+ return r;
+}
+
+/*
* Process the RPC request.
*/
int
@@ -963,14 +987,13 @@ svc_process(struct svc_rqst *rqstp)
return 0;
err_short_len:
- if (net_ratelimit())
- printk("svc: short len %Zd, dropping request\n", argv->iov_len);
+ svc_printk(rqstp, "short len %Zd, dropping request\n",
+ argv->iov_len);
goto dropit; /* drop request */
err_bad_dir:
- if (net_ratelimit())
- printk("svc: bad direction %d, dropping request\n", dir);
+ svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
serv->sv_stats->rpcbadfmt++;
goto dropit; /* drop request */
@@ -1000,8 +1023,7 @@ err_bad_prog:
goto sendit;
err_bad_vers:
- if (net_ratelimit())
- printk("svc: unknown version (%d for prog %d, %s)\n",
+ svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
vers, prog, progp->pg_name);
serv->sv_stats->rpcbadfmt++;
@@ -1011,16 +1033,14 @@ err_bad_vers:
goto sendit;
err_bad_proc:
- if (net_ratelimit())
- printk("svc: unknown procedure (%d)\n", proc);
+ svc_printk(rqstp, "unknown procedure (%d)\n", proc);
serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROC_UNAVAIL);
goto sendit;
err_garbage:
- if (net_ratelimit())
- printk("svc: failed to decode args\n");
+ svc_printk(rqstp, "failed to decode args\n");
rpc_stat = rpc_garbage_args;
err_bad:
diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c
index 8142fdb8a93..31becbf0926 100644
--- a/net/sunrpc/timer.c
+++ b/net/sunrpc/timer.c
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/unistd.h>
+#include <linux/module.h>
#include <linux/sunrpc/clnt.h>
@@ -40,6 +41,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
rt->ntimeouts[i] = 0;
}
}
+EXPORT_SYMBOL_GPL(rpc_init_rtt);
/*
* NB: When computing the smoothed RTT and standard deviation,
@@ -75,6 +77,7 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
if (*sdrtt < RPC_RTO_MIN)
*sdrtt = RPC_RTO_MIN;
}
+EXPORT_SYMBOL_GPL(rpc_update_rtt);
/*
* Estimate rto for an nfs rpc sent via. an unreliable datagram.
@@ -103,3 +106,4 @@ rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
return res;
}
+EXPORT_SYMBOL_GPL(rpc_calc_rto);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index c8c2edccad7..282a9a2ec90 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -62,6 +62,9 @@ static inline void do_xprt_reserve(struct rpc_task *);
static void xprt_connect_status(struct rpc_task *task);
static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
+static spinlock_t xprt_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(xprt_list);
+
/*
* The transport code maintains an estimate on the maximum number of out-
* standing RPC requests, using a smoothed version of the congestion
@@ -81,6 +84,78 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
/**
+ * xprt_register_transport - register a transport implementation
+ * @transport: transport to register
+ *
+ * If a transport implementation is loaded as a kernel module, it can
+ * call this interface to make itself known to the RPC client.
+ *
+ * Returns:
+ * 0: transport successfully registered
+ * -EEXIST: transport already registered
+ * -EINVAL: transport module being unloaded
+ */
+int xprt_register_transport(struct xprt_class *transport)
+{
+ struct xprt_class *t;
+ int result;
+
+ result = -EEXIST;
+ spin_lock(&xprt_list_lock);
+ list_for_each_entry(t, &xprt_list, list) {
+ /* don't register the same transport class twice */
+ if (t->ident == transport->ident)
+ goto out;
+ }
+
+ result = -EINVAL;
+ if (try_module_get(THIS_MODULE)) {
+ list_add_tail(&transport->list, &xprt_list);
+ printk(KERN_INFO "RPC: Registered %s transport module.\n",
+ transport->name);
+ result = 0;
+ }
+
+out:
+ spin_unlock(&xprt_list_lock);
+ return result;
+}
+EXPORT_SYMBOL_GPL(xprt_register_transport);
+
+/**
+ * xprt_unregister_transport - unregister a transport implementation
+ * transport: transport to unregister
+ *
+ * Returns:
+ * 0: transport successfully unregistered
+ * -ENOENT: transport never registered
+ */
+int xprt_unregister_transport(struct xprt_class *transport)
+{
+ struct xprt_class *t;
+ int result;
+
+ result = 0;
+ spin_lock(&xprt_list_lock);
+ list_for_each_entry(t, &xprt_list, list) {
+ if (t == transport) {
+ printk(KERN_INFO
+ "RPC: Unregistered %s transport module.\n",
+ transport->name);
+ list_del_init(&transport->list);
+ module_put(THIS_MODULE);
+ goto out;
+ }
+ }
+ result = -ENOENT;
+
+out:
+ spin_unlock(&xprt_list_lock);
+ return result;
+}
+EXPORT_SYMBOL_GPL(xprt_unregister_transport);
+
+/**
* xprt_reserve_xprt - serialize write access to transports
* @task: task that is requesting access to the transport
*
@@ -118,6 +193,7 @@ out_sleep:
rpc_sleep_on(&xprt->sending, task, NULL, NULL);
return 0;
}
+EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
static void xprt_clear_locked(struct rpc_xprt *xprt)
{
@@ -167,6 +243,7 @@ out_sleep:
rpc_sleep_on(&xprt->sending, task, NULL, NULL);
return 0;
}
+EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
{
@@ -246,6 +323,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
__xprt_lock_write_next(xprt);
}
}
+EXPORT_SYMBOL_GPL(xprt_release_xprt);
/**
* xprt_release_xprt_cong - allow other requests to use a transport
@@ -262,6 +340,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
__xprt_lock_write_next_cong(xprt);
}
}
+EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
{
@@ -314,6 +393,7 @@ void xprt_release_rqst_cong(struct rpc_task *task)
{
__xprt_put_cong(task->tk_xprt, task->tk_rqstp);
}
+EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
/**
* xprt_adjust_cwnd - adjust transport congestion window
@@ -345,6 +425,7 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result)
xprt->cwnd = cwnd;
__xprt_put_cong(xprt, req);
}
+EXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
/**
* xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
@@ -359,6 +440,7 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
else
rpc_wake_up(&xprt->pending);
}
+EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
/**
* xprt_wait_for_buffer_space - wait for transport output buffer to clear
@@ -373,6 +455,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task)
task->tk_timeout = req->rq_timeout;
rpc_sleep_on(&xprt->pending, task, NULL, NULL);
}
+EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
/**
* xprt_write_space - wake the task waiting for transport output buffer space
@@ -393,6 +476,7 @@ void xprt_write_space(struct rpc_xprt *xprt)
}
spin_unlock_bh(&xprt->transport_lock);
}
+EXPORT_SYMBOL_GPL(xprt_write_space);
/**
* xprt_set_retrans_timeout_def - set a request's retransmit timeout
@@ -406,6 +490,7 @@ void xprt_set_retrans_timeout_def(struct rpc_task *task)
{
task->tk_timeout = task->tk_rqstp->rq_timeout;
}
+EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def);
/*
* xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
@@ -425,6 +510,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
task->tk_timeout = max_timeout;
}
+EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt);
static void xprt_reset_majortimeo(struct rpc_rqst *req)
{
@@ -500,6 +586,7 @@ void xprt_disconnect(struct rpc_xprt *xprt)
xprt_wake_pending_tasks(xprt, -ENOTCONN);
spin_unlock_bh(&xprt->transport_lock);
}
+EXPORT_SYMBOL_GPL(xprt_disconnect);
static void
xprt_init_autodisconnect(unsigned long data)
@@ -610,6 +697,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
xprt->stat.bad_xids++;
return NULL;
}
+EXPORT_SYMBOL_GPL(xprt_lookup_rqst);
/**
* xprt_update_rtt - update an RPC client's RTT state after receiving a reply
@@ -629,6 +717,7 @@ void xprt_update_rtt(struct rpc_task *task)
rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
}
}
+EXPORT_SYMBOL_GPL(xprt_update_rtt);
/**
* xprt_complete_rqst - called when reply processing is complete
@@ -653,6 +742,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
req->rq_received = req->rq_private_buf.len = copied;
rpc_wake_up_task(task);
}
+EXPORT_SYMBOL_GPL(xprt_complete_rqst);
static void xprt_timer(struct rpc_task *task)
{
@@ -889,23 +979,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
* @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
{
struct rpc_xprt *xprt;
struct rpc_rqst *req;
+ struct xprt_class *t;
- switch (args->proto) {
- case IPPROTO_UDP:
- xprt = xs_setup_udp(args);
- break;
- case IPPROTO_TCP:
- xprt = xs_setup_tcp(args);
- break;
- default:
- printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
- args->proto);
- return ERR_PTR(-EIO);
+ spin_lock(&xprt_list_lock);
+ list_for_each_entry(t, &xprt_list, list) {
+ if (t->ident == args->ident) {
+ spin_unlock(&xprt_list_lock);
+ goto found;
+ }
}
+ spin_unlock(&xprt_list_lock);
+ printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident);
+ return ERR_PTR(-EIO);
+
+found:
+ xprt = t->setup(args);
if (IS_ERR(xprt)) {
dprintk("RPC: xprt_create_transport: failed, %ld\n",
-PTR_ERR(xprt));
diff --git a/net/sunrpc/xprtrdma/Makefile b/net/sunrpc/xprtrdma/Makefile
new file mode 100644
index 00000000000..264f0feeb51
--- /dev/null
+++ b/net/sunrpc/xprtrdma/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
+
+xprtrdma-y := transport.o rpc_rdma.o verbs.o
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
new file mode 100644
index 00000000000..12db6358042
--- /dev/null
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * rpc_rdma.c
+ *
+ * This file contains the guts of the RPC RDMA protocol, and
+ * does marshaling/unmarshaling, etc. It is also where interfacing
+ * to the Linux RPC framework lives.
+ */
+
+#include "xprt_rdma.h"
+
+#include <linux/highmem.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_TRANS
+#endif
+
+enum rpcrdma_chunktype {
+ rpcrdma_noch = 0,
+ rpcrdma_readch,
+ rpcrdma_areadch,
+ rpcrdma_writech,
+ rpcrdma_replych
+};
+
+#ifdef RPC_DEBUG
+static const char transfertypes[][12] = {
+ "pure inline", /* no chunks */
+ " read chunk", /* some argument via rdma read */
+ "*read chunk", /* entire request via rdma read */
+ "write chunk", /* some result via rdma write */
+ "reply chunk" /* entire reply via rdma write */
+};
+#endif
+
+/*
+ * Chunk assembly from upper layer xdr_buf.
+ *
+ * Prepare the passed-in xdr_buf into representation as RPC/RDMA chunk
+ * elements. Segments are then coalesced when registered, if possible
+ * within the selected memreg mode.
+ *
+ * Note, this routine is never called if the connection's memory
+ * registration strategy is 0 (bounce buffers).
+ */
+
+static int
+rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, int pos,
+ enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs)
+{
+ int len, n = 0, p;
+
+ if (pos == 0 && xdrbuf->head[0].iov_len) {
+ seg[n].mr_page = NULL;
+ seg[n].mr_offset = xdrbuf->head[0].iov_base;
+ seg[n].mr_len = xdrbuf->head[0].iov_len;
+ pos += xdrbuf->head[0].iov_len;
+ ++n;
+ }
+
+ if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) {
+ if (n == nsegs)
+ return 0;
+ seg[n].mr_page = xdrbuf->pages[0];
+ seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base;
+ seg[n].mr_len = min_t(u32,
+ PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len);
+ len = xdrbuf->page_len - seg[n].mr_len;
+ pos += len;
+ ++n;
+ p = 1;
+ while (len > 0) {
+ if (n == nsegs)
+ return 0;
+ seg[n].mr_page = xdrbuf->pages[p];
+ seg[n].mr_offset = NULL;
+ seg[n].mr_len = min_t(u32, PAGE_SIZE, len);
+ len -= seg[n].mr_len;
+ ++n;
+ ++p;
+ }
+ }
+
+ if (pos < xdrbuf->len && xdrbuf->tail[0].iov_len) {
+ if (n == nsegs)
+ return 0;
+ seg[n].mr_page = NULL;
+ seg[n].mr_offset = xdrbuf->tail[0].iov_base;
+ seg[n].mr_len = xdrbuf->tail[0].iov_len;
+ pos += xdrbuf->tail[0].iov_len;
+ ++n;
+ }
+
+ if (pos < xdrbuf->len)
+ dprintk("RPC: %s: marshaled only %d of %d\n",
+ __func__, pos, xdrbuf->len);
+
+ return n;
+}
+
+/*
+ * Create read/write chunk lists, and reply chunks, for RDMA
+ *
+ * Assume check against THRESHOLD has been done, and chunks are required.
+ * Assume only encoding one list entry for read|write chunks. The NFSv3
+ * protocol is simple enough to allow this as it only has a single "bulk
+ * result" in each procedure - complicated NFSv4 COMPOUNDs are not. (The
+ * RDMA/Sessions NFSv4 proposal addresses this for future v4 revs.)
+ *
+ * When used for a single reply chunk (which is a special write
+ * chunk used for the entire reply, rather than just the data), it
+ * is used primarily for READDIR and READLINK which would otherwise
+ * be severely size-limited by a small rdma inline read max. The server
+ * response will come back as an RDMA Write, followed by a message
+ * of type RDMA_NOMSG carrying the xid and length. As a result, reply
+ * chunks do not provide data alignment, however they do not require
+ * "fixup" (moving the response to the upper layer buffer) either.
+ *
+ * Encoding key for single-list chunks (HLOO = Handle32 Length32 Offset64):
+ *
+ * Read chunklist (a linked list):
+ * N elements, position P (same P for all chunks of same arg!):
+ * 1 - PHLOO - 1 - PHLOO - ... - 1 - PHLOO - 0
+ *
+ * Write chunklist (a list of (one) counted array):
+ * N elements:
+ * 1 - N - HLOO - HLOO - ... - HLOO - 0
+ *
+ * Reply chunk (a counted array):
+ * N elements:
+ * 1 - N - HLOO - HLOO - ... - HLOO
+ */
+
+static unsigned int
+rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
+ struct rpcrdma_msg *headerp, enum rpcrdma_chunktype type)
+{
+ struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_task->tk_xprt);
+ int nsegs, nchunks = 0;
+ int pos;
+ struct rpcrdma_mr_seg *seg = req->rl_segments;
+ struct rpcrdma_read_chunk *cur_rchunk = NULL;
+ struct rpcrdma_write_array *warray = NULL;
+ struct rpcrdma_write_chunk *cur_wchunk = NULL;
+ u32 *iptr = headerp->rm_body.rm_chunks;
+
+ if (type == rpcrdma_readch || type == rpcrdma_areadch) {
+ /* a read chunk - server will RDMA Read our memory */
+ cur_rchunk = (struct rpcrdma_read_chunk *) iptr;
+ } else {
+ /* a write or reply chunk - server will RDMA Write our memory */
+ *iptr++ = xdr_zero; /* encode a NULL read chunk list */
+ if (type == rpcrdma_replych)
+ *iptr++ = xdr_zero; /* a NULL write chunk list */
+ warray = (struct rpcrdma_write_array *) iptr;
+ cur_wchunk = (struct rpcrdma_write_chunk *) (warray + 1);
+ }
+
+ if (type == rpcrdma_replych || type == rpcrdma_areadch)
+ pos = 0;
+ else
+ pos = target->head[0].iov_len;
+
+ nsegs = rpcrdma_convert_iovs(target, pos, type, seg, RPCRDMA_MAX_SEGS);
+ if (nsegs == 0)
+ return 0;
+
+ do {
+ /* bind/register the memory, then build chunk from result. */
+ int n = rpcrdma_register_external(seg, nsegs,
+ cur_wchunk != NULL, r_xprt);
+ if (n <= 0)
+ goto out;
+ if (cur_rchunk) { /* read */
+ cur_rchunk->rc_discrim = xdr_one;
+ /* all read chunks have the same "position" */
+ cur_rchunk->rc_position = htonl(pos);
+ cur_rchunk->rc_target.rs_handle = htonl(seg->mr_rkey);
+ cur_rchunk->rc_target.rs_length = htonl(seg->mr_len);
+ xdr_encode_hyper(
+ (u32 *)&cur_rchunk->rc_target.rs_offset,
+ seg->mr_base);
+ dprintk("RPC: %s: read chunk "
+ "elem %d@0x%llx:0x%x pos %d (%s)\n", __func__,
+ seg->mr_len, seg->mr_base, seg->mr_rkey, pos,
+ n < nsegs ? "more" : "last");
+ cur_rchunk++;
+ r_xprt->rx_stats.read_chunk_count++;
+ } else { /* write/reply */
+ cur_wchunk->wc_target.rs_handle = htonl(seg->mr_rkey);
+ cur_wchunk->wc_target.rs_length = htonl(seg->mr_len);
+ xdr_encode_hyper(
+ (u32 *)&cur_wchunk->wc_target.rs_offset,
+ seg->mr_base);
+ dprintk("RPC: %s: %s chunk "
+ "elem %d@0x%llx:0x%x (%s)\n", __func__,
+ (type == rpcrdma_replych) ? "reply" : "write",
+ seg->mr_len, seg->mr_base, seg->mr_rkey,
+ n < nsegs ? "more" : "last");
+ cur_wchunk++;
+ if (type == rpcrdma_replych)
+ r_xprt->rx_stats.reply_chunk_count++;
+ else
+ r_xprt->rx_stats.write_chunk_count++;
+ r_xprt->rx_stats.total_rdma_request += seg->mr_len;
+ }
+ nchunks++;
+ seg += n;
+ nsegs -= n;
+ } while (nsegs);
+
+ /* success. all failures return above */
+ req->rl_nchunks = nchunks;
+
+ BUG_ON(nchunks == 0);
+
+ /*
+ * finish off header. If write, marshal discrim and nchunks.
+ */
+ if (cur_rchunk) {
+ iptr = (u32 *) cur_rchunk;
+ *iptr++ = xdr_zero; /* finish the read chunk list */
+ *iptr++ = xdr_zero; /* encode a NULL write chunk list */
+ *iptr++ = xdr_zero; /* encode a NULL reply chunk */
+ } else {
+ warray->wc_discrim = xdr_one;
+ warray->wc_nchunks = htonl(nchunks);
+ iptr = (u32 *) cur_wchunk;
+ if (type == rpcrdma_writech) {
+ *iptr++ = xdr_zero; /* finish the write chunk list */
+ *iptr++ = xdr_zero; /* encode a NULL reply chunk */
+ }
+ }
+
+ /*
+ * Return header size.
+ */
+ return (unsigned char *)iptr - (unsigned char *)headerp;
+
+out:
+ for (pos = 0; nchunks--;)
+ pos += rpcrdma_deregister_external(
+ &req->rl_segments[pos], r_xprt, NULL);
+ return 0;
+}
+
+/*
+ * Copy write data inline.
+ * This function is used for "small" requests. Data which is passed
+ * to RPC via iovecs (or page list) is copied directly into the
+ * pre-registered memory buffer for this request. For small amounts
+ * of data, this is efficient. The cutoff value is tunable.
+ */
+static int
+rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
+{
+ int i, npages, curlen;
+ int copy_len;
+ unsigned char *srcp, *destp;
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
+
+ destp = rqst->rq_svec[0].iov_base;
+ curlen = rqst->rq_svec[0].iov_len;
+ destp += curlen;
+ /*
+ * Do optional padding where it makes sense. Alignment of write
+ * payload can help the server, if our setting is accurate.
+ */
+ pad -= (curlen + 36/*sizeof(struct rpcrdma_msg_padded)*/);
+ if (pad < 0 || rqst->rq_slen - curlen < RPCRDMA_INLINE_PAD_THRESH)
+ pad = 0; /* don't pad this request */
+
+ dprintk("RPC: %s: pad %d destp 0x%p len %d hdrlen %d\n",
+ __func__, pad, destp, rqst->rq_slen, curlen);
+
+ copy_len = rqst->rq_snd_buf.page_len;
+ r_xprt->rx_stats.pullup_copy_count += copy_len;
+ npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
+ for (i = 0; copy_len && i < npages; i++) {
+ if (i == 0)
+ curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base;
+ else
+ curlen = PAGE_SIZE;
+ if (curlen > copy_len)
+ curlen = copy_len;
+ dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n",
+ __func__, i, destp, copy_len, curlen);
+ srcp = kmap_atomic(rqst->rq_snd_buf.pages[i],
+ KM_SKB_SUNRPC_DATA);
+ if (i == 0)
+ memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen);
+ else
+ memcpy(destp, srcp, curlen);
+ kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA);
+ rqst->rq_svec[0].iov_len += curlen;
+ destp += curlen;
+ copy_len -= curlen;
+ }
+ if (rqst->rq_snd_buf.tail[0].iov_len) {
+ curlen = rqst->rq_snd_buf.tail[0].iov_len;
+ if (destp != rqst->rq_snd_buf.tail[0].iov_base) {
+ memcpy(destp,
+ rqst->rq_snd_buf.tail[0].iov_base, curlen);
+ r_xprt->rx_stats.pullup_copy_count += curlen;
+ }
+ dprintk("RPC: %s: tail destp 0x%p len %d curlen %d\n",
+ __func__, destp, copy_len, curlen);
+ rqst->rq_svec[0].iov_len += curlen;
+ }
+ /* header now contains entire send message */
+ return pad;
+}
+
+/*
+ * Marshal a request: the primary job of this routine is to choose
+ * the transfer modes. See comments below.
+ *
+ * Uses multiple RDMA IOVs for a request:
+ * [0] -- RPC RDMA header, which uses memory from the *start* of the
+ * preregistered buffer that already holds the RPC data in
+ * its middle.
+ * [1] -- the RPC header/data, marshaled by RPC and the NFS protocol.
+ * [2] -- optional padding.
+ * [3] -- if padded, header only in [1] and data here.
+ */
+
+int
+rpcrdma_marshal_req(struct rpc_rqst *rqst)
+{
+ struct rpc_xprt *xprt = rqst->rq_task->tk_xprt;
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+ struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+ char *base;
+ size_t hdrlen, rpclen, padlen;
+ enum rpcrdma_chunktype rtype, wtype;
+ struct rpcrdma_msg *headerp;
+
+ /*
+ * rpclen gets amount of data in first buffer, which is the
+ * pre-registered buffer.
+ */
+ base = rqst->rq_svec[0].iov_base;
+ rpclen = rqst->rq_svec[0].iov_len;
+
+ /* build RDMA header in private area at front */
+ headerp = (struct rpcrdma_msg *) req->rl_base;
+ /* don't htonl XID, it's already done in request */
+ headerp->rm_xid = rqst->rq_xid;
+ headerp->rm_vers = xdr_one;
+ headerp->rm_credit = htonl(r_xprt->rx_buf.rb_max_requests);
+ headerp->rm_type = __constant_htonl(RDMA_MSG);
+
+ /*
+ * Chunks needed for results?
+ *
+ * o If the expected result is under the inline threshold, all ops
+ * return as inline (but see later).
+ * o Large non-read ops return as a single reply chunk.
+ * o Large read ops return data as write chunk(s), header as inline.
+ *
+ * Note: the NFS code sending down multiple result segments implies
+ * the op is one of read, readdir[plus], readlink or NFSv4 getacl.
+ */
+
+ /*
+ * This code can handle read chunks, write chunks OR reply
+ * chunks -- only one type. If the request is too big to fit
+ * inline, then we will choose read chunks. If the request is
+ * a READ, then use write chunks to separate the file data
+ * into pages; otherwise use reply chunks.
+ */
+ if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst))
+ wtype = rpcrdma_noch;
+ else if (rqst->rq_rcv_buf.page_len == 0)
+ wtype = rpcrdma_replych;
+ else if (rqst->rq_rcv_buf.flags & XDRBUF_READ)
+ wtype = rpcrdma_writech;
+ else
+ wtype = rpcrdma_replych;
+
+ /*
+ * Chunks needed for arguments?
+ *
+ * o If the total request is under the inline threshold, all ops
+ * are sent as inline.
+ * o Large non-write ops are sent with the entire message as a
+ * single read chunk (protocol 0-position special case).
+ * o Large write ops transmit data as read chunk(s), header as
+ * inline.
+ *
+ * Note: the NFS code sending down multiple argument segments
+ * implies the op is a write.
+ * TBD check NFSv4 setacl
+ */
+ if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst))
+ rtype = rpcrdma_noch;
+ else if (rqst->rq_snd_buf.page_len == 0)
+ rtype = rpcrdma_areadch;
+ else
+ rtype = rpcrdma_readch;
+
+ /* The following simplification is not true forever */
+ if (rtype != rpcrdma_noch && wtype == rpcrdma_replych)
+ wtype = rpcrdma_noch;
+ BUG_ON(rtype != rpcrdma_noch && wtype != rpcrdma_noch);
+
+ if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_BOUNCEBUFFERS &&
+ (rtype != rpcrdma_noch || wtype != rpcrdma_noch)) {
+ /* forced to "pure inline"? */
+ dprintk("RPC: %s: too much data (%d/%d) for inline\n",
+ __func__, rqst->rq_rcv_buf.len, rqst->rq_snd_buf.len);
+ return -1;
+ }
+
+ hdrlen = 28; /*sizeof *headerp;*/
+ padlen = 0;
+
+ /*
+ * Pull up any extra send data into the preregistered buffer.
+ * When padding is in use and applies to the transfer, insert
+ * it and change the message type.
+ */
+ if (rtype == rpcrdma_noch) {
+
+ padlen = rpcrdma_inline_pullup(rqst,
+ RPCRDMA_INLINE_PAD_VALUE(rqst));
+
+ if (padlen) {
+ headerp->rm_type = __constant_htonl(RDMA_MSGP);
+ headerp->rm_body.rm_padded.rm_align =
+ htonl(RPCRDMA_INLINE_PAD_VALUE(rqst));
+ headerp->rm_body.rm_padded.rm_thresh =
+ __constant_htonl(RPCRDMA_INLINE_PAD_THRESH);
+ headerp->rm_body.rm_padded.rm_pempty[0] = xdr_zero;
+ headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero;
+ headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero;
+ hdrlen += 2 * sizeof(u32); /* extra words in padhdr */
+ BUG_ON(wtype != rpcrdma_noch);
+
+ } else {
+ headerp->rm_body.rm_nochunks.rm_empty[0] = xdr_zero;
+ headerp->rm_body.rm_nochunks.rm_empty[1] = xdr_zero;
+ headerp->rm_body.rm_nochunks.rm_empty[2] = xdr_zero;
+ /* new length after pullup */
+ rpclen = rqst->rq_svec[0].iov_len;
+ /*
+ * Currently we try to not actually use read inline.
+ * Reply chunks have the desirable property that
+ * they land, packed, directly in the target buffers
+ * without headers, so they require no fixup. The
+ * additional RDMA Write op sends the same amount
+ * of data, streams on-the-wire and adds no overhead
+ * on receive. Therefore, we request a reply chunk
+ * for non-writes wherever feasible and efficient.
+ */
+ if (wtype == rpcrdma_noch &&
+ r_xprt->rx_ia.ri_memreg_strategy > RPCRDMA_REGISTER)
+ wtype = rpcrdma_replych;
+ }
+ }
+
+ /*
+ * Marshal chunks. This routine will return the header length
+ * consumed by marshaling.
+ */
+ if (rtype != rpcrdma_noch) {
+ hdrlen = rpcrdma_create_chunks(rqst,
+ &rqst->rq_snd_buf, headerp, rtype);
+ wtype = rtype; /* simplify dprintk */
+
+ } else if (wtype != rpcrdma_noch) {
+ hdrlen = rpcrdma_create_chunks(rqst,
+ &rqst->rq_rcv_buf, headerp, wtype);
+ }
+
+ if (hdrlen == 0)
+ return -1;
+
+ dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd\n"
+ " headerp 0x%p base 0x%p lkey 0x%x\n",
+ __func__, transfertypes[wtype], hdrlen, rpclen, padlen,
+ headerp, base, req->rl_iov.lkey);
+
+ /*
+ * initialize send_iov's - normally only two: rdma chunk header and
+ * single preregistered RPC header buffer, but if padding is present,
+ * then use a preregistered (and zeroed) pad buffer between the RPC
+ * header and any write data. In all non-rdma cases, any following
+ * data has been copied into the RPC header buffer.
+ */
+ req->rl_send_iov[0].addr = req->rl_iov.addr;
+ req->rl_send_iov[0].length = hdrlen;
+ req->rl_send_iov[0].lkey = req->rl_iov.lkey;
+
+ req->rl_send_iov[1].addr = req->rl_iov.addr + (base - req->rl_base);
+ req->rl_send_iov[1].length = rpclen;
+ req->rl_send_iov[1].lkey = req->rl_iov.lkey;
+
+ req->rl_niovs = 2;
+
+ if (padlen) {
+ struct rpcrdma_ep *ep = &r_xprt->rx_ep;
+
+ req->rl_send_iov[2].addr = ep->rep_pad.addr;
+ req->rl_send_iov[2].length = padlen;
+ req->rl_send_iov[2].lkey = ep->rep_pad.lkey;
+
+ req->rl_send_iov[3].addr = req->rl_send_iov[1].addr + rpclen;
+ req->rl_send_iov[3].length = rqst->rq_slen - rpclen;
+ req->rl_send_iov[3].lkey = req->rl_iov.lkey;
+
+ req->rl_niovs = 4;
+ }
+
+ return 0;
+}
+
+/*
+ * Chase down a received write or reply chunklist to get length
+ * RDMA'd by server. See map at rpcrdma_create_chunks()! :-)
+ */
+static int
+rpcrdma_count_chunks(struct rpcrdma_rep *rep, int max, int wrchunk, u32 **iptrp)
+{
+ unsigned int i, total_len;
+ struct rpcrdma_write_chunk *cur_wchunk;
+
+ i = ntohl(**iptrp); /* get array count */
+ if (i > max)
+ return -1;
+ cur_wchunk = (struct rpcrdma_write_chunk *) (*iptrp + 1);
+ total_len = 0;
+ while (i--) {
+ struct rpcrdma_segment *seg = &cur_wchunk->wc_target;
+ ifdebug(FACILITY) {
+ u64 off;
+ xdr_decode_hyper((u32 *)&seg->rs_offset, &off);
+ dprintk("RPC: %s: chunk %d@0x%llx:0x%x\n",
+ __func__,
+ ntohl(seg->rs_length),
+ off,
+ ntohl(seg->rs_handle));
+ }
+ total_len += ntohl(seg->rs_length);
+ ++cur_wchunk;
+ }
+ /* check and adjust for properly terminated write chunk */
+ if (wrchunk) {
+ u32 *w = (u32 *) cur_wchunk;
+ if (*w++ != xdr_zero)
+ return -1;
+ cur_wchunk = (struct rpcrdma_write_chunk *) w;
+ }
+ if ((char *) cur_wchunk > rep->rr_base + rep->rr_len)
+ return -1;
+
+ *iptrp = (u32 *) cur_wchunk;
+ return total_len;
+}
+
+/*
+ * Scatter inline received data back into provided iov's.
+ */
+static void
+rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len)
+{
+ int i, npages, curlen, olen;
+ char *destp;
+
+ curlen = rqst->rq_rcv_buf.head[0].iov_len;
+ if (curlen > copy_len) { /* write chunk header fixup */
+ curlen = copy_len;
+ rqst->rq_rcv_buf.head[0].iov_len = curlen;
+ }
+
+ dprintk("RPC: %s: srcp 0x%p len %d hdrlen %d\n",
+ __func__, srcp, copy_len, curlen);
+
+ /* Shift pointer for first receive segment only */
+ rqst->rq_rcv_buf.head[0].iov_base = srcp;
+ srcp += curlen;
+ copy_len -= curlen;
+
+ olen = copy_len;
+ i = 0;
+ rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen;
+ if (copy_len && rqst->rq_rcv_buf.page_len) {
+ npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base +
+ rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT;
+ for (; i < npages; i++) {
+ if (i == 0)
+ curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base;
+ else
+ curlen = PAGE_SIZE;
+ if (curlen > copy_len)
+ curlen = copy_len;
+ dprintk("RPC: %s: page %d"
+ " srcp 0x%p len %d curlen %d\n",
+ __func__, i, srcp, copy_len, curlen);
+ destp = kmap_atomic(rqst->rq_rcv_buf.pages[i],
+ KM_SKB_SUNRPC_DATA);
+ if (i == 0)
+ memcpy(destp + rqst->rq_rcv_buf.page_base,
+ srcp, curlen);
+ else
+ memcpy(destp, srcp, curlen);
+ flush_dcache_page(rqst->rq_rcv_buf.pages[i]);
+ kunmap_atomic(destp, KM_SKB_SUNRPC_DATA);
+ srcp += curlen;
+ copy_len -= curlen;
+ if (copy_len == 0)
+ break;
+ }
+ rqst->rq_rcv_buf.page_len = olen - copy_len;
+ } else
+ rqst->rq_rcv_buf.page_len = 0;
+
+ if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) {
+ curlen = copy_len;
+ if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
+ curlen = rqst->rq_rcv_buf.tail[0].iov_len;
+ if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
+ memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
+ dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n",
+ __func__, srcp, copy_len, curlen);
+ rqst->rq_rcv_buf.tail[0].iov_len = curlen;
+ copy_len -= curlen; ++i;
+ } else
+ rqst->rq_rcv_buf.tail[0].iov_len = 0;
+
+ if (copy_len)
+ dprintk("RPC: %s: %d bytes in"
+ " %d extra segments (%d lost)\n",
+ __func__, olen, i, copy_len);
+
+ /* TBD avoid a warning from call_decode() */
+ rqst->rq_private_buf = rqst->rq_rcv_buf;
+}
+
+/*
+ * This function is called when an async event is posted to
+ * the connection which changes the connection state. All it
+ * does at this point is mark the connection up/down, the rpc
+ * timers do the rest.
+ */
+void
+rpcrdma_conn_func(struct rpcrdma_ep *ep)
+{
+ struct rpc_xprt *xprt = ep->rep_xprt;
+
+ spin_lock_bh(&xprt->transport_lock);
+ if (ep->rep_connected > 0) {
+ if (!xprt_test_and_set_connected(xprt))
+ xprt_wake_pending_tasks(xprt, 0);
+ } else {
+ if (xprt_test_and_clear_connected(xprt))
+ xprt_wake_pending_tasks(xprt, ep->rep_connected);
+ }
+ spin_unlock_bh(&xprt->transport_lock);
+}
+
+/*
+ * This function is called when memory window unbind which we are waiting
+ * for completes. Just use rr_func (zeroed by upcall) to signal completion.
+ */
+static void
+rpcrdma_unbind_func(struct rpcrdma_rep *rep)
+{
+ wake_up(&rep->rr_unbind);
+}
+
+/*
+ * Called as a tasklet to do req/reply match and complete a request
+ * Errors must result in the RPC task either being awakened, or
+ * allowed to timeout, to discover the errors at that time.
+ */
+void
+rpcrdma_reply_handler(struct rpcrdma_rep *rep)
+{
+ struct rpcrdma_msg *headerp;
+ struct rpcrdma_req *req;
+ struct rpc_rqst *rqst;
+ struct rpc_xprt *xprt = rep->rr_xprt;
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+ u32 *iptr;
+ int i, rdmalen, status;
+
+ /* Check status. If bad, signal disconnect and return rep to pool */
+ if (rep->rr_len == ~0U) {
+ rpcrdma_recv_buffer_put(rep);
+ if (r_xprt->rx_ep.rep_connected == 1) {
+ r_xprt->rx_ep.rep_connected = -EIO;
+ rpcrdma_conn_func(&r_xprt->rx_ep);
+ }
+ return;
+ }
+ if (rep->rr_len < 28) {
+ dprintk("RPC: %s: short/invalid reply\n", __func__);
+ goto repost;
+ }
+ headerp = (struct rpcrdma_msg *) rep->rr_base;
+ if (headerp->rm_vers != xdr_one) {
+ dprintk("RPC: %s: invalid version %d\n",
+ __func__, ntohl(headerp->rm_vers));
+ goto repost;
+ }
+
+ /* Get XID and try for a match. */
+ spin_lock(&xprt->transport_lock);
+ rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);
+ if (rqst == NULL) {
+ spin_unlock(&xprt->transport_lock);
+ dprintk("RPC: %s: reply 0x%p failed "
+ "to match any request xid 0x%08x len %d\n",
+ __func__, rep, headerp->rm_xid, rep->rr_len);
+repost:
+ r_xprt->rx_stats.bad_reply_count++;
+ rep->rr_func = rpcrdma_reply_handler;
+ if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, &r_xprt->rx_ep, rep))
+ rpcrdma_recv_buffer_put(rep);
+
+ return;
+ }
+
+ /* get request object */
+ req = rpcr_to_rdmar(rqst);
+
+ dprintk("RPC: %s: reply 0x%p completes request 0x%p\n"
+ " RPC request 0x%p xid 0x%08x\n",
+ __func__, rep, req, rqst, headerp->rm_xid);
+
+ BUG_ON(!req || req->rl_reply);
+
+ /* from here on, the reply is no longer an orphan */
+ req->rl_reply = rep;
+
+ /* check for expected message types */
+ /* The order of some of these tests is important. */
+ switch (headerp->rm_type) {
+ case __constant_htonl(RDMA_MSG):
+ /* never expect read chunks */
+ /* never expect reply chunks (two ways to check) */
+ /* never expect write chunks without having offered RDMA */
+ if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
+ (headerp->rm_body.rm_chunks[1] == xdr_zero &&
+ headerp->rm_body.rm_chunks[2] != xdr_zero) ||
+ (headerp->rm_body.rm_chunks[1] != xdr_zero &&
+ req->rl_nchunks == 0))
+ goto badheader;
+ if (headerp->rm_body.rm_chunks[1] != xdr_zero) {
+ /* count any expected write chunks in read reply */
+ /* start at write chunk array count */
+ iptr = &headerp->rm_body.rm_chunks[2];
+ rdmalen = rpcrdma_count_chunks(rep,
+ req->rl_nchunks, 1, &iptr);
+ /* check for validity, and no reply chunk after */
+ if (rdmalen < 0 || *iptr++ != xdr_zero)
+ goto badheader;
+ rep->rr_len -=
+ ((unsigned char *)iptr - (unsigned char *)headerp);
+ status = rep->rr_len + rdmalen;
+ r_xprt->rx_stats.total_rdma_reply += rdmalen;
+ } else {
+ /* else ordinary inline */
+ iptr = (u32 *)((unsigned char *)headerp + 28);
+ rep->rr_len -= 28; /*sizeof *headerp;*/
+ status = rep->rr_len;
+ }
+ /* Fix up the rpc results for upper layer */
+ rpcrdma_inline_fixup(rqst, (char *)iptr, rep->rr_len);
+ break;
+
+ case __constant_htonl(RDMA_NOMSG):
+ /* never expect read or write chunks, always reply chunks */
+ if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
+ headerp->rm_body.rm_chunks[1] != xdr_zero ||
+ headerp->rm_body.rm_chunks[2] != xdr_one ||
+ req->rl_nchunks == 0)
+ goto badheader;
+ iptr = (u32 *)((unsigned char *)headerp + 28);
+ rdmalen = rpcrdma_count_chunks(rep, req->rl_nchunks, 0, &iptr);
+ if (rdmalen < 0)
+ goto badheader;
+ r_xprt->rx_stats.total_rdma_reply += rdmalen;
+ /* Reply chunk buffer already is the reply vector - no fixup. */
+ status = rdmalen;
+ break;
+
+badheader:
+ default:
+ dprintk("%s: invalid rpcrdma reply header (type %d):"
+ " chunks[012] == %d %d %d"
+ " expected chunks <= %d\n",
+ __func__, ntohl(headerp->rm_type),
+ headerp->rm_body.rm_chunks[0],
+ headerp->rm_body.rm_chunks[1],
+ headerp->rm_body.rm_chunks[2],
+ req->rl_nchunks);
+ status = -EIO;
+ r_xprt->rx_stats.bad_reply_count++;
+ break;
+ }
+
+ /* If using mw bind, start the deregister process now. */
+ /* (Note: if mr_free(), cannot perform it here, in tasklet context) */
+ if (req->rl_nchunks) switch (r_xprt->rx_ia.ri_memreg_strategy) {
+ case RPCRDMA_MEMWINDOWS:
+ for (i = 0; req->rl_nchunks-- > 1;)
+ i += rpcrdma_deregister_external(
+ &req->rl_segments[i], r_xprt, NULL);
+ /* Optionally wait (not here) for unbinds to complete */
+ rep->rr_func = rpcrdma_unbind_func;
+ (void) rpcrdma_deregister_external(&req->rl_segments[i],
+ r_xprt, rep);
+ break;
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ for (i = 0; req->rl_nchunks--;)
+ i += rpcrdma_deregister_external(&req->rl_segments[i],
+ r_xprt, NULL);
+ break;
+ default:
+ break;
+ }
+
+ dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",
+ __func__, xprt, rqst, status);
+ xprt_complete_rqst(rqst->rq_task, status);
+ spin_unlock(&xprt->transport_lock);
+}
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
new file mode 100644
index 00000000000..dc55cc974c9
--- /dev/null
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * transport.c
+ *
+ * This file contains the top-level implementation of an RPC RDMA
+ * transport.
+ *
+ * Naming convention: functions beginning with xprt_ are part of the
+ * transport switch. All others are RPC RDMA internal.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+#include "xprt_rdma.h"
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_TRANS
+#endif
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_DESCRIPTION("RPC/RDMA Transport for Linux kernel NFS");
+MODULE_AUTHOR("Network Appliance, Inc.");
+
+/*
+ * tunables
+ */
+
+static unsigned int xprt_rdma_slot_table_entries = RPCRDMA_DEF_SLOT_TABLE;
+static unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
+static unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
+static unsigned int xprt_rdma_inline_write_padding;
+#if !RPCRDMA_PERSISTENT_REGISTRATION
+static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_REGISTER; /* FMR? */
+#else
+static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_ALLPHYSICAL;
+#endif
+
+#ifdef RPC_DEBUG
+
+static unsigned int min_slot_table_size = RPCRDMA_MIN_SLOT_TABLE;
+static unsigned int max_slot_table_size = RPCRDMA_MAX_SLOT_TABLE;
+static unsigned int zero;
+static unsigned int max_padding = PAGE_SIZE;
+static unsigned int min_memreg = RPCRDMA_BOUNCEBUFFERS;
+static unsigned int max_memreg = RPCRDMA_LAST - 1;
+
+static struct ctl_table_header *sunrpc_table_header;
+
+static ctl_table xr_tunables_table[] = {
+ {
+ .ctl_name = CTL_SLOTTABLE_RDMA,
+ .procname = "rdma_slot_table_entries",
+ .data = &xprt_rdma_slot_table_entries,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &min_slot_table_size,
+ .extra2 = &max_slot_table_size
+ },
+ {
+ .ctl_name = CTL_RDMA_MAXINLINEREAD,
+ .procname = "rdma_max_inline_read",
+ .data = &xprt_rdma_max_inline_read,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ },
+ {
+ .ctl_name = CTL_RDMA_MAXINLINEWRITE,
+ .procname = "rdma_max_inline_write",
+ .data = &xprt_rdma_max_inline_write,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ },
+ {
+ .ctl_name = CTL_RDMA_WRITEPADDING,
+ .procname = "rdma_inline_write_padding",
+ .data = &xprt_rdma_inline_write_padding,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ .extra2 = &max_padding,
+ },
+ {
+ .ctl_name = CTL_RDMA_MEMREG,
+ .procname = "rdma_memreg_strategy",
+ .data = &xprt_rdma_memreg_strategy,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &min_memreg,
+ .extra2 = &max_memreg,
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+static ctl_table sunrpc_table[] = {
+ {
+ .ctl_name = CTL_SUNRPC,
+ .procname = "sunrpc",
+ .mode = 0555,
+ .child = xr_tunables_table
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+#endif
+
+static struct rpc_xprt_ops xprt_rdma_procs; /* forward reference */
+
+static void
+xprt_rdma_format_addresses(struct rpc_xprt *xprt)
+{
+ struct sockaddr_in *addr = (struct sockaddr_in *)
+ &rpcx_to_rdmad(xprt).addr;
+ char *buf;
+
+ buf = kzalloc(20, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 20, NIPQUAD_FMT, NIPQUAD(addr->sin_addr.s_addr));
+ xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 8, "%u", ntohs(addr->sin_port));
+ xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+
+ xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma";
+
+ buf = kzalloc(48, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
+ NIPQUAD(addr->sin_addr.s_addr),
+ ntohs(addr->sin_port), "rdma");
+ xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+ buf = kzalloc(10, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 10, "%02x%02x%02x%02x",
+ NIPQUAD(addr->sin_addr.s_addr));
+ xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 8, "%4hx", ntohs(addr->sin_port));
+ xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+ buf = kzalloc(30, GFP_KERNEL);
+ if (buf)
+ snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
+ NIPQUAD(addr->sin_addr.s_addr),
+ ntohs(addr->sin_port) >> 8,
+ ntohs(addr->sin_port) & 0xff);
+ xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+ /* netid */
+ xprt->address_strings[RPC_DISPLAY_NETID] = "rdma";
+}
+
+static void
+xprt_rdma_free_addresses(struct rpc_xprt *xprt)
+{
+ kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
+ kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
+ kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
+ kfree(xprt->address_strings[RPC_DISPLAY_HEX_ADDR]);
+ kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
+ kfree(xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR]);
+}
+
+static void
+xprt_rdma_connect_worker(struct work_struct *work)
+{
+ struct rpcrdma_xprt *r_xprt =
+ container_of(work, struct rpcrdma_xprt, rdma_connect.work);
+ struct rpc_xprt *xprt = &r_xprt->xprt;
+ int rc = 0;
+
+ if (!xprt->shutdown) {
+ xprt_clear_connected(xprt);
+
+ dprintk("RPC: %s: %sconnect\n", __func__,
+ r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
+ rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+ if (rc)
+ goto out;
+ }
+ goto out_clear;
+
+out:
+ xprt_wake_pending_tasks(xprt, rc);
+
+out_clear:
+ dprintk("RPC: %s: exit\n", __func__);
+ xprt_clear_connecting(xprt);
+}
+
+/*
+ * xprt_rdma_destroy
+ *
+ * Destroy the xprt.
+ * Free all memory associated with the object, including its own.
+ * NOTE: none of the *destroy methods free memory for their top-level
+ * objects, even though they may have allocated it (they do free
+ * private memory). It's up to the caller to handle it. In this
+ * case (RDMA transport), all structure memory is inlined with the
+ * struct rpcrdma_xprt.
+ */
+static void
+xprt_rdma_destroy(struct rpc_xprt *xprt)
+{
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+ int rc;
+
+ dprintk("RPC: %s: called\n", __func__);
+
+ cancel_delayed_work(&r_xprt->rdma_connect);
+ flush_scheduled_work();
+
+ xprt_clear_connected(xprt);
+
+ rpcrdma_buffer_destroy(&r_xprt->rx_buf);
+ rc = rpcrdma_ep_destroy(&r_xprt->rx_ep, &r_xprt->rx_ia);
+ if (rc)
+ dprintk("RPC: %s: rpcrdma_ep_destroy returned %i\n",
+ __func__, rc);
+ rpcrdma_ia_close(&r_xprt->rx_ia);
+
+ xprt_rdma_free_addresses(xprt);
+
+ kfree(xprt->slot);
+ xprt->slot = NULL;
+ kfree(xprt);
+
+ dprintk("RPC: %s: returning\n", __func__);
+
+ module_put(THIS_MODULE);
+}
+
+/**
+ * xprt_setup_rdma - Set up transport to use RDMA
+ *
+ * @args: rpc transport arguments
+ */
+static struct rpc_xprt *
+xprt_setup_rdma(struct xprt_create *args)
+{
+ struct rpcrdma_create_data_internal cdata;
+ struct rpc_xprt *xprt;
+ struct rpcrdma_xprt *new_xprt;
+ struct rpcrdma_ep *new_ep;
+ struct sockaddr_in *sin;
+ int rc;
+
+ if (args->addrlen > sizeof(xprt->addr)) {
+ dprintk("RPC: %s: address too large\n", __func__);
+ return ERR_PTR(-EBADF);
+ }
+
+ xprt = kzalloc(sizeof(struct rpcrdma_xprt), GFP_KERNEL);
+ if (xprt == NULL) {
+ dprintk("RPC: %s: couldn't allocate rpcrdma_xprt\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ xprt->max_reqs = xprt_rdma_slot_table_entries;
+ xprt->slot = kcalloc(xprt->max_reqs,
+ sizeof(struct rpc_rqst), GFP_KERNEL);
+ if (xprt->slot == NULL) {
+ kfree(xprt);
+ dprintk("RPC: %s: couldn't allocate %d slots\n",
+ __func__, xprt->max_reqs);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* 60 second timeout, no retries */
+ xprt_set_timeout(&xprt->timeout, 0, 60UL * HZ);
+ xprt->bind_timeout = (60U * HZ);
+ xprt->connect_timeout = (60U * HZ);
+ xprt->reestablish_timeout = (5U * HZ);
+ xprt->idle_timeout = (5U * 60 * HZ);
+
+ xprt->resvport = 0; /* privileged port not needed */
+ xprt->tsh_size = 0; /* RPC-RDMA handles framing */
+ xprt->max_payload = RPCRDMA_MAX_DATA_SEGS * PAGE_SIZE;
+ xprt->ops = &xprt_rdma_procs;
+
+ /*
+ * Set up RDMA-specific connect data.
+ */
+
+ /* Put server RDMA address in local cdata */
+ memcpy(&cdata.addr, args->dstaddr, args->addrlen);
+
+ /* Ensure xprt->addr holds valid server TCP (not RDMA)
+ * address, for any side protocols which peek at it */
+ xprt->prot = IPPROTO_TCP;
+ xprt->addrlen = args->addrlen;
+ memcpy(&xprt->addr, &cdata.addr, xprt->addrlen);
+
+ sin = (struct sockaddr_in *)&cdata.addr;
+ if (ntohs(sin->sin_port) != 0)
+ xprt_set_bound(xprt);
+
+ dprintk("RPC: %s: %u.%u.%u.%u:%u\n", __func__,
+ NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+
+ /* Set max requests */
+ cdata.max_requests = xprt->max_reqs;
+
+ /* Set some length limits */
+ cdata.rsize = RPCRDMA_MAX_SEGS * PAGE_SIZE; /* RDMA write max */
+ cdata.wsize = RPCRDMA_MAX_SEGS * PAGE_SIZE; /* RDMA read max */
+
+ cdata.inline_wsize = xprt_rdma_max_inline_write;
+ if (cdata.inline_wsize > cdata.wsize)
+ cdata.inline_wsize = cdata.wsize;
+
+ cdata.inline_rsize = xprt_rdma_max_inline_read;
+ if (cdata.inline_rsize > cdata.rsize)
+ cdata.inline_rsize = cdata.rsize;
+
+ cdata.padding = xprt_rdma_inline_write_padding;
+
+ /*
+ * Create new transport instance, which includes initialized
+ * o ia
+ * o endpoint
+ * o buffers
+ */
+
+ new_xprt = rpcx_to_rdmax(xprt);
+
+ rc = rpcrdma_ia_open(new_xprt, (struct sockaddr *) &cdata.addr,
+ xprt_rdma_memreg_strategy);
+ if (rc)
+ goto out1;
+
+ /*
+ * initialize and create ep
+ */
+ new_xprt->rx_data = cdata;
+ new_ep = &new_xprt->rx_ep;
+ new_ep->rep_remote_addr = cdata.addr;
+
+ rc = rpcrdma_ep_create(&new_xprt->rx_ep,
+ &new_xprt->rx_ia, &new_xprt->rx_data);
+ if (rc)
+ goto out2;
+
+ /*
+ * Allocate pre-registered send and receive buffers for headers and
+ * any inline data. Also specify any padding which will be provided
+ * from a preregistered zero buffer.
+ */
+ rc = rpcrdma_buffer_create(&new_xprt->rx_buf, new_ep, &new_xprt->rx_ia,
+ &new_xprt->rx_data);
+ if (rc)
+ goto out3;
+
+ /*
+ * Register a callback for connection events. This is necessary because
+ * connection loss notification is async. We also catch connection loss
+ * when reaping receives.
+ */
+ INIT_DELAYED_WORK(&new_xprt->rdma_connect, xprt_rdma_connect_worker);
+ new_ep->rep_func = rpcrdma_conn_func;
+ new_ep->rep_xprt = xprt;
+
+ xprt_rdma_format_addresses(xprt);
+
+ if (!try_module_get(THIS_MODULE))
+ goto out4;
+
+ return xprt;
+
+out4:
+ xprt_rdma_free_addresses(xprt);
+ rc = -EINVAL;
+out3:
+ (void) rpcrdma_ep_destroy(new_ep, &new_xprt->rx_ia);
+out2:
+ rpcrdma_ia_close(&new_xprt->rx_ia);
+out1:
+ kfree(xprt->slot);
+ kfree(xprt);
+ return ERR_PTR(rc);
+}
+
+/*
+ * Close a connection, during shutdown or timeout/reconnect
+ */
+static void
+xprt_rdma_close(struct rpc_xprt *xprt)
+{
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+ dprintk("RPC: %s: closing\n", __func__);
+ xprt_disconnect(xprt);
+ (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+}
+
+static void
+xprt_rdma_set_port(struct rpc_xprt *xprt, u16 port)
+{
+ struct sockaddr_in *sap;
+
+ sap = (struct sockaddr_in *)&xprt->addr;
+ sap->sin_port = htons(port);
+ sap = (struct sockaddr_in *)&rpcx_to_rdmad(xprt).addr;
+ sap->sin_port = htons(port);
+ dprintk("RPC: %s: %u\n", __func__, port);
+}
+
+static void
+xprt_rdma_connect(struct rpc_task *task)
+{
+ struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt;
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+ if (!xprt_test_and_set_connecting(xprt)) {
+ if (r_xprt->rx_ep.rep_connected != 0) {
+ /* Reconnect */
+ schedule_delayed_work(&r_xprt->rdma_connect,
+ xprt->reestablish_timeout);
+ } else {
+ schedule_delayed_work(&r_xprt->rdma_connect, 0);
+ if (!RPC_IS_ASYNC(task))
+ flush_scheduled_work();
+ }
+ }
+}
+
+static int
+xprt_rdma_reserve_xprt(struct rpc_task *task)
+{
+ struct rpc_xprt *xprt = task->tk_xprt;
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+ int credits = atomic_read(&r_xprt->rx_buf.rb_credits);
+
+ /* == RPC_CWNDSCALE @ init, but *after* setup */
+ if (r_xprt->rx_buf.rb_cwndscale == 0UL) {
+ r_xprt->rx_buf.rb_cwndscale = xprt->cwnd;
+ dprintk("RPC: %s: cwndscale %lu\n", __func__,
+ r_xprt->rx_buf.rb_cwndscale);
+ BUG_ON(r_xprt->rx_buf.rb_cwndscale <= 0);
+ }
+ xprt->cwnd = credits * r_xprt->rx_buf.rb_cwndscale;
+ return xprt_reserve_xprt_cong(task);
+}
+
+/*
+ * The RDMA allocate/free functions need the task structure as a place
+ * to hide the struct rpcrdma_req, which is necessary for the actual send/recv
+ * sequence. For this reason, the recv buffers are attached to send
+ * buffers for portions of the RPC. Note that the RPC layer allocates
+ * both send and receive buffers in the same call. We may register
+ * the receive buffer portion when using reply chunks.
+ */
+static void *
+xprt_rdma_allocate(struct rpc_task *task, size_t size)
+{
+ struct rpc_xprt *xprt = task->tk_xprt;
+ struct rpcrdma_req *req, *nreq;
+
+ req = rpcrdma_buffer_get(&rpcx_to_rdmax(xprt)->rx_buf);
+ BUG_ON(NULL == req);
+
+ if (size > req->rl_size) {
+ dprintk("RPC: %s: size %zd too large for buffer[%zd]: "
+ "prog %d vers %d proc %d\n",
+ __func__, size, req->rl_size,
+ task->tk_client->cl_prog, task->tk_client->cl_vers,
+ task->tk_msg.rpc_proc->p_proc);
+ /*
+ * Outgoing length shortage. Our inline write max must have
+ * been configured to perform direct i/o.
+ *
+ * This is therefore a large metadata operation, and the
+ * allocate call was made on the maximum possible message,
+ * e.g. containing long filename(s) or symlink data. In
+ * fact, while these metadata operations *might* carry
+ * large outgoing payloads, they rarely *do*. However, we
+ * have to commit to the request here, so reallocate and
+ * register it now. The data path will never require this
+ * reallocation.
+ *
+ * If the allocation or registration fails, the RPC framework
+ * will (doggedly) retry.
+ */
+ if (rpcx_to_rdmax(xprt)->rx_ia.ri_memreg_strategy ==
+ RPCRDMA_BOUNCEBUFFERS) {
+ /* forced to "pure inline" */
+ dprintk("RPC: %s: too much data (%zd) for inline "
+ "(r/w max %d/%d)\n", __func__, size,
+ rpcx_to_rdmad(xprt).inline_rsize,
+ rpcx_to_rdmad(xprt).inline_wsize);
+ size = req->rl_size;
+ rpc_exit(task, -EIO); /* fail the operation */
+ rpcx_to_rdmax(xprt)->rx_stats.failed_marshal_count++;
+ goto out;
+ }
+ if (task->tk_flags & RPC_TASK_SWAPPER)
+ nreq = kmalloc(sizeof *req + size, GFP_ATOMIC);
+ else
+ nreq = kmalloc(sizeof *req + size, GFP_NOFS);
+ if (nreq == NULL)
+ goto outfail;
+
+ if (rpcrdma_register_internal(&rpcx_to_rdmax(xprt)->rx_ia,
+ nreq->rl_base, size + sizeof(struct rpcrdma_req)
+ - offsetof(struct rpcrdma_req, rl_base),
+ &nreq->rl_handle, &nreq->rl_iov)) {
+ kfree(nreq);
+ goto outfail;
+ }
+ rpcx_to_rdmax(xprt)->rx_stats.hardway_register_count += size;
+ nreq->rl_size = size;
+ nreq->rl_niovs = 0;
+ nreq->rl_nchunks = 0;
+ nreq->rl_buffer = (struct rpcrdma_buffer *)req;
+ nreq->rl_reply = req->rl_reply;
+ memcpy(nreq->rl_segments,
+ req->rl_segments, sizeof nreq->rl_segments);
+ /* flag the swap with an unused field */
+ nreq->rl_iov.length = 0;
+ req->rl_reply = NULL;
+ req = nreq;
+ }
+ dprintk("RPC: %s: size %zd, request 0x%p\n", __func__, size, req);
+out:
+ return req->rl_xdr_buf;
+
+outfail:
+ rpcrdma_buffer_put(req);
+ rpcx_to_rdmax(xprt)->rx_stats.failed_marshal_count++;
+ return NULL;
+}
+
+/*
+ * This function returns all RDMA resources to the pool.
+ */
+static void
+xprt_rdma_free(void *buffer)
+{
+ struct rpcrdma_req *req;
+ struct rpcrdma_xprt *r_xprt;
+ struct rpcrdma_rep *rep;
+ int i;
+
+ if (buffer == NULL)
+ return;
+
+ req = container_of(buffer, struct rpcrdma_req, rl_xdr_buf[0]);
+ r_xprt = container_of(req->rl_buffer, struct rpcrdma_xprt, rx_buf);
+ rep = req->rl_reply;
+
+ dprintk("RPC: %s: called on 0x%p%s\n",
+ __func__, rep, (rep && rep->rr_func) ? " (with waiter)" : "");
+
+ /*
+ * Finish the deregistration. When using mw bind, this was
+ * begun in rpcrdma_reply_handler(). In all other modes, we
+ * do it here, in thread context. The process is considered
+ * complete when the rr_func vector becomes NULL - this
+ * was put in place during rpcrdma_reply_handler() - the wait
+ * call below will not block if the dereg is "done". If
+ * interrupted, our framework will clean up.
+ */
+ for (i = 0; req->rl_nchunks;) {
+ --req->rl_nchunks;
+ i += rpcrdma_deregister_external(
+ &req->rl_segments[i], r_xprt, NULL);
+ }
+
+ if (rep && wait_event_interruptible(rep->rr_unbind, !rep->rr_func)) {
+ rep->rr_func = NULL; /* abandon the callback */
+ req->rl_reply = NULL;
+ }
+
+ if (req->rl_iov.length == 0) { /* see allocate above */
+ struct rpcrdma_req *oreq = (struct rpcrdma_req *)req->rl_buffer;
+ oreq->rl_reply = req->rl_reply;
+ (void) rpcrdma_deregister_internal(&r_xprt->rx_ia,
+ req->rl_handle,
+ &req->rl_iov);
+ kfree(req);
+ req = oreq;
+ }
+
+ /* Put back request+reply buffers */
+ rpcrdma_buffer_put(req);
+}
+
+/*
+ * send_request invokes the meat of RPC RDMA. It must do the following:
+ * 1. Marshal the RPC request into an RPC RDMA request, which means
+ * putting a header in front of data, and creating IOVs for RDMA
+ * from those in the request.
+ * 2. In marshaling, detect opportunities for RDMA, and use them.
+ * 3. Post a recv message to set up asynch completion, then send
+ * the request (rpcrdma_ep_post).
+ * 4. No partial sends are possible in the RPC-RDMA protocol (as in UDP).
+ */
+
+static int
+xprt_rdma_send_request(struct rpc_task *task)
+{
+ struct rpc_rqst *rqst = task->tk_rqstp;
+ struct rpc_xprt *xprt = task->tk_xprt;
+ struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+ /* marshal the send itself */
+ if (req->rl_niovs == 0 && rpcrdma_marshal_req(rqst) != 0) {
+ r_xprt->rx_stats.failed_marshal_count++;
+ dprintk("RPC: %s: rpcrdma_marshal_req failed\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (req->rl_reply == NULL) /* e.g. reconnection */
+ rpcrdma_recv_buffer_get(req);
+
+ if (req->rl_reply) {
+ req->rl_reply->rr_func = rpcrdma_reply_handler;
+ /* this need only be done once, but... */
+ req->rl_reply->rr_xprt = xprt;
+ }
+
+ if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) {
+ xprt_disconnect(xprt);
+ return -ENOTCONN; /* implies disconnect */
+ }
+
+ rqst->rq_bytes_sent = 0;
+ return 0;
+}
+
+static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
+{
+ struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+ long idle_time = 0;
+
+ if (xprt_connected(xprt))
+ idle_time = (long)(jiffies - xprt->last_used) / HZ;
+
+ seq_printf(seq,
+ "\txprt:\trdma %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu "
+ "%lu %lu %lu %Lu %Lu %Lu %Lu %lu %lu %lu\n",
+
+ 0, /* need a local port? */
+ xprt->stat.bind_count,
+ xprt->stat.connect_count,
+ xprt->stat.connect_time,
+ idle_time,
+ xprt->stat.sends,
+ xprt->stat.recvs,
+ xprt->stat.bad_xids,
+ xprt->stat.req_u,
+ xprt->stat.bklog_u,
+
+ r_xprt->rx_stats.read_chunk_count,
+ r_xprt->rx_stats.write_chunk_count,
+ r_xprt->rx_stats.reply_chunk_count,
+ r_xprt->rx_stats.total_rdma_request,
+ r_xprt->rx_stats.total_rdma_reply,
+ r_xprt->rx_stats.pullup_copy_count,
+ r_xprt->rx_stats.fixup_copy_count,
+ r_xprt->rx_stats.hardway_register_count,
+ r_xprt->rx_stats.failed_marshal_count,
+ r_xprt->rx_stats.bad_reply_count);
+}
+
+/*
+ * Plumbing for rpc transport switch and kernel module
+ */
+
+static struct rpc_xprt_ops xprt_rdma_procs = {
+ .reserve_xprt = xprt_rdma_reserve_xprt,
+ .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */
+ .release_request = xprt_release_rqst_cong, /* ditto */
+ .set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */
+ .rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */
+ .set_port = xprt_rdma_set_port,
+ .connect = xprt_rdma_connect,
+ .buf_alloc = xprt_rdma_allocate,
+ .buf_free = xprt_rdma_free,
+ .send_request = xprt_rdma_send_request,
+ .close = xprt_rdma_close,
+ .destroy = xprt_rdma_destroy,
+ .print_stats = xprt_rdma_print_stats
+};
+
+static struct xprt_class xprt_rdma = {
+ .list = LIST_HEAD_INIT(xprt_rdma.list),
+ .name = "rdma",
+ .owner = THIS_MODULE,
+ .ident = XPRT_TRANSPORT_RDMA,
+ .setup = xprt_setup_rdma,
+};
+
+static void __exit xprt_rdma_cleanup(void)
+{
+ int rc;
+
+ dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n");
+#ifdef RPC_DEBUG
+ if (sunrpc_table_header) {
+ unregister_sysctl_table(sunrpc_table_header);
+ sunrpc_table_header = NULL;
+ }
+#endif
+ rc = xprt_unregister_transport(&xprt_rdma);
+ if (rc)
+ dprintk("RPC: %s: xprt_unregister returned %i\n",
+ __func__, rc);
+}
+
+static int __init xprt_rdma_init(void)
+{
+ int rc;
+
+ rc = xprt_register_transport(&xprt_rdma);
+
+ if (rc)
+ return rc;
+
+ dprintk(KERN_INFO "RPCRDMA Module Init, register RPC RDMA transport\n");
+
+ dprintk(KERN_INFO "Defaults:\n");
+ dprintk(KERN_INFO "\tSlots %d\n"
+ "\tMaxInlineRead %d\n\tMaxInlineWrite %d\n",
+ xprt_rdma_slot_table_entries,
+ xprt_rdma_max_inline_read, xprt_rdma_max_inline_write);
+ dprintk(KERN_INFO "\tPadding %d\n\tMemreg %d\n",
+ xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy);
+
+#ifdef RPC_DEBUG
+ if (!sunrpc_table_header)
+ sunrpc_table_header = register_sysctl_table(sunrpc_table);
+#endif
+ return 0;
+}
+
+module_init(xprt_rdma_init);
+module_exit(xprt_rdma_cleanup);
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
new file mode 100644
index 00000000000..9ec8ca4f602
--- /dev/null
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -0,0 +1,1626 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * verbs.c
+ *
+ * Encapsulates the major functions managing:
+ * o adapters
+ * o endpoints
+ * o connections
+ * o buffer memory
+ */
+
+#include <linux/pci.h> /* for Tavor hack below */
+
+#include "xprt_rdma.h"
+
+/*
+ * Globals/Macros
+ */
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_TRANS
+#endif
+
+/*
+ * internal functions
+ */
+
+/*
+ * handle replies in tasklet context, using a single, global list
+ * rdma tasklet function -- just turn around and call the func
+ * for all replies on the list
+ */
+
+static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
+static LIST_HEAD(rpcrdma_tasklets_g);
+
+static void
+rpcrdma_run_tasklet(unsigned long data)
+{
+ struct rpcrdma_rep *rep;
+ void (*func)(struct rpcrdma_rep *);
+ unsigned long flags;
+
+ data = data;
+ spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+ while (!list_empty(&rpcrdma_tasklets_g)) {
+ rep = list_entry(rpcrdma_tasklets_g.next,
+ struct rpcrdma_rep, rr_list);
+ list_del(&rep->rr_list);
+ func = rep->rr_func;
+ rep->rr_func = NULL;
+ spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+
+ if (func)
+ func(rep);
+ else
+ rpcrdma_recv_buffer_put(rep);
+
+ spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+ }
+ spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+}
+
+static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
+
+static inline void
+rpcrdma_schedule_tasklet(struct rpcrdma_rep *rep)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+ list_add_tail(&rep->rr_list, &rpcrdma_tasklets_g);
+ spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+ tasklet_schedule(&rpcrdma_tasklet_g);
+}
+
+static void
+rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
+{
+ struct rpcrdma_ep *ep = context;
+
+ dprintk("RPC: %s: QP error %X on device %s ep %p\n",
+ __func__, event->event, event->device->name, context);
+ if (ep->rep_connected == 1) {
+ ep->rep_connected = -EIO;
+ ep->rep_func(ep);
+ wake_up_all(&ep->rep_connect_wait);
+ }
+}
+
+static void
+rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
+{
+ struct rpcrdma_ep *ep = context;
+
+ dprintk("RPC: %s: CQ error %X on device %s ep %p\n",
+ __func__, event->event, event->device->name, context);
+ if (ep->rep_connected == 1) {
+ ep->rep_connected = -EIO;
+ ep->rep_func(ep);
+ wake_up_all(&ep->rep_connect_wait);
+ }
+}
+
+static inline
+void rpcrdma_event_process(struct ib_wc *wc)
+{
+ struct rpcrdma_rep *rep =
+ (struct rpcrdma_rep *)(unsigned long) wc->wr_id;
+
+ dprintk("RPC: %s: event rep %p status %X opcode %X length %u\n",
+ __func__, rep, wc->status, wc->opcode, wc->byte_len);
+
+ if (!rep) /* send or bind completion that we don't care about */
+ return;
+
+ if (IB_WC_SUCCESS != wc->status) {
+ dprintk("RPC: %s: %s WC status %X, connection lost\n",
+ __func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send",
+ wc->status);
+ rep->rr_len = ~0U;
+ rpcrdma_schedule_tasklet(rep);
+ return;
+ }
+
+ switch (wc->opcode) {
+ case IB_WC_RECV:
+ rep->rr_len = wc->byte_len;
+ ib_dma_sync_single_for_cpu(
+ rdmab_to_ia(rep->rr_buffer)->ri_id->device,
+ rep->rr_iov.addr, rep->rr_len, DMA_FROM_DEVICE);
+ /* Keep (only) the most recent credits, after check validity */
+ if (rep->rr_len >= 16) {
+ struct rpcrdma_msg *p =
+ (struct rpcrdma_msg *) rep->rr_base;
+ unsigned int credits = ntohl(p->rm_credit);
+ if (credits == 0) {
+ dprintk("RPC: %s: server"
+ " dropped credits to 0!\n", __func__);
+ /* don't deadlock */
+ credits = 1;
+ } else if (credits > rep->rr_buffer->rb_max_requests) {
+ dprintk("RPC: %s: server"
+ " over-crediting: %d (%d)\n",
+ __func__, credits,
+ rep->rr_buffer->rb_max_requests);
+ credits = rep->rr_buffer->rb_max_requests;
+ }
+ atomic_set(&rep->rr_buffer->rb_credits, credits);
+ }
+ /* fall through */
+ case IB_WC_BIND_MW:
+ rpcrdma_schedule_tasklet(rep);
+ break;
+ default:
+ dprintk("RPC: %s: unexpected WC event %X\n",
+ __func__, wc->opcode);
+ break;
+ }
+}
+
+static inline int
+rpcrdma_cq_poll(struct ib_cq *cq)
+{
+ struct ib_wc wc;
+ int rc;
+
+ for (;;) {
+ rc = ib_poll_cq(cq, 1, &wc);
+ if (rc < 0) {
+ dprintk("RPC: %s: ib_poll_cq failed %i\n",
+ __func__, rc);
+ return rc;
+ }
+ if (rc == 0)
+ break;
+
+ rpcrdma_event_process(&wc);
+ }
+
+ return 0;
+}
+
+/*
+ * rpcrdma_cq_event_upcall
+ *
+ * This upcall handles recv, send, bind and unbind events.
+ * It is reentrant but processes single events in order to maintain
+ * ordering of receives to keep server credits.
+ *
+ * It is the responsibility of the scheduled tasklet to return
+ * recv buffers to the pool. NOTE: this affects synchronization of
+ * connection shutdown. That is, the structures required for
+ * the completion of the reply handler must remain intact until
+ * all memory has been reclaimed.
+ *
+ * Note that send events are suppressed and do not result in an upcall.
+ */
+static void
+rpcrdma_cq_event_upcall(struct ib_cq *cq, void *context)
+{
+ int rc;
+
+ rc = rpcrdma_cq_poll(cq);
+ if (rc)
+ return;
+
+ rc = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+ if (rc) {
+ dprintk("RPC: %s: ib_req_notify_cq failed %i\n",
+ __func__, rc);
+ return;
+ }
+
+ rpcrdma_cq_poll(cq);
+}
+
+#ifdef RPC_DEBUG
+static const char * const conn[] = {
+ "address resolved",
+ "address error",
+ "route resolved",
+ "route error",
+ "connect request",
+ "connect response",
+ "connect error",
+ "unreachable",
+ "rejected",
+ "established",
+ "disconnected",
+ "device removal"
+};
+#endif
+
+static int
+rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
+{
+ struct rpcrdma_xprt *xprt = id->context;
+ struct rpcrdma_ia *ia = &xprt->rx_ia;
+ struct rpcrdma_ep *ep = &xprt->rx_ep;
+ struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr;
+ struct ib_qp_attr attr;
+ struct ib_qp_init_attr iattr;
+ int connstate = 0;
+
+ switch (event->event) {
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+ complete(&ia->ri_done);
+ break;
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ ia->ri_async_rc = -EHOSTUNREACH;
+ dprintk("RPC: %s: CM address resolution error, ep 0x%p\n",
+ __func__, ep);
+ complete(&ia->ri_done);
+ break;
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ ia->ri_async_rc = -ENETUNREACH;
+ dprintk("RPC: %s: CM route resolution error, ep 0x%p\n",
+ __func__, ep);
+ complete(&ia->ri_done);
+ break;
+ case RDMA_CM_EVENT_ESTABLISHED:
+ connstate = 1;
+ ib_query_qp(ia->ri_id->qp, &attr,
+ IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
+ &iattr);
+ dprintk("RPC: %s: %d responder resources"
+ " (%d initiator)\n",
+ __func__, attr.max_dest_rd_atomic, attr.max_rd_atomic);
+ goto connected;
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ connstate = -ENOTCONN;
+ goto connected;
+ case RDMA_CM_EVENT_UNREACHABLE:
+ connstate = -ENETDOWN;
+ goto connected;
+ case RDMA_CM_EVENT_REJECTED:
+ connstate = -ECONNREFUSED;
+ goto connected;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ connstate = -ECONNABORTED;
+ goto connected;
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ connstate = -ENODEV;
+connected:
+ dprintk("RPC: %s: %s: %u.%u.%u.%u:%u"
+ " (ep 0x%p event 0x%x)\n",
+ __func__,
+ (event->event <= 11) ? conn[event->event] :
+ "unknown connection error",
+ NIPQUAD(addr->sin_addr.s_addr),
+ ntohs(addr->sin_port),
+ ep, event->event);
+ atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1);
+ dprintk("RPC: %s: %sconnected\n",
+ __func__, connstate > 0 ? "" : "dis");
+ ep->rep_connected = connstate;
+ ep->rep_func(ep);
+ wake_up_all(&ep->rep_connect_wait);
+ break;
+ default:
+ ia->ri_async_rc = -EINVAL;
+ dprintk("RPC: %s: unexpected CM event %X\n",
+ __func__, event->event);
+ complete(&ia->ri_done);
+ break;
+ }
+
+ return 0;
+}
+
+static struct rdma_cm_id *
+rpcrdma_create_id(struct rpcrdma_xprt *xprt,
+ struct rpcrdma_ia *ia, struct sockaddr *addr)
+{
+ struct rdma_cm_id *id;
+ int rc;
+
+ id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP);
+ if (IS_ERR(id)) {
+ rc = PTR_ERR(id);
+ dprintk("RPC: %s: rdma_create_id() failed %i\n",
+ __func__, rc);
+ return id;
+ }
+
+ ia->ri_async_rc = 0;
+ rc = rdma_resolve_addr(id, NULL, addr, RDMA_RESOLVE_TIMEOUT);
+ if (rc) {
+ dprintk("RPC: %s: rdma_resolve_addr() failed %i\n",
+ __func__, rc);
+ goto out;
+ }
+ wait_for_completion(&ia->ri_done);
+ rc = ia->ri_async_rc;
+ if (rc)
+ goto out;
+
+ ia->ri_async_rc = 0;
+ rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
+ if (rc) {
+ dprintk("RPC: %s: rdma_resolve_route() failed %i\n",
+ __func__, rc);
+ goto out;
+ }
+ wait_for_completion(&ia->ri_done);
+ rc = ia->ri_async_rc;
+ if (rc)
+ goto out;
+
+ return id;
+
+out:
+ rdma_destroy_id(id);
+ return ERR_PTR(rc);
+}
+
+/*
+ * Drain any cq, prior to teardown.
+ */
+static void
+rpcrdma_clean_cq(struct ib_cq *cq)
+{
+ struct ib_wc wc;
+ int count = 0;
+
+ while (1 == ib_poll_cq(cq, 1, &wc))
+ ++count;
+
+ if (count)
+ dprintk("RPC: %s: flushed %d events (last 0x%x)\n",
+ __func__, count, wc.opcode);
+}
+
+/*
+ * Exported functions.
+ */
+
+/*
+ * Open and initialize an Interface Adapter.
+ * o initializes fields of struct rpcrdma_ia, including
+ * interface and provider attributes and protection zone.
+ */
+int
+rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
+{
+ int rc;
+ struct rpcrdma_ia *ia = &xprt->rx_ia;
+
+ init_completion(&ia->ri_done);
+
+ ia->ri_id = rpcrdma_create_id(xprt, ia, addr);
+ if (IS_ERR(ia->ri_id)) {
+ rc = PTR_ERR(ia->ri_id);
+ goto out1;
+ }
+
+ ia->ri_pd = ib_alloc_pd(ia->ri_id->device);
+ if (IS_ERR(ia->ri_pd)) {
+ rc = PTR_ERR(ia->ri_pd);
+ dprintk("RPC: %s: ib_alloc_pd() failed %i\n",
+ __func__, rc);
+ goto out2;
+ }
+
+ /*
+ * Optionally obtain an underlying physical identity mapping in
+ * order to do a memory window-based bind. This base registration
+ * is protected from remote access - that is enabled only by binding
+ * for the specific bytes targeted during each RPC operation, and
+ * revoked after the corresponding completion similar to a storage
+ * adapter.
+ */
+ if (memreg > RPCRDMA_REGISTER) {
+ int mem_priv = IB_ACCESS_LOCAL_WRITE;
+ switch (memreg) {
+#if RPCRDMA_PERSISTENT_REGISTRATION
+ case RPCRDMA_ALLPHYSICAL:
+ mem_priv |= IB_ACCESS_REMOTE_WRITE;
+ mem_priv |= IB_ACCESS_REMOTE_READ;
+ break;
+#endif
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ mem_priv |= IB_ACCESS_MW_BIND;
+ break;
+ default:
+ break;
+ }
+ ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
+ if (IS_ERR(ia->ri_bind_mem)) {
+ printk(KERN_ALERT "%s: ib_get_dma_mr for "
+ "phys register failed with %lX\n\t"
+ "Will continue with degraded performance\n",
+ __func__, PTR_ERR(ia->ri_bind_mem));
+ memreg = RPCRDMA_REGISTER;
+ ia->ri_bind_mem = NULL;
+ }
+ }
+
+ /* Else will do memory reg/dereg for each chunk */
+ ia->ri_memreg_strategy = memreg;
+
+ return 0;
+out2:
+ rdma_destroy_id(ia->ri_id);
+out1:
+ return rc;
+}
+
+/*
+ * Clean up/close an IA.
+ * o if event handles and PD have been initialized, free them.
+ * o close the IA
+ */
+void
+rpcrdma_ia_close(struct rpcrdma_ia *ia)
+{
+ int rc;
+
+ dprintk("RPC: %s: entering\n", __func__);
+ if (ia->ri_bind_mem != NULL) {
+ rc = ib_dereg_mr(ia->ri_bind_mem);
+ dprintk("RPC: %s: ib_dereg_mr returned %i\n",
+ __func__, rc);
+ }
+ if (ia->ri_id != NULL && !IS_ERR(ia->ri_id) && ia->ri_id->qp)
+ rdma_destroy_qp(ia->ri_id);
+ if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
+ rc = ib_dealloc_pd(ia->ri_pd);
+ dprintk("RPC: %s: ib_dealloc_pd returned %i\n",
+ __func__, rc);
+ }
+ if (ia->ri_id != NULL && !IS_ERR(ia->ri_id))
+ rdma_destroy_id(ia->ri_id);
+}
+
+/*
+ * Create unconnected endpoint.
+ */
+int
+rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
+ struct rpcrdma_create_data_internal *cdata)
+{
+ struct ib_device_attr devattr;
+ int rc;
+
+ rc = ib_query_device(ia->ri_id->device, &devattr);
+ if (rc) {
+ dprintk("RPC: %s: ib_query_device failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* check provider's send/recv wr limits */
+ if (cdata->max_requests > devattr.max_qp_wr)
+ cdata->max_requests = devattr.max_qp_wr;
+
+ ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
+ ep->rep_attr.qp_context = ep;
+ /* send_cq and recv_cq initialized below */
+ ep->rep_attr.srq = NULL;
+ ep->rep_attr.cap.max_send_wr = cdata->max_requests;
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ /* Add room for mw_binds+unbinds - overkill! */
+ ep->rep_attr.cap.max_send_wr++;
+ ep->rep_attr.cap.max_send_wr *= (2 * RPCRDMA_MAX_SEGS);
+ if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
+ ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
+ ep->rep_attr.cap.max_recv_sge = 1;
+ ep->rep_attr.cap.max_inline_data = 0;
+ ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+ ep->rep_attr.qp_type = IB_QPT_RC;
+ ep->rep_attr.port_num = ~0;
+
+ dprintk("RPC: %s: requested max: dtos: send %d recv %d; "
+ "iovs: send %d recv %d\n",
+ __func__,
+ ep->rep_attr.cap.max_send_wr,
+ ep->rep_attr.cap.max_recv_wr,
+ ep->rep_attr.cap.max_send_sge,
+ ep->rep_attr.cap.max_recv_sge);
+
+ /* set trigger for requesting send completion */
+ ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 /* - 1*/;
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ ep->rep_cqinit -= RPCRDMA_MAX_SEGS;
+ break;
+ default:
+ break;
+ }
+ if (ep->rep_cqinit <= 2)
+ ep->rep_cqinit = 0;
+ INIT_CQCOUNT(ep);
+ ep->rep_ia = ia;
+ init_waitqueue_head(&ep->rep_connect_wait);
+
+ /*
+ * Create a single cq for receive dto and mw_bind (only ever
+ * care about unbind, really). Send completions are suppressed.
+ * Use single threaded tasklet upcalls to maintain ordering.
+ */
+ ep->rep_cq = ib_create_cq(ia->ri_id->device, rpcrdma_cq_event_upcall,
+ rpcrdma_cq_async_error_upcall, NULL,
+ ep->rep_attr.cap.max_recv_wr +
+ ep->rep_attr.cap.max_send_wr + 1, 0);
+ if (IS_ERR(ep->rep_cq)) {
+ rc = PTR_ERR(ep->rep_cq);
+ dprintk("RPC: %s: ib_create_cq failed: %i\n",
+ __func__, rc);
+ goto out1;
+ }
+
+ rc = ib_req_notify_cq(ep->rep_cq, IB_CQ_NEXT_COMP);
+ if (rc) {
+ dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
+ __func__, rc);
+ goto out2;
+ }
+
+ ep->rep_attr.send_cq = ep->rep_cq;
+ ep->rep_attr.recv_cq = ep->rep_cq;
+
+ /* Initialize cma parameters */
+
+ /* RPC/RDMA does not use private data */
+ ep->rep_remote_cma.private_data = NULL;
+ ep->rep_remote_cma.private_data_len = 0;
+
+ /* Client offers RDMA Read but does not initiate */
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_BOUNCEBUFFERS:
+ ep->rep_remote_cma.responder_resources = 0;
+ break;
+ case RPCRDMA_MTHCAFMR:
+ case RPCRDMA_REGISTER:
+ ep->rep_remote_cma.responder_resources = cdata->max_requests *
+ (RPCRDMA_MAX_DATA_SEGS / 8);
+ break;
+ case RPCRDMA_MEMWINDOWS:
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+#if RPCRDMA_PERSISTENT_REGISTRATION
+ case RPCRDMA_ALLPHYSICAL:
+#endif
+ ep->rep_remote_cma.responder_resources = cdata->max_requests *
+ (RPCRDMA_MAX_DATA_SEGS / 2);
+ break;
+ default:
+ break;
+ }
+ if (ep->rep_remote_cma.responder_resources > devattr.max_qp_rd_atom)
+ ep->rep_remote_cma.responder_resources = devattr.max_qp_rd_atom;
+ ep->rep_remote_cma.initiator_depth = 0;
+
+ ep->rep_remote_cma.retry_count = 7;
+ ep->rep_remote_cma.flow_control = 0;
+ ep->rep_remote_cma.rnr_retry_count = 0;
+
+ return 0;
+
+out2:
+ if (ib_destroy_cq(ep->rep_cq))
+ ;
+out1:
+ return rc;
+}
+
+/*
+ * rpcrdma_ep_destroy
+ *
+ * Disconnect and destroy endpoint. After this, the only
+ * valid operations on the ep are to free it (if dynamically
+ * allocated) or re-create it.
+ *
+ * The caller's error handling must be sure to not leak the endpoint
+ * if this function fails.
+ */
+int
+rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+ int rc;
+
+ dprintk("RPC: %s: entering, connected is %d\n",
+ __func__, ep->rep_connected);
+
+ if (ia->ri_id->qp) {
+ rc = rpcrdma_ep_disconnect(ep, ia);
+ if (rc)
+ dprintk("RPC: %s: rpcrdma_ep_disconnect"
+ " returned %i\n", __func__, rc);
+ }
+
+ ep->rep_func = NULL;
+
+ /* padding - could be done in rpcrdma_buffer_destroy... */
+ if (ep->rep_pad_mr) {
+ rpcrdma_deregister_internal(ia, ep->rep_pad_mr, &ep->rep_pad);
+ ep->rep_pad_mr = NULL;
+ }
+
+ if (ia->ri_id->qp) {
+ rdma_destroy_qp(ia->ri_id);
+ ia->ri_id->qp = NULL;
+ }
+
+ rpcrdma_clean_cq(ep->rep_cq);
+ rc = ib_destroy_cq(ep->rep_cq);
+ if (rc)
+ dprintk("RPC: %s: ib_destroy_cq returned %i\n",
+ __func__, rc);
+
+ return rc;
+}
+
+/*
+ * Connect unconnected endpoint.
+ */
+int
+rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+ struct rdma_cm_id *id;
+ int rc = 0;
+ int retry_count = 0;
+ int reconnect = (ep->rep_connected != 0);
+
+ if (reconnect) {
+ struct rpcrdma_xprt *xprt;
+retry:
+ rc = rpcrdma_ep_disconnect(ep, ia);
+ if (rc && rc != -ENOTCONN)
+ dprintk("RPC: %s: rpcrdma_ep_disconnect"
+ " status %i\n", __func__, rc);
+ rpcrdma_clean_cq(ep->rep_cq);
+
+ xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
+ id = rpcrdma_create_id(xprt, ia,
+ (struct sockaddr *)&xprt->rx_data.addr);
+ if (IS_ERR(id)) {
+ rc = PTR_ERR(id);
+ goto out;
+ }
+ /* TEMP TEMP TEMP - fail if new device:
+ * Deregister/remarshal *all* requests!
+ * Close and recreate adapter, pd, etc!
+ * Re-determine all attributes still sane!
+ * More stuff I haven't thought of!
+ * Rrrgh!
+ */
+ if (ia->ri_id->device != id->device) {
+ printk("RPC: %s: can't reconnect on "
+ "different device!\n", __func__);
+ rdma_destroy_id(id);
+ rc = -ENETDOWN;
+ goto out;
+ }
+ /* END TEMP */
+ rdma_destroy_id(ia->ri_id);
+ ia->ri_id = id;
+ }
+
+ rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
+ if (rc) {
+ dprintk("RPC: %s: rdma_create_qp failed %i\n",
+ __func__, rc);
+ goto out;
+ }
+
+/* XXX Tavor device performs badly with 2K MTU! */
+if (strnicmp(ia->ri_id->device->dma_device->bus->name, "pci", 3) == 0) {
+ struct pci_dev *pcid = to_pci_dev(ia->ri_id->device->dma_device);
+ if (pcid->device == PCI_DEVICE_ID_MELLANOX_TAVOR &&
+ (pcid->vendor == PCI_VENDOR_ID_MELLANOX ||
+ pcid->vendor == PCI_VENDOR_ID_TOPSPIN)) {
+ struct ib_qp_attr attr = {
+ .path_mtu = IB_MTU_1024
+ };
+ rc = ib_modify_qp(ia->ri_id->qp, &attr, IB_QP_PATH_MTU);
+ }
+}
+
+ /* Theoretically a client initiator_depth > 0 is not needed,
+ * but many peers fail to complete the connection unless they
+ * == responder_resources! */
+ if (ep->rep_remote_cma.initiator_depth !=
+ ep->rep_remote_cma.responder_resources)
+ ep->rep_remote_cma.initiator_depth =
+ ep->rep_remote_cma.responder_resources;
+
+ ep->rep_connected = 0;
+
+ rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
+ if (rc) {
+ dprintk("RPC: %s: rdma_connect() failed with %i\n",
+ __func__, rc);
+ goto out;
+ }
+
+ if (reconnect)
+ return 0;
+
+ wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
+
+ /*
+ * Check state. A non-peer reject indicates no listener
+ * (ECONNREFUSED), which may be a transient state. All
+ * others indicate a transport condition which has already
+ * undergone a best-effort.
+ */
+ if (ep->rep_connected == -ECONNREFUSED
+ && ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
+ dprintk("RPC: %s: non-peer_reject, retry\n", __func__);
+ goto retry;
+ }
+ if (ep->rep_connected <= 0) {
+ /* Sometimes, the only way to reliably connect to remote
+ * CMs is to use same nonzero values for ORD and IRD. */
+ ep->rep_remote_cma.initiator_depth =
+ ep->rep_remote_cma.responder_resources;
+ if (ep->rep_remote_cma.initiator_depth == 0)
+ ++ep->rep_remote_cma.initiator_depth;
+ if (ep->rep_remote_cma.responder_resources == 0)
+ ++ep->rep_remote_cma.responder_resources;
+ if (retry_count++ == 0)
+ goto retry;
+ rc = ep->rep_connected;
+ } else {
+ dprintk("RPC: %s: connected\n", __func__);
+ }
+
+out:
+ if (rc)
+ ep->rep_connected = rc;
+ return rc;
+}
+
+/*
+ * rpcrdma_ep_disconnect
+ *
+ * This is separate from destroy to facilitate the ability
+ * to reconnect without recreating the endpoint.
+ *
+ * This call is not reentrant, and must not be made in parallel
+ * on the same endpoint.
+ */
+int
+rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+ int rc;
+
+ rpcrdma_clean_cq(ep->rep_cq);
+ rc = rdma_disconnect(ia->ri_id);
+ if (!rc) {
+ /* returns without wait if not connected */
+ wait_event_interruptible(ep->rep_connect_wait,
+ ep->rep_connected != 1);
+ dprintk("RPC: %s: after wait, %sconnected\n", __func__,
+ (ep->rep_connected == 1) ? "still " : "dis");
+ } else {
+ dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc);
+ ep->rep_connected = rc;
+ }
+ return rc;
+}
+
+/*
+ * Initialize buffer memory
+ */
+int
+rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep,
+ struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata)
+{
+ char *p;
+ size_t len;
+ int i, rc;
+
+ buf->rb_max_requests = cdata->max_requests;
+ spin_lock_init(&buf->rb_lock);
+ atomic_set(&buf->rb_credits, 1);
+
+ /* Need to allocate:
+ * 1. arrays for send and recv pointers
+ * 2. arrays of struct rpcrdma_req to fill in pointers
+ * 3. array of struct rpcrdma_rep for replies
+ * 4. padding, if any
+ * 5. mw's, if any
+ * Send/recv buffers in req/rep need to be registered
+ */
+
+ len = buf->rb_max_requests *
+ (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
+ len += cdata->padding;
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MTHCAFMR:
+ /* TBD we are perhaps overallocating here */
+ len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS *
+ sizeof(struct rpcrdma_mw);
+ break;
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS *
+ sizeof(struct rpcrdma_mw);
+ break;
+ default:
+ break;
+ }
+
+ /* allocate 1, 4 and 5 in one shot */
+ p = kzalloc(len, GFP_KERNEL);
+ if (p == NULL) {
+ dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
+ __func__, len);
+ rc = -ENOMEM;
+ goto out;
+ }
+ buf->rb_pool = p; /* for freeing it later */
+
+ buf->rb_send_bufs = (struct rpcrdma_req **) p;
+ p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
+ buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
+ p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
+
+ /*
+ * Register the zeroed pad buffer, if any.
+ */
+ if (cdata->padding) {
+ rc = rpcrdma_register_internal(ia, p, cdata->padding,
+ &ep->rep_pad_mr, &ep->rep_pad);
+ if (rc)
+ goto out;
+ }
+ p += cdata->padding;
+
+ /*
+ * Allocate the fmr's, or mw's for mw_bind chunk registration.
+ * We "cycle" the mw's in order to minimize rkey reuse,
+ * and also reduce unbind-to-bind collision.
+ */
+ INIT_LIST_HEAD(&buf->rb_mws);
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MTHCAFMR:
+ {
+ struct rpcrdma_mw *r = (struct rpcrdma_mw *)p;
+ struct ib_fmr_attr fa = {
+ RPCRDMA_MAX_DATA_SEGS, 1, PAGE_SHIFT
+ };
+ /* TBD we are perhaps overallocating here */
+ for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) {
+ r->r.fmr = ib_alloc_fmr(ia->ri_pd,
+ IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ,
+ &fa);
+ if (IS_ERR(r->r.fmr)) {
+ rc = PTR_ERR(r->r.fmr);
+ dprintk("RPC: %s: ib_alloc_fmr"
+ " failed %i\n", __func__, rc);
+ goto out;
+ }
+ list_add(&r->mw_list, &buf->rb_mws);
+ ++r;
+ }
+ }
+ break;
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ {
+ struct rpcrdma_mw *r = (struct rpcrdma_mw *)p;
+ /* Allocate one extra request's worth, for full cycling */
+ for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) {
+ r->r.mw = ib_alloc_mw(ia->ri_pd);
+ if (IS_ERR(r->r.mw)) {
+ rc = PTR_ERR(r->r.mw);
+ dprintk("RPC: %s: ib_alloc_mw"
+ " failed %i\n", __func__, rc);
+ goto out;
+ }
+ list_add(&r->mw_list, &buf->rb_mws);
+ ++r;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Allocate/init the request/reply buffers. Doing this
+ * using kmalloc for now -- one for each buf.
+ */
+ for (i = 0; i < buf->rb_max_requests; i++) {
+ struct rpcrdma_req *req;
+ struct rpcrdma_rep *rep;
+
+ len = cdata->inline_wsize + sizeof(struct rpcrdma_req);
+ /* RPC layer requests *double* size + 1K RPC_SLACK_SPACE! */
+ /* Typical ~2400b, so rounding up saves work later */
+ if (len < 4096)
+ len = 4096;
+ req = kmalloc(len, GFP_KERNEL);
+ if (req == NULL) {
+ dprintk("RPC: %s: request buffer %d alloc"
+ " failed\n", __func__, i);
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(req, 0, sizeof(struct rpcrdma_req));
+ buf->rb_send_bufs[i] = req;
+ buf->rb_send_bufs[i]->rl_buffer = buf;
+
+ rc = rpcrdma_register_internal(ia, req->rl_base,
+ len - offsetof(struct rpcrdma_req, rl_base),
+ &buf->rb_send_bufs[i]->rl_handle,
+ &buf->rb_send_bufs[i]->rl_iov);
+ if (rc)
+ goto out;
+
+ buf->rb_send_bufs[i]->rl_size = len-sizeof(struct rpcrdma_req);
+
+ len = cdata->inline_rsize + sizeof(struct rpcrdma_rep);
+ rep = kmalloc(len, GFP_KERNEL);
+ if (rep == NULL) {
+ dprintk("RPC: %s: reply buffer %d alloc failed\n",
+ __func__, i);
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(rep, 0, sizeof(struct rpcrdma_rep));
+ buf->rb_recv_bufs[i] = rep;
+ buf->rb_recv_bufs[i]->rr_buffer = buf;
+ init_waitqueue_head(&rep->rr_unbind);
+
+ rc = rpcrdma_register_internal(ia, rep->rr_base,
+ len - offsetof(struct rpcrdma_rep, rr_base),
+ &buf->rb_recv_bufs[i]->rr_handle,
+ &buf->rb_recv_bufs[i]->rr_iov);
+ if (rc)
+ goto out;
+
+ }
+ dprintk("RPC: %s: max_requests %d\n",
+ __func__, buf->rb_max_requests);
+ /* done */
+ return 0;
+out:
+ rpcrdma_buffer_destroy(buf);
+ return rc;
+}
+
+/*
+ * Unregister and destroy buffer memory. Need to deal with
+ * partial initialization, so it's callable from failed create.
+ * Must be called before destroying endpoint, as registrations
+ * reference it.
+ */
+void
+rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
+{
+ int rc, i;
+ struct rpcrdma_ia *ia = rdmab_to_ia(buf);
+
+ /* clean up in reverse order from create
+ * 1. recv mr memory (mr free, then kfree)
+ * 1a. bind mw memory
+ * 2. send mr memory (mr free, then kfree)
+ * 3. padding (if any) [moved to rpcrdma_ep_destroy]
+ * 4. arrays
+ */
+ dprintk("RPC: %s: entering\n", __func__);
+
+ for (i = 0; i < buf->rb_max_requests; i++) {
+ if (buf->rb_recv_bufs && buf->rb_recv_bufs[i]) {
+ rpcrdma_deregister_internal(ia,
+ buf->rb_recv_bufs[i]->rr_handle,
+ &buf->rb_recv_bufs[i]->rr_iov);
+ kfree(buf->rb_recv_bufs[i]);
+ }
+ if (buf->rb_send_bufs && buf->rb_send_bufs[i]) {
+ while (!list_empty(&buf->rb_mws)) {
+ struct rpcrdma_mw *r;
+ r = list_entry(buf->rb_mws.next,
+ struct rpcrdma_mw, mw_list);
+ list_del(&r->mw_list);
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MTHCAFMR:
+ rc = ib_dealloc_fmr(r->r.fmr);
+ if (rc)
+ dprintk("RPC: %s:"
+ " ib_dealloc_fmr"
+ " failed %i\n",
+ __func__, rc);
+ break;
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ rc = ib_dealloc_mw(r->r.mw);
+ if (rc)
+ dprintk("RPC: %s:"
+ " ib_dealloc_mw"
+ " failed %i\n",
+ __func__, rc);
+ break;
+ default:
+ break;
+ }
+ }
+ rpcrdma_deregister_internal(ia,
+ buf->rb_send_bufs[i]->rl_handle,
+ &buf->rb_send_bufs[i]->rl_iov);
+ kfree(buf->rb_send_bufs[i]);
+ }
+ }
+
+ kfree(buf->rb_pool);
+}
+
+/*
+ * Get a set of request/reply buffers.
+ *
+ * Reply buffer (if needed) is attached to send buffer upon return.
+ * Rule:
+ * rb_send_index and rb_recv_index MUST always be pointing to the
+ * *next* available buffer (non-NULL). They are incremented after
+ * removing buffers, and decremented *before* returning them.
+ */
+struct rpcrdma_req *
+rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
+{
+ struct rpcrdma_req *req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&buffers->rb_lock, flags);
+ if (buffers->rb_send_index == buffers->rb_max_requests) {
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
+ dprintk("RPC: %s: out of request buffers\n", __func__);
+ return ((struct rpcrdma_req *)NULL);
+ }
+
+ req = buffers->rb_send_bufs[buffers->rb_send_index];
+ if (buffers->rb_send_index < buffers->rb_recv_index) {
+ dprintk("RPC: %s: %d extra receives outstanding (ok)\n",
+ __func__,
+ buffers->rb_recv_index - buffers->rb_send_index);
+ req->rl_reply = NULL;
+ } else {
+ req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
+ buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
+ }
+ buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
+ if (!list_empty(&buffers->rb_mws)) {
+ int i = RPCRDMA_MAX_SEGS - 1;
+ do {
+ struct rpcrdma_mw *r;
+ r = list_entry(buffers->rb_mws.next,
+ struct rpcrdma_mw, mw_list);
+ list_del(&r->mw_list);
+ req->rl_segments[i].mr_chunk.rl_mw = r;
+ } while (--i >= 0);
+ }
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
+ return req;
+}
+
+/*
+ * Put request/reply buffers back into pool.
+ * Pre-decrement counter/array index.
+ */
+void
+rpcrdma_buffer_put(struct rpcrdma_req *req)
+{
+ struct rpcrdma_buffer *buffers = req->rl_buffer;
+ struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
+ int i;
+ unsigned long flags;
+
+ BUG_ON(req->rl_nchunks != 0);
+ spin_lock_irqsave(&buffers->rb_lock, flags);
+ buffers->rb_send_bufs[--buffers->rb_send_index] = req;
+ req->rl_niovs = 0;
+ if (req->rl_reply) {
+ buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply;
+ init_waitqueue_head(&req->rl_reply->rr_unbind);
+ req->rl_reply->rr_func = NULL;
+ req->rl_reply = NULL;
+ }
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_MTHCAFMR:
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ /*
+ * Cycle mw's back in reverse order, and "spin" them.
+ * This delays and scrambles reuse as much as possible.
+ */
+ i = 1;
+ do {
+ struct rpcrdma_mw **mw;
+ mw = &req->rl_segments[i].mr_chunk.rl_mw;
+ list_add_tail(&(*mw)->mw_list, &buffers->rb_mws);
+ *mw = NULL;
+ } while (++i < RPCRDMA_MAX_SEGS);
+ list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list,
+ &buffers->rb_mws);
+ req->rl_segments[0].mr_chunk.rl_mw = NULL;
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Recover reply buffers from pool.
+ * This happens when recovering from error conditions.
+ * Post-increment counter/array index.
+ */
+void
+rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
+{
+ struct rpcrdma_buffer *buffers = req->rl_buffer;
+ unsigned long flags;
+
+ if (req->rl_iov.length == 0) /* special case xprt_rdma_allocate() */
+ buffers = ((struct rpcrdma_req *) buffers)->rl_buffer;
+ spin_lock_irqsave(&buffers->rb_lock, flags);
+ if (buffers->rb_recv_index < buffers->rb_max_requests) {
+ req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
+ buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
+ }
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Put reply buffers back into pool when not attached to
+ * request. This happens in error conditions, and when
+ * aborting unbinds. Pre-decrement counter/array index.
+ */
+void
+rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
+{
+ struct rpcrdma_buffer *buffers = rep->rr_buffer;
+ unsigned long flags;
+
+ rep->rr_func = NULL;
+ spin_lock_irqsave(&buffers->rb_lock, flags);
+ buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Wrappers for internal-use kmalloc memory registration, used by buffer code.
+ */
+
+int
+rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
+ struct ib_mr **mrp, struct ib_sge *iov)
+{
+ struct ib_phys_buf ipb;
+ struct ib_mr *mr;
+ int rc;
+
+ /*
+ * All memory passed here was kmalloc'ed, therefore phys-contiguous.
+ */
+ iov->addr = ib_dma_map_single(ia->ri_id->device,
+ va, len, DMA_BIDIRECTIONAL);
+ iov->length = len;
+
+ if (ia->ri_bind_mem != NULL) {
+ *mrp = NULL;
+ iov->lkey = ia->ri_bind_mem->lkey;
+ return 0;
+ }
+
+ ipb.addr = iov->addr;
+ ipb.size = iov->length;
+ mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
+ IB_ACCESS_LOCAL_WRITE, &iov->addr);
+
+ dprintk("RPC: %s: phys convert: 0x%llx "
+ "registered 0x%llx length %d\n",
+ __func__, ipb.addr, iov->addr, len);
+
+ if (IS_ERR(mr)) {
+ *mrp = NULL;
+ rc = PTR_ERR(mr);
+ dprintk("RPC: %s: failed with %i\n", __func__, rc);
+ } else {
+ *mrp = mr;
+ iov->lkey = mr->lkey;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int
+rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
+ struct ib_mr *mr, struct ib_sge *iov)
+{
+ int rc;
+
+ ib_dma_unmap_single(ia->ri_id->device,
+ iov->addr, iov->length, DMA_BIDIRECTIONAL);
+
+ if (NULL == mr)
+ return 0;
+
+ rc = ib_dereg_mr(mr);
+ if (rc)
+ dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc);
+ return rc;
+}
+
+/*
+ * Wrappers for chunk registration, shared by read/write chunk code.
+ */
+
+static void
+rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
+{
+ seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ seg->mr_dmalen = seg->mr_len;
+ if (seg->mr_page)
+ seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
+ seg->mr_page, offset_in_page(seg->mr_offset),
+ seg->mr_dmalen, seg->mr_dir);
+ else
+ seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
+ seg->mr_offset,
+ seg->mr_dmalen, seg->mr_dir);
+}
+
+static void
+rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
+{
+ if (seg->mr_page)
+ ib_dma_unmap_page(ia->ri_id->device,
+ seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
+ else
+ ib_dma_unmap_single(ia->ri_id->device,
+ seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
+}
+
+int
+rpcrdma_register_external(struct rpcrdma_mr_seg *seg,
+ int nsegs, int writing, struct rpcrdma_xprt *r_xprt)
+{
+ struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+ int mem_priv = (writing ? IB_ACCESS_REMOTE_WRITE :
+ IB_ACCESS_REMOTE_READ);
+ struct rpcrdma_mr_seg *seg1 = seg;
+ int i;
+ int rc = 0;
+
+ switch (ia->ri_memreg_strategy) {
+
+#if RPCRDMA_PERSISTENT_REGISTRATION
+ case RPCRDMA_ALLPHYSICAL:
+ rpcrdma_map_one(ia, seg, writing);
+ seg->mr_rkey = ia->ri_bind_mem->rkey;
+ seg->mr_base = seg->mr_dma;
+ seg->mr_nsegs = 1;
+ nsegs = 1;
+ break;
+#endif
+
+ /* Registration using fast memory registration */
+ case RPCRDMA_MTHCAFMR:
+ {
+ u64 physaddrs[RPCRDMA_MAX_DATA_SEGS];
+ int len, pageoff = offset_in_page(seg->mr_offset);
+ seg1->mr_offset -= pageoff; /* start of page */
+ seg1->mr_len += pageoff;
+ len = -pageoff;
+ if (nsegs > RPCRDMA_MAX_DATA_SEGS)
+ nsegs = RPCRDMA_MAX_DATA_SEGS;
+ for (i = 0; i < nsegs;) {
+ rpcrdma_map_one(ia, seg, writing);
+ physaddrs[i] = seg->mr_dma;
+ len += seg->mr_len;
+ ++seg;
+ ++i;
+ /* Check for holes */
+ if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
+ offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len))
+ break;
+ }
+ nsegs = i;
+ rc = ib_map_phys_fmr(seg1->mr_chunk.rl_mw->r.fmr,
+ physaddrs, nsegs, seg1->mr_dma);
+ if (rc) {
+ dprintk("RPC: %s: failed ib_map_phys_fmr "
+ "%u@0x%llx+%i (%d)... status %i\n", __func__,
+ len, (unsigned long long)seg1->mr_dma,
+ pageoff, nsegs, rc);
+ while (nsegs--)
+ rpcrdma_unmap_one(ia, --seg);
+ } else {
+ seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.fmr->rkey;
+ seg1->mr_base = seg1->mr_dma + pageoff;
+ seg1->mr_nsegs = nsegs;
+ seg1->mr_len = len;
+ }
+ }
+ break;
+
+ /* Registration using memory windows */
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ {
+ struct ib_mw_bind param;
+ rpcrdma_map_one(ia, seg, writing);
+ param.mr = ia->ri_bind_mem;
+ param.wr_id = 0ULL; /* no send cookie */
+ param.addr = seg->mr_dma;
+ param.length = seg->mr_len;
+ param.send_flags = 0;
+ param.mw_access_flags = mem_priv;
+
+ DECR_CQCOUNT(&r_xprt->rx_ep);
+ rc = ib_bind_mw(ia->ri_id->qp,
+ seg->mr_chunk.rl_mw->r.mw, &param);
+ if (rc) {
+ dprintk("RPC: %s: failed ib_bind_mw "
+ "%u@0x%llx status %i\n",
+ __func__, seg->mr_len,
+ (unsigned long long)seg->mr_dma, rc);
+ rpcrdma_unmap_one(ia, seg);
+ } else {
+ seg->mr_rkey = seg->mr_chunk.rl_mw->r.mw->rkey;
+ seg->mr_base = param.addr;
+ seg->mr_nsegs = 1;
+ nsegs = 1;
+ }
+ }
+ break;
+
+ /* Default registration each time */
+ default:
+ {
+ struct ib_phys_buf ipb[RPCRDMA_MAX_DATA_SEGS];
+ int len = 0;
+ if (nsegs > RPCRDMA_MAX_DATA_SEGS)
+ nsegs = RPCRDMA_MAX_DATA_SEGS;
+ for (i = 0; i < nsegs;) {
+ rpcrdma_map_one(ia, seg, writing);
+ ipb[i].addr = seg->mr_dma;
+ ipb[i].size = seg->mr_len;
+ len += seg->mr_len;
+ ++seg;
+ ++i;
+ /* Check for holes */
+ if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
+ offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len))
+ break;
+ }
+ nsegs = i;
+ seg1->mr_base = seg1->mr_dma;
+ seg1->mr_chunk.rl_mr = ib_reg_phys_mr(ia->ri_pd,
+ ipb, nsegs, mem_priv, &seg1->mr_base);
+ if (IS_ERR(seg1->mr_chunk.rl_mr)) {
+ rc = PTR_ERR(seg1->mr_chunk.rl_mr);
+ dprintk("RPC: %s: failed ib_reg_phys_mr "
+ "%u@0x%llx (%d)... status %i\n",
+ __func__, len,
+ (unsigned long long)seg1->mr_dma, nsegs, rc);
+ while (nsegs--)
+ rpcrdma_unmap_one(ia, --seg);
+ } else {
+ seg1->mr_rkey = seg1->mr_chunk.rl_mr->rkey;
+ seg1->mr_nsegs = nsegs;
+ seg1->mr_len = len;
+ }
+ }
+ break;
+ }
+ if (rc)
+ return -1;
+
+ return nsegs;
+}
+
+int
+rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg,
+ struct rpcrdma_xprt *r_xprt, void *r)
+{
+ struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+ struct rpcrdma_mr_seg *seg1 = seg;
+ int nsegs = seg->mr_nsegs, rc;
+
+ switch (ia->ri_memreg_strategy) {
+
+#if RPCRDMA_PERSISTENT_REGISTRATION
+ case RPCRDMA_ALLPHYSICAL:
+ BUG_ON(nsegs != 1);
+ rpcrdma_unmap_one(ia, seg);
+ rc = 0;
+ break;
+#endif
+
+ case RPCRDMA_MTHCAFMR:
+ {
+ LIST_HEAD(l);
+ list_add(&seg->mr_chunk.rl_mw->r.fmr->list, &l);
+ rc = ib_unmap_fmr(&l);
+ while (seg1->mr_nsegs--)
+ rpcrdma_unmap_one(ia, seg++);
+ }
+ if (rc)
+ dprintk("RPC: %s: failed ib_unmap_fmr,"
+ " status %i\n", __func__, rc);
+ break;
+
+ case RPCRDMA_MEMWINDOWS_ASYNC:
+ case RPCRDMA_MEMWINDOWS:
+ {
+ struct ib_mw_bind param;
+ BUG_ON(nsegs != 1);
+ param.mr = ia->ri_bind_mem;
+ param.addr = 0ULL; /* unbind */
+ param.length = 0;
+ param.mw_access_flags = 0;
+ if (r) {
+ param.wr_id = (u64) (unsigned long) r;
+ param.send_flags = IB_SEND_SIGNALED;
+ INIT_CQCOUNT(&r_xprt->rx_ep);
+ } else {
+ param.wr_id = 0ULL;
+ param.send_flags = 0;
+ DECR_CQCOUNT(&r_xprt->rx_ep);
+ }
+ rc = ib_bind_mw(ia->ri_id->qp,
+ seg->mr_chunk.rl_mw->r.mw, &param);
+ rpcrdma_unmap_one(ia, seg);
+ }
+ if (rc)
+ dprintk("RPC: %s: failed ib_(un)bind_mw,"
+ " status %i\n", __func__, rc);
+ else
+ r = NULL; /* will upcall on completion */
+ break;
+
+ default:
+ rc = ib_dereg_mr(seg1->mr_chunk.rl_mr);
+ seg1->mr_chunk.rl_mr = NULL;
+ while (seg1->mr_nsegs--)
+ rpcrdma_unmap_one(ia, seg++);
+ if (rc)
+ dprintk("RPC: %s: failed ib_dereg_mr,"
+ " status %i\n", __func__, rc);
+ break;
+ }
+ if (r) {
+ struct rpcrdma_rep *rep = r;
+ void (*func)(struct rpcrdma_rep *) = rep->rr_func;
+ rep->rr_func = NULL;
+ func(rep); /* dereg done, callback now */
+ }
+ return nsegs;
+}
+
+/*
+ * Prepost any receive buffer, then post send.
+ *
+ * Receive buffer is donated to hardware, reclaimed upon recv completion.
+ */
+int
+rpcrdma_ep_post(struct rpcrdma_ia *ia,
+ struct rpcrdma_ep *ep,
+ struct rpcrdma_req *req)
+{
+ struct ib_send_wr send_wr, *send_wr_fail;
+ struct rpcrdma_rep *rep = req->rl_reply;
+ int rc;
+
+ if (rep) {
+ rc = rpcrdma_ep_post_recv(ia, ep, rep);
+ if (rc)
+ goto out;
+ req->rl_reply = NULL;
+ }
+
+ send_wr.next = NULL;
+ send_wr.wr_id = 0ULL; /* no send cookie */
+ send_wr.sg_list = req->rl_send_iov;
+ send_wr.num_sge = req->rl_niovs;
+ send_wr.opcode = IB_WR_SEND;
+ send_wr.imm_data = 0;
+ if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */
+ ib_dma_sync_single_for_device(ia->ri_id->device,
+ req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
+ DMA_TO_DEVICE);
+ ib_dma_sync_single_for_device(ia->ri_id->device,
+ req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
+ DMA_TO_DEVICE);
+ ib_dma_sync_single_for_device(ia->ri_id->device,
+ req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
+ DMA_TO_DEVICE);
+
+ if (DECR_CQCOUNT(ep) > 0)
+ send_wr.send_flags = 0;
+ else { /* Provider must take a send completion every now and then */
+ INIT_CQCOUNT(ep);
+ send_wr.send_flags = IB_SEND_SIGNALED;
+ }
+
+ rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
+ if (rc)
+ dprintk("RPC: %s: ib_post_send returned %i\n", __func__,
+ rc);
+out:
+ return rc;
+}
+
+/*
+ * (Re)post a receive buffer.
+ */
+int
+rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
+ struct rpcrdma_ep *ep,
+ struct rpcrdma_rep *rep)
+{
+ struct ib_recv_wr recv_wr, *recv_wr_fail;
+ int rc;
+
+ recv_wr.next = NULL;
+ recv_wr.wr_id = (u64) (unsigned long) rep;
+ recv_wr.sg_list = &rep->rr_iov;
+ recv_wr.num_sge = 1;
+
+ ib_dma_sync_single_for_cpu(ia->ri_id->device,
+ rep->rr_iov.addr, rep->rr_iov.length, DMA_BIDIRECTIONAL);
+
+ DECR_CQCOUNT(ep);
+ rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
+
+ if (rc)
+ dprintk("RPC: %s: ib_post_recv returned %i\n", __func__,
+ rc);
+ return rc;
+}
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
new file mode 100644
index 00000000000..2427822f8bd
--- /dev/null
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRT_RDMA_H
+#define _LINUX_SUNRPC_XPRT_RDMA_H
+
+#include <linux/wait.h> /* wait_queue_head_t, etc */
+#include <linux/spinlock.h> /* spinlock_t, etc */
+#include <asm/atomic.h> /* atomic_t, etc */
+
+#include <rdma/rdma_cm.h> /* RDMA connection api */
+#include <rdma/ib_verbs.h> /* RDMA verbs api */
+
+#include <linux/sunrpc/clnt.h> /* rpc_xprt */
+#include <linux/sunrpc/rpc_rdma.h> /* RPC/RDMA protocol */
+#include <linux/sunrpc/xprtrdma.h> /* xprt parameters */
+
+/*
+ * Interface Adapter -- one per transport instance
+ */
+struct rpcrdma_ia {
+ struct rdma_cm_id *ri_id;
+ struct ib_pd *ri_pd;
+ struct ib_mr *ri_bind_mem;
+ struct completion ri_done;
+ int ri_async_rc;
+ enum rpcrdma_memreg ri_memreg_strategy;
+};
+
+/*
+ * RDMA Endpoint -- one per transport instance
+ */
+
+struct rpcrdma_ep {
+ atomic_t rep_cqcount;
+ int rep_cqinit;
+ int rep_connected;
+ struct rpcrdma_ia *rep_ia;
+ struct ib_cq *rep_cq;
+ struct ib_qp_init_attr rep_attr;
+ wait_queue_head_t rep_connect_wait;
+ struct ib_sge rep_pad; /* holds zeroed pad */
+ struct ib_mr *rep_pad_mr; /* holds zeroed pad */
+ void (*rep_func)(struct rpcrdma_ep *);
+ struct rpc_xprt *rep_xprt; /* for rep_func */
+ struct rdma_conn_param rep_remote_cma;
+ struct sockaddr_storage rep_remote_addr;
+};
+
+#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
+#define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount)
+
+/*
+ * struct rpcrdma_rep -- this structure encapsulates state required to recv
+ * and complete a reply, asychronously. It needs several pieces of
+ * state:
+ * o recv buffer (posted to provider)
+ * o ib_sge (also donated to provider)
+ * o status of reply (length, success or not)
+ * o bookkeeping state to get run by tasklet (list, etc)
+ *
+ * These are allocated during initialization, per-transport instance;
+ * however, the tasklet execution list itself is global, as it should
+ * always be pretty short.
+ *
+ * N of these are associated with a transport instance, and stored in
+ * struct rpcrdma_buffer. N is the max number of outstanding requests.
+ */
+
+/* temporary static scatter/gather max */
+#define RPCRDMA_MAX_DATA_SEGS (8) /* max scatter/gather */
+#define RPCRDMA_MAX_SEGS (RPCRDMA_MAX_DATA_SEGS + 2) /* head+tail = 2 */
+#define MAX_RPCRDMAHDR (\
+ /* max supported RPC/RDMA header */ \
+ sizeof(struct rpcrdma_msg) + (2 * sizeof(u32)) + \
+ (sizeof(struct rpcrdma_read_chunk) * RPCRDMA_MAX_SEGS) + sizeof(u32))
+
+struct rpcrdma_buffer;
+
+struct rpcrdma_rep {
+ unsigned int rr_len; /* actual received reply length */
+ struct rpcrdma_buffer *rr_buffer; /* home base for this structure */
+ struct rpc_xprt *rr_xprt; /* needed for request/reply matching */
+ void (*rr_func)(struct rpcrdma_rep *);/* called by tasklet in softint */
+ struct list_head rr_list; /* tasklet list */
+ wait_queue_head_t rr_unbind; /* optional unbind wait */
+ struct ib_sge rr_iov; /* for posting */
+ struct ib_mr *rr_handle; /* handle for mem in rr_iov */
+ char rr_base[MAX_RPCRDMAHDR]; /* minimal inline receive buffer */
+};
+
+/*
+ * struct rpcrdma_req -- structure central to the request/reply sequence.
+ *
+ * N of these are associated with a transport instance, and stored in
+ * struct rpcrdma_buffer. N is the max number of outstanding requests.
+ *
+ * It includes pre-registered buffer memory for send AND recv.
+ * The recv buffer, however, is not owned by this structure, and
+ * is "donated" to the hardware when a recv is posted. When a
+ * reply is handled, the recv buffer used is given back to the
+ * struct rpcrdma_req associated with the request.
+ *
+ * In addition to the basic memory, this structure includes an array
+ * of iovs for send operations. The reason is that the iovs passed to
+ * ib_post_{send,recv} must not be modified until the work request
+ * completes.
+ *
+ * NOTES:
+ * o RPCRDMA_MAX_SEGS is the max number of addressible chunk elements we
+ * marshal. The number needed varies depending on the iov lists that
+ * are passed to us, the memory registration mode we are in, and if
+ * physical addressing is used, the layout.
+ */
+
+struct rpcrdma_mr_seg { /* chunk descriptors */
+ union { /* chunk memory handles */
+ struct ib_mr *rl_mr; /* if registered directly */
+ struct rpcrdma_mw { /* if registered from region */
+ union {
+ struct ib_mw *mw;
+ struct ib_fmr *fmr;
+ } r;
+ struct list_head mw_list;
+ } *rl_mw;
+ } mr_chunk;
+ u64 mr_base; /* registration result */
+ u32 mr_rkey; /* registration result */
+ u32 mr_len; /* length of chunk or segment */
+ int mr_nsegs; /* number of segments in chunk or 0 */
+ enum dma_data_direction mr_dir; /* segment mapping direction */
+ dma_addr_t mr_dma; /* segment mapping address */
+ size_t mr_dmalen; /* segment mapping length */
+ struct page *mr_page; /* owning page, if any */
+ char *mr_offset; /* kva if no page, else offset */
+};
+
+struct rpcrdma_req {
+ size_t rl_size; /* actual length of buffer */
+ unsigned int rl_niovs; /* 0, 2 or 4 */
+ unsigned int rl_nchunks; /* non-zero if chunks */
+ struct rpcrdma_buffer *rl_buffer; /* home base for this structure */
+ struct rpcrdma_rep *rl_reply;/* holder for reply buffer */
+ struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */
+ struct ib_sge rl_send_iov[4]; /* for active requests */
+ struct ib_sge rl_iov; /* for posting */
+ struct ib_mr *rl_handle; /* handle for mem in rl_iov */
+ char rl_base[MAX_RPCRDMAHDR]; /* start of actual buffer */
+ __u32 rl_xdr_buf[0]; /* start of returned rpc rq_buffer */
+};
+#define rpcr_to_rdmar(r) \
+ container_of((r)->rq_buffer, struct rpcrdma_req, rl_xdr_buf[0])
+
+/*
+ * struct rpcrdma_buffer -- holds list/queue of pre-registered memory for
+ * inline requests/replies, and client/server credits.
+ *
+ * One of these is associated with a transport instance
+ */
+struct rpcrdma_buffer {
+ spinlock_t rb_lock; /* protects indexes */
+ atomic_t rb_credits; /* most recent server credits */
+ unsigned long rb_cwndscale; /* cached framework rpc_cwndscale */
+ int rb_max_requests;/* client max requests */
+ struct list_head rb_mws; /* optional memory windows/fmrs */
+ int rb_send_index;
+ struct rpcrdma_req **rb_send_bufs;
+ int rb_recv_index;
+ struct rpcrdma_rep **rb_recv_bufs;
+ char *rb_pool;
+};
+#define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia)
+
+/*
+ * Internal structure for transport instance creation. This
+ * exists primarily for modularity.
+ *
+ * This data should be set with mount options
+ */
+struct rpcrdma_create_data_internal {
+ struct sockaddr_storage addr; /* RDMA server address */
+ unsigned int max_requests; /* max requests (slots) in flight */
+ unsigned int rsize; /* mount rsize - max read hdr+data */
+ unsigned int wsize; /* mount wsize - max write hdr+data */
+ unsigned int inline_rsize; /* max non-rdma read data payload */
+ unsigned int inline_wsize; /* max non-rdma write data payload */
+ unsigned int padding; /* non-rdma write header padding */
+};
+
+#define RPCRDMA_INLINE_READ_THRESHOLD(rq) \
+ (rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_rsize)
+
+#define RPCRDMA_INLINE_WRITE_THRESHOLD(rq)\
+ (rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_wsize)
+
+#define RPCRDMA_INLINE_PAD_VALUE(rq)\
+ rpcx_to_rdmad(rq->rq_task->tk_xprt).padding
+
+/*
+ * Statistics for RPCRDMA
+ */
+struct rpcrdma_stats {
+ unsigned long read_chunk_count;
+ unsigned long write_chunk_count;
+ unsigned long reply_chunk_count;
+
+ unsigned long long total_rdma_request;
+ unsigned long long total_rdma_reply;
+
+ unsigned long long pullup_copy_count;
+ unsigned long long fixup_copy_count;
+ unsigned long hardway_register_count;
+ unsigned long failed_marshal_count;
+ unsigned long bad_reply_count;
+};
+
+/*
+ * RPCRDMA transport -- encapsulates the structures above for
+ * integration with RPC.
+ *
+ * The contained structures are embedded, not pointers,
+ * for convenience. This structure need not be visible externally.
+ *
+ * It is allocated and initialized during mount, and released
+ * during unmount.
+ */
+struct rpcrdma_xprt {
+ struct rpc_xprt xprt;
+ struct rpcrdma_ia rx_ia;
+ struct rpcrdma_ep rx_ep;
+ struct rpcrdma_buffer rx_buf;
+ struct rpcrdma_create_data_internal rx_data;
+ struct delayed_work rdma_connect;
+ struct rpcrdma_stats rx_stats;
+};
+
+#define rpcx_to_rdmax(x) container_of(x, struct rpcrdma_xprt, xprt)
+#define rpcx_to_rdmad(x) (rpcx_to_rdmax(x)->rx_data)
+
+/*
+ * Interface Adapter calls - xprtrdma/verbs.c
+ */
+int rpcrdma_ia_open(struct rpcrdma_xprt *, struct sockaddr *, int);
+void rpcrdma_ia_close(struct rpcrdma_ia *);
+
+/*
+ * Endpoint calls - xprtrdma/verbs.c
+ */
+int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *,
+ struct rpcrdma_create_data_internal *);
+int rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *);
+int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *);
+int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *);
+
+int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *,
+ struct rpcrdma_req *);
+int rpcrdma_ep_post_recv(struct rpcrdma_ia *, struct rpcrdma_ep *,
+ struct rpcrdma_rep *);
+
+/*
+ * Buffer calls - xprtrdma/verbs.c
+ */
+int rpcrdma_buffer_create(struct rpcrdma_buffer *, struct rpcrdma_ep *,
+ struct rpcrdma_ia *,
+ struct rpcrdma_create_data_internal *);
+void rpcrdma_buffer_destroy(struct rpcrdma_buffer *);
+
+struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *);
+void rpcrdma_buffer_put(struct rpcrdma_req *);
+void rpcrdma_recv_buffer_get(struct rpcrdma_req *);
+void rpcrdma_recv_buffer_put(struct rpcrdma_rep *);
+
+int rpcrdma_register_internal(struct rpcrdma_ia *, void *, int,
+ struct ib_mr **, struct ib_sge *);
+int rpcrdma_deregister_internal(struct rpcrdma_ia *,
+ struct ib_mr *, struct ib_sge *);
+
+int rpcrdma_register_external(struct rpcrdma_mr_seg *,
+ int, int, struct rpcrdma_xprt *);
+int rpcrdma_deregister_external(struct rpcrdma_mr_seg *,
+ struct rpcrdma_xprt *, void *);
+
+/*
+ * RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c
+ */
+void rpcrdma_conn_func(struct rpcrdma_ep *);
+void rpcrdma_reply_handler(struct rpcrdma_rep *);
+
+/*
+ * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c
+ */
+int rpcrdma_marshal_req(struct rpc_rqst *);
+
+#endif /* _LINUX_SUNRPC_XPRT_RDMA_H */
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 282efd447a6..02298f529da 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -13,10 +13,14 @@
* (C) 1999 Trond Myklebust <trond.myklebust@fys.uio.no>
*
* IP socket transport implementation, (C) 2005 Chuck Lever <cel@netapp.com>
+ *
+ * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005.
+ * <gilles.quillard@bull.net>
*/
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/capability.h>
#include <linux/pagemap.h>
#include <linux/errno.h>
@@ -28,6 +32,7 @@
#include <linux/tcp.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/xprtsock.h>
#include <linux/file.h>
#include <net/sock.h>
@@ -260,14 +265,29 @@ struct sock_xprt {
#define TCP_RCV_COPY_XID (1UL << 2)
#define TCP_RCV_COPY_DATA (1UL << 3)
-static void xs_format_peer_addresses(struct rpc_xprt *xprt)
+static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
+{
+ return (struct sockaddr *) &xprt->addr;
+}
+
+static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt)
{
- struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
+ return (struct sockaddr_in *) &xprt->addr;
+}
+
+static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt)
+{
+ return (struct sockaddr_in6 *) &xprt->addr;
+}
+
+static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt)
+{
+ struct sockaddr_in *addr = xs_addr_in(xprt);
char *buf;
buf = kzalloc(20, GFP_KERNEL);
if (buf) {
- snprintf(buf, 20, "%u.%u.%u.%u",
+ snprintf(buf, 20, NIPQUAD_FMT,
NIPQUAD(addr->sin_addr.s_addr));
}
xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
@@ -279,26 +299,123 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt)
}
xprt->address_strings[RPC_DISPLAY_PORT] = buf;
- if (xprt->prot == IPPROTO_UDP)
- xprt->address_strings[RPC_DISPLAY_PROTO] = "udp";
- else
- xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp";
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf) {
+ if (xprt->prot == IPPROTO_UDP)
+ snprintf(buf, 8, "udp");
+ else
+ snprintf(buf, 8, "tcp");
+ }
+ xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
buf = kzalloc(48, GFP_KERNEL);
if (buf) {
- snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s",
+ snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
NIPQUAD(addr->sin_addr.s_addr),
ntohs(addr->sin_port),
xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
}
xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+ buf = kzalloc(10, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 10, "%02x%02x%02x%02x",
+ NIPQUAD(addr->sin_addr.s_addr));
+ }
+ xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 8, "%4hx",
+ ntohs(addr->sin_port));
+ }
+ xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+ buf = kzalloc(30, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
+ NIPQUAD(addr->sin_addr.s_addr),
+ ntohs(addr->sin_port) >> 8,
+ ntohs(addr->sin_port) & 0xff);
+ }
+ xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+ xprt->address_strings[RPC_DISPLAY_NETID] =
+ kstrdup(xprt->prot == IPPROTO_UDP ?
+ RPCBIND_NETID_UDP : RPCBIND_NETID_TCP, GFP_KERNEL);
+}
+
+static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt)
+{
+ struct sockaddr_in6 *addr = xs_addr_in6(xprt);
+ char *buf;
+
+ buf = kzalloc(40, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 40, NIP6_FMT,
+ NIP6(addr->sin6_addr));
+ }
+ xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 8, "%u",
+ ntohs(addr->sin6_port));
+ }
+ xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf) {
+ if (xprt->prot == IPPROTO_UDP)
+ snprintf(buf, 8, "udp");
+ else
+ snprintf(buf, 8, "tcp");
+ }
+ xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s",
+ NIP6(addr->sin6_addr),
+ ntohs(addr->sin6_port),
+ xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
+ }
+ xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+ buf = kzalloc(36, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 36, NIP6_SEQFMT,
+ NIP6(addr->sin6_addr));
+ }
+ xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 8, "%4hx",
+ ntohs(addr->sin6_port));
+ }
+ xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+ buf = kzalloc(50, GFP_KERNEL);
+ if (buf) {
+ snprintf(buf, 50, NIP6_FMT".%u.%u",
+ NIP6(addr->sin6_addr),
+ ntohs(addr->sin6_port) >> 8,
+ ntohs(addr->sin6_port) & 0xff);
+ }
+ xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+ xprt->address_strings[RPC_DISPLAY_NETID] =
+ kstrdup(xprt->prot == IPPROTO_UDP ?
+ RPCBIND_NETID_UDP6 : RPCBIND_NETID_TCP6, GFP_KERNEL);
}
static void xs_free_peer_addresses(struct rpc_xprt *xprt)
{
- kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
- kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
- kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
+ int i;
+
+ for (i = 0; i < RPC_DISPLAY_MAX; i++)
+ kfree(xprt->address_strings[i]);
}
#define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL)
@@ -463,19 +580,20 @@ static int xs_udp_send_request(struct rpc_task *task)
req->rq_xtime = jiffies;
status = xs_sendpages(transport->sock,
- (struct sockaddr *) &xprt->addr,
+ xs_addr(xprt),
xprt->addrlen, xdr,
req->rq_bytes_sent);
dprintk("RPC: xs_udp_send_request(%u) = %d\n",
xdr->len - req->rq_bytes_sent, status);
- if (likely(status >= (int) req->rq_slen))
- return 0;
-
- /* Still some bytes left; set up for a retry later. */
- if (status > 0)
+ if (status >= 0) {
+ task->tk_bytes_sent += status;
+ if (status >= req->rq_slen)
+ return 0;
+ /* Still some bytes left; set up for a retry later. */
status = -EAGAIN;
+ }
switch (status) {
case -ENETUNREACH:
@@ -523,7 +641,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
struct rpc_xprt *xprt = req->rq_xprt;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct xdr_buf *xdr = &req->rq_snd_buf;
- int status, retry = 0;
+ int status;
+ unsigned int retry = 0;
xs_encode_tcp_record_marker(&req->rq_snd_buf);
@@ -661,6 +780,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
xs_free_peer_addresses(xprt);
kfree(xprt->slot);
kfree(xprt);
+ module_put(THIS_MODULE);
}
static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
@@ -1139,14 +1259,23 @@ static unsigned short xs_get_random_port(void)
*/
static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
{
- struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
+ struct sockaddr *addr = xs_addr(xprt);
dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
- sap->sin_port = htons(port);
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
+ break;
+ default:
+ BUG();
+ }
}
-static int xs_bind(struct sock_xprt *transport, struct socket *sock)
+static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
{
struct sockaddr_in myaddr = {
.sin_family = AF_INET,
@@ -1174,8 +1303,42 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
else
port--;
} while (err == -EADDRINUSE && port != transport->port);
- dprintk("RPC: xs_bind "NIPQUAD_FMT":%u: %s (%d)\n",
- NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err);
+ dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n",
+ __FUNCTION__, NIPQUAD(myaddr.sin_addr),
+ port, err ? "failed" : "ok", err);
+ return err;
+}
+
+static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
+{
+ struct sockaddr_in6 myaddr = {
+ .sin6_family = AF_INET6,
+ };
+ struct sockaddr_in6 *sa;
+ int err;
+ unsigned short port = transport->port;
+
+ if (!transport->xprt.resvport)
+ port = 0;
+ sa = (struct sockaddr_in6 *)&transport->addr;
+ myaddr.sin6_addr = sa->sin6_addr;
+ do {
+ myaddr.sin6_port = htons(port);
+ err = kernel_bind(sock, (struct sockaddr *) &myaddr,
+ sizeof(myaddr));
+ if (!transport->xprt.resvport)
+ break;
+ if (err == 0) {
+ transport->port = port;
+ break;
+ }
+ if (port <= xprt_min_resvport)
+ port = xprt_max_resvport;
+ else
+ port--;
+ } while (err == -EADDRINUSE && port != transport->port);
+ dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n",
+ NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err);
return err;
}
@@ -1183,38 +1346,69 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
static struct lock_class_key xs_key[2];
static struct lock_class_key xs_slock_key[2];
-static inline void xs_reclassify_socket(struct socket *sock)
+static inline void xs_reclassify_socket4(struct socket *sock)
{
struct sock *sk = sock->sk;
+
BUG_ON(sock_owned_by_user(sk));
- switch (sk->sk_family) {
- case AF_INET:
- sock_lock_init_class_and_name(sk, "slock-AF_INET-NFS",
- &xs_slock_key[0], "sk_lock-AF_INET-NFS", &xs_key[0]);
- break;
+ sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
+ &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
+}
- case AF_INET6:
- sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFS",
- &xs_slock_key[1], "sk_lock-AF_INET6-NFS", &xs_key[1]);
- break;
+static inline void xs_reclassify_socket6(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
- default:
- BUG();
- }
+ BUG_ON(sock_owned_by_user(sk));
+ sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
+ &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
}
#else
-static inline void xs_reclassify_socket(struct socket *sock)
+static inline void xs_reclassify_socket4(struct socket *sock)
+{
+}
+
+static inline void xs_reclassify_socket6(struct socket *sock)
{
}
#endif
+static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+ if (!transport->inet) {
+ struct sock *sk = sock->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+
+ sk->sk_user_data = xprt;
+ transport->old_data_ready = sk->sk_data_ready;
+ transport->old_state_change = sk->sk_state_change;
+ transport->old_write_space = sk->sk_write_space;
+ sk->sk_data_ready = xs_udp_data_ready;
+ sk->sk_write_space = xs_udp_write_space;
+ sk->sk_no_check = UDP_CSUM_NORCV;
+ sk->sk_allocation = GFP_ATOMIC;
+
+ xprt_set_connected(xprt);
+
+ /* Reset to new socket */
+ transport->sock = sock;
+ transport->inet = sk;
+
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ xs_udp_do_set_buffer_size(xprt);
+}
+
/**
- * xs_udp_connect_worker - set up a UDP socket
+ * xs_udp_connect_worker4 - set up a UDP socket
* @work: RPC transport to connect
*
* Invoked by a work queue tasklet.
*/
-static void xs_udp_connect_worker(struct work_struct *work)
+static void xs_udp_connect_worker4(struct work_struct *work)
{
struct sock_xprt *transport =
container_of(work, struct sock_xprt, connect_worker.work);
@@ -1232,9 +1426,9 @@ static void xs_udp_connect_worker(struct work_struct *work)
dprintk("RPC: can't create UDP transport socket (%d).\n", -err);
goto out;
}
- xs_reclassify_socket(sock);
+ xs_reclassify_socket4(sock);
- if (xs_bind(transport, sock)) {
+ if (xs_bind4(transport, sock)) {
sock_release(sock);
goto out;
}
@@ -1242,29 +1436,48 @@ static void xs_udp_connect_worker(struct work_struct *work)
dprintk("RPC: worker connecting xprt %p to address: %s\n",
xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
- if (!transport->inet) {
- struct sock *sk = sock->sk;
+ xs_udp_finish_connecting(xprt, sock);
+ status = 0;
+out:
+ xprt_wake_pending_tasks(xprt, status);
+ xprt_clear_connecting(xprt);
+}
- write_lock_bh(&sk->sk_callback_lock);
+/**
+ * xs_udp_connect_worker6 - set up a UDP socket
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_udp_connect_worker6(struct work_struct *work)
+{
+ struct sock_xprt *transport =
+ container_of(work, struct sock_xprt, connect_worker.work);
+ struct rpc_xprt *xprt = &transport->xprt;
+ struct socket *sock = transport->sock;
+ int err, status = -EIO;
- sk->sk_user_data = xprt;
- transport->old_data_ready = sk->sk_data_ready;
- transport->old_state_change = sk->sk_state_change;
- transport->old_write_space = sk->sk_write_space;
- sk->sk_data_ready = xs_udp_data_ready;
- sk->sk_write_space = xs_udp_write_space;
- sk->sk_no_check = UDP_CSUM_NORCV;
- sk->sk_allocation = GFP_ATOMIC;
+ if (xprt->shutdown || !xprt_bound(xprt))
+ goto out;
- xprt_set_connected(xprt);
+ /* Start by resetting any existing state */
+ xs_close(xprt);
- /* Reset to new socket */
- transport->sock = sock;
- transport->inet = sk;
+ if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+ dprintk("RPC: can't create UDP transport socket (%d).\n", -err);
+ goto out;
+ }
+ xs_reclassify_socket6(sock);
- write_unlock_bh(&sk->sk_callback_lock);
+ if (xs_bind6(transport, sock) < 0) {
+ sock_release(sock);
+ goto out;
}
- xs_udp_do_set_buffer_size(xprt);
+
+ dprintk("RPC: worker connecting xprt %p to address: %s\n",
+ xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+
+ xs_udp_finish_connecting(xprt, sock);
status = 0;
out:
xprt_wake_pending_tasks(xprt, status);
@@ -1295,13 +1508,52 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
result);
}
+static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+ if (!transport->inet) {
+ struct sock *sk = sock->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+
+ sk->sk_user_data = xprt;
+ transport->old_data_ready = sk->sk_data_ready;
+ transport->old_state_change = sk->sk_state_change;
+ transport->old_write_space = sk->sk_write_space;
+ sk->sk_data_ready = xs_tcp_data_ready;
+ sk->sk_state_change = xs_tcp_state_change;
+ sk->sk_write_space = xs_tcp_write_space;
+ sk->sk_allocation = GFP_ATOMIC;
+
+ /* socket options */
+ sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
+ sock_reset_flag(sk, SOCK_LINGER);
+ tcp_sk(sk)->linger2 = 0;
+ tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+
+ xprt_clear_connected(xprt);
+
+ /* Reset to new socket */
+ transport->sock = sock;
+ transport->inet = sk;
+
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+
+ /* Tell the socket layer to start connecting... */
+ xprt->stat.connect_count++;
+ xprt->stat.connect_start = jiffies;
+ return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
+}
+
/**
- * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
+ * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
* @work: RPC transport to connect
*
* Invoked by a work queue tasklet.
*/
-static void xs_tcp_connect_worker(struct work_struct *work)
+static void xs_tcp_connect_worker4(struct work_struct *work)
{
struct sock_xprt *transport =
container_of(work, struct sock_xprt, connect_worker.work);
@@ -1315,13 +1567,12 @@ static void xs_tcp_connect_worker(struct work_struct *work)
if (!sock) {
/* start from scratch */
if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
- dprintk("RPC: can't create TCP transport "
- "socket (%d).\n", -err);
+ dprintk("RPC: can't create TCP transport socket (%d).\n", -err);
goto out;
}
- xs_reclassify_socket(sock);
+ xs_reclassify_socket4(sock);
- if (xs_bind(transport, sock)) {
+ if (xs_bind4(transport, sock) < 0) {
sock_release(sock);
goto out;
}
@@ -1332,43 +1583,70 @@ static void xs_tcp_connect_worker(struct work_struct *work)
dprintk("RPC: worker connecting xprt %p to address: %s\n",
xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
- if (!transport->inet) {
- struct sock *sk = sock->sk;
-
- write_lock_bh(&sk->sk_callback_lock);
+ status = xs_tcp_finish_connecting(xprt, sock);
+ dprintk("RPC: %p connect status %d connected %d sock state %d\n",
+ xprt, -status, xprt_connected(xprt),
+ sock->sk->sk_state);
+ if (status < 0) {
+ switch (status) {
+ case -EINPROGRESS:
+ case -EALREADY:
+ goto out_clear;
+ case -ECONNREFUSED:
+ case -ECONNRESET:
+ /* retry with existing socket, after a delay */
+ break;
+ default:
+ /* get rid of existing socket, and retry */
+ xs_close(xprt);
+ break;
+ }
+ }
+out:
+ xprt_wake_pending_tasks(xprt, status);
+out_clear:
+ xprt_clear_connecting(xprt);
+}
- sk->sk_user_data = xprt;
- transport->old_data_ready = sk->sk_data_ready;
- transport->old_state_change = sk->sk_state_change;
- transport->old_write_space = sk->sk_write_space;
- sk->sk_data_ready = xs_tcp_data_ready;
- sk->sk_state_change = xs_tcp_state_change;
- sk->sk_write_space = xs_tcp_write_space;
- sk->sk_allocation = GFP_ATOMIC;
+/**
+ * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_tcp_connect_worker6(struct work_struct *work)
+{
+ struct sock_xprt *transport =
+ container_of(work, struct sock_xprt, connect_worker.work);
+ struct rpc_xprt *xprt = &transport->xprt;
+ struct socket *sock = transport->sock;
+ int err, status = -EIO;
- /* socket options */
- sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
- sock_reset_flag(sk, SOCK_LINGER);
- tcp_sk(sk)->linger2 = 0;
- tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+ if (xprt->shutdown || !xprt_bound(xprt))
+ goto out;
- xprt_clear_connected(xprt);
+ if (!sock) {
+ /* start from scratch */
+ if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
+ dprintk("RPC: can't create TCP transport socket (%d).\n", -err);
+ goto out;
+ }
+ xs_reclassify_socket6(sock);
- /* Reset to new socket */
- transport->sock = sock;
- transport->inet = sk;
+ if (xs_bind6(transport, sock) < 0) {
+ sock_release(sock);
+ goto out;
+ }
+ } else
+ /* "close" the socket, preserving the local port */
+ xs_tcp_reuse_connection(xprt);
- write_unlock_bh(&sk->sk_callback_lock);
- }
+ dprintk("RPC: worker connecting xprt %p to address: %s\n",
+ xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
- /* Tell the socket layer to start connecting... */
- xprt->stat.connect_count++;
- xprt->stat.connect_start = jiffies;
- status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
- xprt->addrlen, O_NONBLOCK);
+ status = xs_tcp_finish_connecting(xprt, sock);
dprintk("RPC: %p connect status %d connected %d sock state %d\n",
- xprt, -status, xprt_connected(xprt),
- sock->sk->sk_state);
+ xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
if (status < 0) {
switch (status) {
case -EINPROGRESS:
@@ -1508,7 +1786,8 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.print_stats = xs_tcp_print_stats,
};
-static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size)
+static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
+ unsigned int slot_table_size)
{
struct rpc_xprt *xprt;
struct sock_xprt *new;
@@ -1549,8 +1828,9 @@ static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned
* @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
{
+ struct sockaddr *addr = args->dstaddr;
struct rpc_xprt *xprt;
struct sock_xprt *transport;
@@ -1559,15 +1839,11 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
- if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
- xprt_set_bound(xprt);
-
xprt->prot = IPPROTO_UDP;
xprt->tsh_size = 0;
/* XXX: header size can vary due to auth type, IPv6, etc. */
xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
- INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker);
xprt->bind_timeout = XS_BIND_TO;
xprt->connect_timeout = XS_UDP_CONN_TO;
xprt->reestablish_timeout = XS_UDP_REEST_TO;
@@ -1580,11 +1856,37 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
else
xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
- xs_format_peer_addresses(xprt);
+ switch (addr->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+ xprt_set_bound(xprt);
+
+ INIT_DELAYED_WORK(&transport->connect_worker,
+ xs_udp_connect_worker4);
+ xs_format_ipv4_peer_addresses(xprt);
+ break;
+ case AF_INET6:
+ if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+ xprt_set_bound(xprt);
+
+ INIT_DELAYED_WORK(&transport->connect_worker,
+ xs_udp_connect_worker6);
+ xs_format_ipv6_peer_addresses(xprt);
+ break;
+ default:
+ kfree(xprt);
+ return ERR_PTR(-EAFNOSUPPORT);
+ }
+
dprintk("RPC: set up transport to address %s\n",
xprt->address_strings[RPC_DISPLAY_ALL]);
- return xprt;
+ if (try_module_get(THIS_MODULE))
+ return xprt;
+
+ kfree(xprt->slot);
+ kfree(xprt);
+ return ERR_PTR(-EINVAL);
}
/**
@@ -1592,8 +1894,9 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
* @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
{
+ struct sockaddr *addr = args->dstaddr;
struct rpc_xprt *xprt;
struct sock_xprt *transport;
@@ -1602,14 +1905,10 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
- if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
- xprt_set_bound(xprt);
-
xprt->prot = IPPROTO_TCP;
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
- INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker);
xprt->bind_timeout = XS_BIND_TO;
xprt->connect_timeout = XS_TCP_CONN_TO;
xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
@@ -1622,15 +1921,55 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
else
xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
- xs_format_peer_addresses(xprt);
+ switch (addr->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+ xprt_set_bound(xprt);
+
+ INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4);
+ xs_format_ipv4_peer_addresses(xprt);
+ break;
+ case AF_INET6:
+ if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+ xprt_set_bound(xprt);
+
+ INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6);
+ xs_format_ipv6_peer_addresses(xprt);
+ break;
+ default:
+ kfree(xprt);
+ return ERR_PTR(-EAFNOSUPPORT);
+ }
+
dprintk("RPC: set up transport to address %s\n",
xprt->address_strings[RPC_DISPLAY_ALL]);
- return xprt;
+ if (try_module_get(THIS_MODULE))
+ return xprt;
+
+ kfree(xprt->slot);
+ kfree(xprt);
+ return ERR_PTR(-EINVAL);
}
+static struct xprt_class xs_udp_transport = {
+ .list = LIST_HEAD_INIT(xs_udp_transport.list),
+ .name = "udp",
+ .owner = THIS_MODULE,
+ .ident = IPPROTO_UDP,
+ .setup = xs_setup_udp,
+};
+
+static struct xprt_class xs_tcp_transport = {
+ .list = LIST_HEAD_INIT(xs_tcp_transport.list),
+ .name = "tcp",
+ .owner = THIS_MODULE,
+ .ident = IPPROTO_TCP,
+ .setup = xs_setup_tcp,
+};
+
/**
- * init_socket_xprt - set up xprtsock's sysctls
+ * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
*
*/
int init_socket_xprt(void)
@@ -1640,11 +1979,14 @@ int init_socket_xprt(void)
sunrpc_table_header = register_sysctl_table(sunrpc_table);
#endif
+ xprt_register_transport(&xs_udp_transport);
+ xprt_register_transport(&xs_tcp_transport);
+
return 0;
}
/**
- * cleanup_socket_xprt - remove xprtsock's sysctls
+ * cleanup_socket_xprt - remove xprtsock's sysctls, unregister
*
*/
void cleanup_socket_xprt(void)
@@ -1655,4 +1997,7 @@ void cleanup_socket_xprt(void)
sunrpc_table_header = NULL;
}
#endif
+
+ xprt_unregister_transport(&xs_udp_transport);
+ xprt_unregister_transport(&xs_tcp_transport);
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 2b57eaf66ab..6996cba5aa9 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -334,7 +334,7 @@ static void unix_write_space(struct sock *sk)
read_lock(&sk->sk_callback_lock);
if (unix_writable(sk)) {
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible(sk->sk_sleep);
+ wake_up_interruptible_sync(sk->sk_sleep);
sk_wake_async(sk, 2, POLL_OUT);
}
read_unlock(&sk->sk_callback_lock);
@@ -1639,7 +1639,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb)
goto out_unlock;
- wake_up_interruptible(&u->peer_wait);
+ wake_up_interruptible_sync(&u->peer_wait);
if (msg->msg_name)
unix_copy_addr(msg, skb->sk);
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 2d5d2255a27..29f820e1825 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev)
}
#ifdef CONFIG_HOTPLUG
-static int wiphy_uevent(struct device *dev, char **envp,
- int num_envp, char *buf, int size)
+static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
{
/* TODO, we probably need stuff here */
return 0;
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 36e3754db53..494435ca88f 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -396,13 +396,6 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio,
return 1;
}
-static int do_i2c_entry(const char *filename, struct i2c_device_id *i2c, char *alias)
-{
- strcpy(alias, "i2c:");
- ADD(alias, "id", 1, i2c->id);
- return 1;
-}
-
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static void do_input(char *alias,
@@ -613,10 +606,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct vio_device_id), "vio",
do_vio_entry, mod);
- else if (sym_is(symname, "__mod_i2c_device_table"))
- do_table(symval, sym->st_size,
- sizeof(struct i2c_device_id), "i2c",
- do_i2c_entry, mod);
else if (sym_is(symname, "__mod_input_device_table"))
do_table(symval, sym->st_size,
sizeof(struct input_device_id), "input",
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3c3fff33d1c..cf76150e623 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3932,7 +3932,7 @@ out:
}
static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *),
@@ -3941,7 +3941,6 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
char *addrp;
int len, err = 0;
struct sock *sk;
- struct sk_buff *skb = *pskb;
struct avc_audit_data ad;
struct net_device *dev = (struct net_device *)out;
struct sk_security_struct *sksec;
@@ -3977,23 +3976,23 @@ out:
}
static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_postroute_last(hooknum, pskb, in, out, okfn, PF_INET);
+ return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
- struct sk_buff **pskb,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_postroute_last(hooknum, pskb, in, out, okfn, PF_INET6);
+ return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6);
}
#endif /* IPV6 */
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 64d16391433..f84f3e50578 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev)
}
-static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct soundbus_dev * soundbus_dev;
struct of_device * of;
const char *compat;
- int retval = 0, i = 0, length = 0;
+ int retval = 0;
int cplen, seen = 0;
if (!dev)
@@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
of = &soundbus_dev->ofdev;
/* stuff we want to pass to /sbin/hotplug */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "OF_NAME=%s", of->node->name);
+ retval = add_uevent_var(env, "OF_NAME=%s", of->node->name);
if (retval)
return retval;
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "OF_TYPE=%s", of->node->type);
+ retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type);
if (retval)
return retval;
@@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
compat = of_get_property(of->node, "compatible", &cplen);
while (compat && cplen > 0) {
- int tmp = length;
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "OF_COMPATIBLE_%d=%s", seen, compat);
+ int tmp = env->buflen;
+ retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
if (retval)
return retval;
- compat += length - tmp;
- cplen -= length - tmp;
+ compat += env->buflen - tmp;
+ cplen -= env->buflen - tmp;
seen += 1;
}
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "OF_COMPATIBLE_N=%d", seen);
+ retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
if (retval)
return retval;
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=%s", soundbus_dev->modalias);
-
- envp[i] = NULL;
+ retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
return retval;
}
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 188c7cf21b8..131952f5585 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -157,7 +157,7 @@ struct snd_bt87x {
int dig_rate;
spinlock_t reg_lock;
- long opened;
+ unsigned long opened;
struct snd_pcm_substream *substream;
struct snd_dma_buffer dma_risc;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 7bd5852fcc0..ac5666f4c6d 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2876,7 +2876,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
struct audioformat *fp;
struct usb_host_interface *alts;
int stream, err;
- int *rate_table = NULL;
+ unsigned *rate_table = NULL;
fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
if (! fp) {